From 5a61e580b902b75a0e90194be155ece28f5c6b37 Mon Sep 17 00:00:00 2001 From: Viktor Krikun Date: Sat, 20 Feb 2010 18:51:54 +0000 Subject: [PATCH 02/25] Add libzrtp beta --- AUTHORS | 33 + ChangeLog | 556 +++ README | 10 + doc/Doxyfile | 1553 +++++++ doc/doxygen.css | 451 ++ doc/footer.html | 4 + doc/header.html | 6 + doc/manuals/changelog.dox | 197 + doc/manuals/howto.dox | 489 ++ doc/manuals/main.dox | 38 + doc/manuals/rng.dox | 74 + doc/out/html/zfone.jpg | Bin 0 -> 8517 bytes include/zrtp.h | 936 ++++ include/zrtp_base.h | 211 + include/zrtp_config.h | 239 + include/zrtp_config_symbian.h | 69 + include/zrtp_config_user.h | 182 + include/zrtp_config_win.h | 67 + include/zrtp_crypto.h | 664 +++ include/zrtp_engine.h | 387 ++ include/zrtp_error.h | 136 + include/zrtp_iface.h | 692 +++ include/zrtp_iface_cache.h | 164 + include/zrtp_iface_scheduler.h | 89 + include/zrtp_iface_system.h | 183 + include/zrtp_legal.h | 25 + include/zrtp_list.h | 66 + include/zrtp_log.h | 161 + include/zrtp_pbx.h | 139 + include/zrtp_protocol.h | 491 ++ include/zrtp_srtp.h | 240 + include/zrtp_srtp_builtin.h | 149 + include/zrtp_string.h | 284 ++ include/zrtp_types.h | 1008 ++++ include/zrtp_version.h | 19 + projects/gnu/AUTHORS | 30 + projects/gnu/COPYING | 7 + projects/gnu/ChangeLog | 1 + projects/gnu/INSTALL | 255 ++ projects/gnu/Makefile.am | 57 + projects/gnu/NEWS | 0 projects/gnu/README | 0 projects/gnu/autoreconf.sh | 5 + projects/gnu/build/Makefile.am | 56 + projects/gnu/build/test/Makefile.am | 43 + projects/gnu/cfg | 2 + projects/gnu/configure.in | 96 + projects/gnu/create_docs.sh | 11 + projects/gnu/create_pack.pl | 421 ++ projects/symbian/DelayRuner.cpp | 79 + projects/symbian/DelayRuner.h | 72 + projects/symbian/bld.bat | 1 + projects/symbian/bld.inf | 13 + projects/symbian/bldgcce.bat | 2 + projects/symbian/libzrtp.mmp | 74 + projects/symbian/zrtp_iface_symb.cpp | 336 ++ projects/win/libzrtp.sln | 28 + projects/win/libzrtp.vcproj | 499 ++ projects/win/libzrtp_not_ec.vcproj | 483 ++ projects/win/libzrtp_test.vcproj | 211 + projects/win_ce/libzrtp_test_wince.vcproj | 500 ++ projects/win_ce/libzrtp_wince.sln | 40 + projects/win_ce/libzrtp_wince.vcproj | 761 +++ projects/win_ce/libzrtp_wince_not_ec.vcproj | 741 +++ projects/win_kernel/MAKEFILE.WIN32 | 131 + projects/win_kernel/MAKEFILE.WIN64 | 135 + projects/win_kernel/MAKEFILE_NOT_EC.WIN32 | 129 + projects/win_kernel/MAKEFILE_NOT_EC.WIN64 | 131 + .../xcode/libzrtp.xcodeproj/project.pbxproj | 613 +++ .../libzrtp_test.xcodeproj/project.pbxproj | 294 ++ src/zrtp.c | 1197 +++++ src/zrtp_crc.c | 146 + src/zrtp_crypto_aes.c | 833 ++++ src/zrtp_crypto_atl.c | 44 + src/zrtp_crypto_hash.c | 1638 +++++++ src/zrtp_crypto_pk.c | 357 ++ src/zrtp_crypto_sas.c | 745 +++ src/zrtp_datatypes.c | 120 + src/zrtp_engine.c | 1441 ++++++ src/zrtp_engine_driven.c | 152 + src/zrtp_iface_cache.c | 771 ++++ src/zrtp_iface_scheduler.c | 362 ++ src/zrtp_iface_sys.c | 489 ++ src/zrtp_initiator.c | 555 +++ src/zrtp_legal.c | 25 + src/zrtp_list.c | 66 + src/zrtp_log.c | 481 ++ src/zrtp_pbx.c | 587 +++ src/zrtp_protocol.c | 1332 ++++++ src/zrtp_responder.c | 612 +++ src/zrtp_rng.c | 345 ++ src/zrtp_srtp_builtin.c | 1469 ++++++ src/zrtp_srtp_dm.c | 232 + src/zrtp_string.c | 173 + src/zrtp_utils.c | 628 +++ src/zrtp_utils_proto.c | 631 +++ test/README | 0 test/pc/zrtp_test_core.c | 866 ++++ test/pc/zrtp_test_core.h | 38 + test/pc/zrtp_test_crypto.c | 447 ++ test/pc/zrtp_test_queue.c | 115 + test/pc/zrtp_test_queue.h | 30 + test/pc/zrtp_test_ui.c | 75 + test/win_ce/ReadMe.txt | 81 + test/win_ce/libzrtp_test_GUI.cpp | 492 ++ test/win_ce/libzrtp_test_GUI.h | 16 + test/win_ce/libzrtp_test_GUI.ico | Bin 0 -> 23558 bytes test/win_ce/libzrtp_test_GUIppc.rc | 183 + test/win_ce/libzrtp_test_GUIppc.rc2 | 35 + test/win_ce/libzrtp_test_GUIsp.rc | 95 + test/win_ce/libzrtp_test_GUIsp.rc2 | 31 + test/win_ce/resourceppc.h | 36 + test/win_ce/resourcesp.h | 28 + test/win_ce/stdafx.cpp | 18 + test/win_ce/stdafx.h | 61 + third_party/bgaes/aes.h | 232 + third_party/bgaes/aes_modes.c | 914 ++++ third_party/bgaes/aescrypt.c | 316 ++ third_party/bgaes/aeskey.c | 578 +++ third_party/bgaes/aesopt.h | 728 +++ third_party/bgaes/aestab.c | 400 ++ third_party/bgaes/aestab.h | 186 + third_party/bgaes/bg2zrtp.h | 44 + third_party/bgaes/brg_types.h | 186 + third_party/bgaes/sha1.c | 260 ++ third_party/bgaes/sha1.h | 73 + third_party/bgaes/sha2.c | 774 ++++ third_party/bgaes/sha2.h | 151 + third_party/bnlib/CHANGES | 59 + third_party/bnlib/Makefile | 182 + third_party/bnlib/Makefile.in | 182 + third_party/bnlib/README.bn | 225 + third_party/bnlib/README.bntest | 28 + .../bnlib/bignum-ARM/README-small-memory | 6 + third_party/bnlib/bignum-ARM/bntest16.c | 803 ++++ third_party/bnlib/bignum-ARM/config.h | 74 + third_party/bnlib/bignum-ARM/cputime.h | 250 + third_party/bnlib/bignum-ARM/kludge.h | 125 + third_party/bnlib/bignum-ARM/lbn.h | 151 + third_party/bnlib/bignum-ARM/lbn16.c | 4076 +++++++++++++++++ third_party/bnlib/bignum-ARM/lbn16.h | 156 + third_party/bnlib/bignum-ARM/lbnarm.h | 79 + third_party/bnlib/bignum-ARM/lbnarm.s | 173 + third_party/bnlib/bignum-ARM/lbnmem.c | 154 + third_party/bnlib/bignum-ARM/lbnmem.h | 63 + third_party/bnlib/bignum-ARM/sha256_arm.c | 241 + third_party/bnlib/bignum-ARM/sha256_core.s | 157 + third_party/bnlib/bn.c | 104 + third_party/bnlib/bn.doc | 541 +++ third_party/bnlib/bn.h | 225 + third_party/bnlib/bn00.c | 28 + third_party/bnlib/bn16.c | 1188 +++++ third_party/bnlib/bn16.h | 63 + third_party/bnlib/bn32.c | 1188 +++++ third_party/bnlib/bn32.h | 63 + third_party/bnlib/bn64.c | 1188 +++++ third_party/bnlib/bn64.h | 63 + third_party/bnlib/bn68000.c | 22 + third_party/bnlib/bn8086.c | 22 + third_party/bnlib/bnconfig.hin | 73 + third_party/bnlib/bninit16.c | 16 + third_party/bnlib/bninit32.c | 16 + third_party/bnlib/bninit64.c | 16 + third_party/bnlib/bnintern.doc | 304 ++ third_party/bnlib/bnprint.c | 76 + third_party/bnlib/bnprint.h | 10 + third_party/bnlib/bnsize00.h | 35 + third_party/bnlib/bntest00.c | 21 + third_party/bnlib/bntest16.c | 801 ++++ third_party/bnlib/bntest32.c | 801 ++++ third_party/bnlib/bntest64.c | 801 ++++ third_party/bnlib/cfg | 1 + third_party/bnlib/cfg.debug | 1 + third_party/bnlib/configure.in | 320 ++ third_party/bnlib/cputime.h | 256 ++ third_party/bnlib/germain.c | 608 +++ third_party/bnlib/germain.h | 8 + third_party/bnlib/germtest.c | 339 ++ third_party/bnlib/jacobi.c | 67 + third_party/bnlib/jacobi.h | 7 + third_party/bnlib/kludge.h | 125 + third_party/bnlib/lbn.h | 150 + third_party/bnlib/lbn00.c | 24 + third_party/bnlib/lbn16.c | 4073 ++++++++++++++++ third_party/bnlib/lbn16.h | 152 + third_party/bnlib/lbn32.c | 4073 ++++++++++++++++ third_party/bnlib/lbn32.h | 152 + third_party/bnlib/lbn64.c | 4073 ++++++++++++++++ third_party/bnlib/lbn64.h | 152 + third_party/bnlib/lbn68000.c | 460 ++ third_party/bnlib/lbn68000.h | 34 + third_party/bnlib/lbn68020.c | 309 ++ third_party/bnlib/lbn68020.h | 29 + third_party/bnlib/lbn68360.s | 277 ++ third_party/bnlib/lbn80386.asm | 414 ++ third_party/bnlib/lbn80386.h | 142 + third_party/bnlib/lbn80386.s | 394 ++ third_party/bnlib/lbn8086.asm | 1038 +++++ third_party/bnlib/lbn8086.h | 73 + third_party/bnlib/lbn960jx.h | 35 + third_party/bnlib/lbn960jx.s | 250 + third_party/bnlib/lbnalpha.h | 30 + third_party/bnlib/lbnalpha.s | 194 + third_party/bnlib/lbnmem.c | 154 + third_party/bnlib/lbnmem.h | 63 + third_party/bnlib/lbnppc.c | 318 ++ third_party/bnlib/lbnppc.h | 58 + third_party/bnlib/legal.c | 380 ++ third_party/bnlib/legal.h | 11 + third_party/bnlib/ppcasm.h | 535 +++ third_party/bnlib/prime.c | 679 +++ third_party/bnlib/prime.h | 12 + third_party/bnlib/sieve.c | 685 +++ third_party/bnlib/sieve.h | 23 + third_party/bnlib/sizetest.c | 11 + third_party/bnlib/test/README.dhtest | 21 + third_party/bnlib/test/README.dsatest | 18 + third_party/bnlib/test/README.rsatest | 12 + third_party/bnlib/test/dhtest.c | 375 ++ third_party/bnlib/test/dsatest.c | 672 +++ third_party/bnlib/test/first.h | 0 third_party/bnlib/test/kb.h | 6 + third_party/bnlib/test/kbmsdos.c | 75 + third_party/bnlib/test/kbunix.c | 257 ++ third_party/bnlib/test/keygen.c | 380 ++ third_party/bnlib/test/keygen.h | 7 + third_party/bnlib/test/keys.c | 55 + third_party/bnlib/test/keys.h | 30 + third_party/bnlib/test/kludge.h | 93 + third_party/bnlib/test/legal.c | 22 + third_party/bnlib/test/md5.c | 235 + third_party/bnlib/test/md5.h | 20 + third_party/bnlib/test/noise.c | 437 ++ third_party/bnlib/test/noise.h | 11 + third_party/bnlib/test/posix.h | 50 + third_party/bnlib/test/primes.doc | 215 + third_party/bnlib/test/primetest.c | 196 + third_party/bnlib/test/pt.c | 188 + third_party/bnlib/test/random.c | 301 ++ third_party/bnlib/test/random.h | 11 + third_party/bnlib/test/randpool.c | 157 + third_party/bnlib/test/randpool.h | 9 + third_party/bnlib/test/randtest.c | 299 ++ third_party/bnlib/test/rsaglue.c | 471 ++ third_party/bnlib/test/rsaglue.h | 32 + third_party/bnlib/test/rsatest.c | 265 ++ third_party/bnlib/test/sha.c | 511 +++ third_party/bnlib/test/sha.h | 58 + third_party/bnlib/test/types.h | 41 + third_party/bnlib/test/userio.h | 6 + third_party/bnlib/test/usuals.h | 43 + 251 files changed, 80806 insertions(+) create mode 100644 AUTHORS create mode 100644 ChangeLog create mode 100644 README create mode 100644 doc/Doxyfile create mode 100644 doc/doxygen.css create mode 100644 doc/footer.html create mode 100644 doc/header.html create mode 100644 doc/manuals/changelog.dox create mode 100644 doc/manuals/howto.dox create mode 100644 doc/manuals/main.dox create mode 100644 doc/manuals/rng.dox create mode 100644 doc/out/html/zfone.jpg create mode 100644 include/zrtp.h create mode 100644 include/zrtp_base.h create mode 100644 include/zrtp_config.h create mode 100644 include/zrtp_config_symbian.h create mode 100644 include/zrtp_config_user.h create mode 100644 include/zrtp_config_win.h create mode 100644 include/zrtp_crypto.h create mode 100644 include/zrtp_engine.h create mode 100644 include/zrtp_error.h create mode 100644 include/zrtp_iface.h create mode 100644 include/zrtp_iface_cache.h create mode 100644 include/zrtp_iface_scheduler.h create mode 100644 include/zrtp_iface_system.h create mode 100644 include/zrtp_legal.h create mode 100644 include/zrtp_list.h create mode 100644 include/zrtp_log.h create mode 100644 include/zrtp_pbx.h create mode 100644 include/zrtp_protocol.h create mode 100644 include/zrtp_srtp.h create mode 100644 include/zrtp_srtp_builtin.h create mode 100644 include/zrtp_string.h create mode 100644 include/zrtp_types.h create mode 100644 include/zrtp_version.h create mode 100644 projects/gnu/AUTHORS create mode 100644 projects/gnu/COPYING create mode 100644 projects/gnu/ChangeLog create mode 100644 projects/gnu/INSTALL create mode 100644 projects/gnu/Makefile.am create mode 100644 projects/gnu/NEWS create mode 100644 projects/gnu/README create mode 100755 projects/gnu/autoreconf.sh create mode 100644 projects/gnu/build/Makefile.am create mode 100644 projects/gnu/build/test/Makefile.am create mode 100755 projects/gnu/cfg create mode 100644 projects/gnu/configure.in create mode 100755 projects/gnu/create_docs.sh create mode 100755 projects/gnu/create_pack.pl create mode 100644 projects/symbian/DelayRuner.cpp create mode 100644 projects/symbian/DelayRuner.h create mode 100755 projects/symbian/bld.bat create mode 100644 projects/symbian/bld.inf create mode 100755 projects/symbian/bldgcce.bat create mode 100644 projects/symbian/libzrtp.mmp create mode 100644 projects/symbian/zrtp_iface_symb.cpp create mode 100644 projects/win/libzrtp.sln create mode 100644 projects/win/libzrtp.vcproj create mode 100644 projects/win/libzrtp_not_ec.vcproj create mode 100644 projects/win/libzrtp_test.vcproj create mode 100644 projects/win_ce/libzrtp_test_wince.vcproj create mode 100644 projects/win_ce/libzrtp_wince.sln create mode 100644 projects/win_ce/libzrtp_wince.vcproj create mode 100644 projects/win_ce/libzrtp_wince_not_ec.vcproj create mode 100644 projects/win_kernel/MAKEFILE.WIN32 create mode 100644 projects/win_kernel/MAKEFILE.WIN64 create mode 100644 projects/win_kernel/MAKEFILE_NOT_EC.WIN32 create mode 100644 projects/win_kernel/MAKEFILE_NOT_EC.WIN64 create mode 100644 projects/xcode/libzrtp.xcodeproj/project.pbxproj create mode 100644 projects/xcode/libzrtp_test.xcodeproj/project.pbxproj create mode 100644 src/zrtp.c create mode 100644 src/zrtp_crc.c create mode 100644 src/zrtp_crypto_aes.c create mode 100644 src/zrtp_crypto_atl.c create mode 100644 src/zrtp_crypto_hash.c create mode 100644 src/zrtp_crypto_pk.c create mode 100644 src/zrtp_crypto_sas.c create mode 100644 src/zrtp_datatypes.c create mode 100644 src/zrtp_engine.c create mode 100644 src/zrtp_engine_driven.c create mode 100644 src/zrtp_iface_cache.c create mode 100644 src/zrtp_iface_scheduler.c create mode 100644 src/zrtp_iface_sys.c create mode 100644 src/zrtp_initiator.c create mode 100644 src/zrtp_legal.c create mode 100644 src/zrtp_list.c create mode 100644 src/zrtp_log.c create mode 100644 src/zrtp_pbx.c create mode 100644 src/zrtp_protocol.c create mode 100644 src/zrtp_responder.c create mode 100644 src/zrtp_rng.c create mode 100644 src/zrtp_srtp_builtin.c create mode 100644 src/zrtp_srtp_dm.c create mode 100644 src/zrtp_string.c create mode 100644 src/zrtp_utils.c create mode 100644 src/zrtp_utils_proto.c create mode 100644 test/README create mode 100644 test/pc/zrtp_test_core.c create mode 100644 test/pc/zrtp_test_core.h create mode 100644 test/pc/zrtp_test_crypto.c create mode 100644 test/pc/zrtp_test_queue.c create mode 100644 test/pc/zrtp_test_queue.h create mode 100644 test/pc/zrtp_test_ui.c create mode 100644 test/win_ce/ReadMe.txt create mode 100644 test/win_ce/libzrtp_test_GUI.cpp create mode 100644 test/win_ce/libzrtp_test_GUI.h create mode 100644 test/win_ce/libzrtp_test_GUI.ico create mode 100644 test/win_ce/libzrtp_test_GUIppc.rc create mode 100644 test/win_ce/libzrtp_test_GUIppc.rc2 create mode 100644 test/win_ce/libzrtp_test_GUIsp.rc create mode 100644 test/win_ce/libzrtp_test_GUIsp.rc2 create mode 100644 test/win_ce/resourceppc.h create mode 100644 test/win_ce/resourcesp.h create mode 100644 test/win_ce/stdafx.cpp create mode 100644 test/win_ce/stdafx.h create mode 100644 third_party/bgaes/aes.h create mode 100644 third_party/bgaes/aes_modes.c create mode 100644 third_party/bgaes/aescrypt.c create mode 100644 third_party/bgaes/aeskey.c create mode 100644 third_party/bgaes/aesopt.h create mode 100644 third_party/bgaes/aestab.c create mode 100644 third_party/bgaes/aestab.h create mode 100644 third_party/bgaes/bg2zrtp.h create mode 100644 third_party/bgaes/brg_types.h create mode 100644 third_party/bgaes/sha1.c create mode 100644 third_party/bgaes/sha1.h create mode 100644 third_party/bgaes/sha2.c create mode 100644 third_party/bgaes/sha2.h create mode 100644 third_party/bnlib/CHANGES create mode 100644 third_party/bnlib/Makefile create mode 100644 third_party/bnlib/Makefile.in create mode 100644 third_party/bnlib/README.bn create mode 100644 third_party/bnlib/README.bntest create mode 100644 third_party/bnlib/bignum-ARM/README-small-memory create mode 100644 third_party/bnlib/bignum-ARM/bntest16.c create mode 100644 third_party/bnlib/bignum-ARM/config.h create mode 100644 third_party/bnlib/bignum-ARM/cputime.h create mode 100644 third_party/bnlib/bignum-ARM/kludge.h create mode 100644 third_party/bnlib/bignum-ARM/lbn.h create mode 100644 third_party/bnlib/bignum-ARM/lbn16.c create mode 100644 third_party/bnlib/bignum-ARM/lbn16.h create mode 100644 third_party/bnlib/bignum-ARM/lbnarm.h create mode 100644 third_party/bnlib/bignum-ARM/lbnarm.s create mode 100644 third_party/bnlib/bignum-ARM/lbnmem.c create mode 100644 third_party/bnlib/bignum-ARM/lbnmem.h create mode 100644 third_party/bnlib/bignum-ARM/sha256_arm.c create mode 100644 third_party/bnlib/bignum-ARM/sha256_core.s create mode 100644 third_party/bnlib/bn.c create mode 100644 third_party/bnlib/bn.doc create mode 100644 third_party/bnlib/bn.h create mode 100644 third_party/bnlib/bn00.c create mode 100644 third_party/bnlib/bn16.c create mode 100644 third_party/bnlib/bn16.h create mode 100644 third_party/bnlib/bn32.c create mode 100644 third_party/bnlib/bn32.h create mode 100644 third_party/bnlib/bn64.c create mode 100644 third_party/bnlib/bn64.h create mode 100644 third_party/bnlib/bn68000.c create mode 100644 third_party/bnlib/bn8086.c create mode 100644 third_party/bnlib/bnconfig.hin create mode 100644 third_party/bnlib/bninit16.c create mode 100644 third_party/bnlib/bninit32.c create mode 100644 third_party/bnlib/bninit64.c create mode 100644 third_party/bnlib/bnintern.doc create mode 100644 third_party/bnlib/bnprint.c create mode 100644 third_party/bnlib/bnprint.h create mode 100644 third_party/bnlib/bnsize00.h create mode 100644 third_party/bnlib/bntest00.c create mode 100644 third_party/bnlib/bntest16.c create mode 100644 third_party/bnlib/bntest32.c create mode 100644 third_party/bnlib/bntest64.c create mode 100755 third_party/bnlib/cfg create mode 100755 third_party/bnlib/cfg.debug create mode 100644 third_party/bnlib/configure.in create mode 100644 third_party/bnlib/cputime.h create mode 100644 third_party/bnlib/germain.c create mode 100644 third_party/bnlib/germain.h create mode 100644 third_party/bnlib/germtest.c create mode 100644 third_party/bnlib/jacobi.c create mode 100644 third_party/bnlib/jacobi.h create mode 100644 third_party/bnlib/kludge.h create mode 100644 third_party/bnlib/lbn.h create mode 100644 third_party/bnlib/lbn00.c create mode 100644 third_party/bnlib/lbn16.c create mode 100644 third_party/bnlib/lbn16.h create mode 100644 third_party/bnlib/lbn32.c create mode 100644 third_party/bnlib/lbn32.h create mode 100644 third_party/bnlib/lbn64.c create mode 100644 third_party/bnlib/lbn64.h create mode 100644 third_party/bnlib/lbn68000.c create mode 100644 third_party/bnlib/lbn68000.h create mode 100644 third_party/bnlib/lbn68020.c create mode 100644 third_party/bnlib/lbn68020.h create mode 100644 third_party/bnlib/lbn68360.s create mode 100644 third_party/bnlib/lbn80386.asm create mode 100644 third_party/bnlib/lbn80386.h create mode 100644 third_party/bnlib/lbn80386.s create mode 100644 third_party/bnlib/lbn8086.asm create mode 100644 third_party/bnlib/lbn8086.h create mode 100644 third_party/bnlib/lbn960jx.h create mode 100644 third_party/bnlib/lbn960jx.s create mode 100644 third_party/bnlib/lbnalpha.h create mode 100644 third_party/bnlib/lbnalpha.s create mode 100644 third_party/bnlib/lbnmem.c create mode 100644 third_party/bnlib/lbnmem.h create mode 100644 third_party/bnlib/lbnppc.c create mode 100644 third_party/bnlib/lbnppc.h create mode 100644 third_party/bnlib/legal.c create mode 100644 third_party/bnlib/legal.h create mode 100644 third_party/bnlib/ppcasm.h create mode 100644 third_party/bnlib/prime.c create mode 100644 third_party/bnlib/prime.h create mode 100644 third_party/bnlib/sieve.c create mode 100644 third_party/bnlib/sieve.h create mode 100644 third_party/bnlib/sizetest.c create mode 100644 third_party/bnlib/test/README.dhtest create mode 100644 third_party/bnlib/test/README.dsatest create mode 100644 third_party/bnlib/test/README.rsatest create mode 100644 third_party/bnlib/test/dhtest.c create mode 100644 third_party/bnlib/test/dsatest.c create mode 100644 third_party/bnlib/test/first.h create mode 100644 third_party/bnlib/test/kb.h create mode 100644 third_party/bnlib/test/kbmsdos.c create mode 100644 third_party/bnlib/test/kbunix.c create mode 100644 third_party/bnlib/test/keygen.c create mode 100644 third_party/bnlib/test/keygen.h create mode 100644 third_party/bnlib/test/keys.c create mode 100644 third_party/bnlib/test/keys.h create mode 100644 third_party/bnlib/test/kludge.h create mode 100644 third_party/bnlib/test/legal.c create mode 100644 third_party/bnlib/test/md5.c create mode 100644 third_party/bnlib/test/md5.h create mode 100644 third_party/bnlib/test/noise.c create mode 100644 third_party/bnlib/test/noise.h create mode 100644 third_party/bnlib/test/posix.h create mode 100644 third_party/bnlib/test/primes.doc create mode 100644 third_party/bnlib/test/primetest.c create mode 100644 third_party/bnlib/test/pt.c create mode 100644 third_party/bnlib/test/random.c create mode 100644 third_party/bnlib/test/random.h create mode 100644 third_party/bnlib/test/randpool.c create mode 100644 third_party/bnlib/test/randpool.h create mode 100644 third_party/bnlib/test/randtest.c create mode 100644 third_party/bnlib/test/rsaglue.c create mode 100644 third_party/bnlib/test/rsaglue.h create mode 100644 third_party/bnlib/test/rsatest.c create mode 100644 third_party/bnlib/test/sha.c create mode 100644 third_party/bnlib/test/sha.h create mode 100644 third_party/bnlib/test/types.h create mode 100644 third_party/bnlib/test/userio.h create mode 100644 third_party/bnlib/test/usuals.h diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000000..471f0148b3 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,33 @@ +# +# 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 Krikun + +libzrtp BETA + +Created by Phil Zimmermann. + +Developers: + Viktor Krikun + Nikolay Popok + Vitaly Rozhkov + Andrey Rozinko + Bryce Wilcox-O'Hearn + +Thanks to: + Alan Johnston + Jon Callas + Hal Finney + Colin Plumb + Sagar Pai + Werner Dittmann + L. Amber Wilcox-O'Hearn + Ariel Boston + Donovan Preston + +Software development services provided by Soft_industry http://www.soft-industry.com/en. + +Portions of this software are available under open source licenses from other authors. +Notably, Brian Gladman's AES implementation, and David McGrew's libSRTP package. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000000..e86032d299 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,556 @@ + * 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. + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +SINCE LIBZRTP v0.80 CHANGELOG IS A PART OF HTML DOCUMENTATION. +https://developers.zfoneproject.com/libzrtp/wiki/LibzrtpChangeLog +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + +libzrtp 0.7.1 18.11.2008 +-------------------------------------------------------------------------------- +1. Fixed bug with hardcoded AES128 cipher for generating SRTP keys. In this + version is selected according to ZRTP discovery. + +2. Added initialization/deinitalization functions to zrtp helper functions. + +libzrtp 0.7.0 04.11.2008 +-------------------------------------------------------------------------------- +1. Changes in libzrtp sources tree. + +2. Improvements in libzrtp initialization routine: + - all global zrtp options were combined in zrtp_config_t structure; + - zrtp_init() allocates memory for zrtp global context; + - zrtp_config_defaults() + +3. Improvements for Passive/Active mode support. + a) A passive endpoint never sends a commit message, period. Also, it + declares itself as a passive endpoint by setting the P flag it its own + Hello message; + b) A active endpoint does not send a commit to a passive endpoint, which it + recognizes by detecting the P flag; + c) A passive phone, if acting as a SIP initiator (meaning it initiated the + call), rejects all commit packets from everyone; + d) A passive phone rejects all commit messages from a PBX, which is easily + recognized by the M flag. + Passive mode support is built into the library logic and will be used + automatically if the developer specifies signaling role by setting + is_initiator flag in zrtp_init_session_ctx(). + +4. Improvements in ZRTP feedback interface and system-dependent functions. + There are two types of interface functions in libzrtp: system dependent API + and realization of helper functions and events. System dependent API in + defined in zrtp_iface_system.h as set of extern functions. System + functions are already implemented for several basic platforms in + zrtp_iface.sys.c libzrtp feedback and helper functions were re-factored + and implemented as set of callbacks. If the developer doesn't want to + handle one or another event it may just leave necessary pointer empty. + See zrtp_init() and zrtp_callback_t, zrtp_iface.h for more details. + +5. ZRTP configuration approach was improved: zrtp_config_xxx.h contains + adjustments for necessary target platform. libzrtp contains default + configs for Linux, OS X, Windows, Window CE and Symbian platforms. + All ZRTP protocol and behavior related adjustments are collected in + zrtp_config_user.h. Edit this file to configure libzrtp for your + needs. + +6. Implemented new functions in protocol according to the Internet Draft v 10. + +7. Improved realization of built-in libzrtp scheduler. Fixed bug with crashing + on performing delay call when zrtp session have been already deleted. + +8. Logging function was improved. Use ZRTP_LOG macro to print log messages. See + zrtp_log.h for more information. + + +libzrtp 0.6.8 03.09.2008 +-------------------------------------------------------------------------------- +ZRTP +1. Fixed bug with incorrect maximum value for T1 retry interval timer which + increased delay between LOOKING_FOR_ZRTP and NO_ZRTP_SUPPORT states. + Internal fix, no API changes required; +2. Implemented version negotiation according to the latest specification. + libzrtp v 0.6.8 supports ZRTP v0.90 only. No changes required in + applications that use the SDK. +3. Compilation flag WITH_ZFONE was removed. The developer, who wants to use + built-in ZRTP cache, has to set name of the ZRTP cache explicitly, + implementing zrtp_get_cache_path() function. +4. New libzrtp licensing scheme was implemented. It allows the licensing policy + to be changed at run time. See zrtp_license_mode_t doc. for more details. + Affected API - zrtp_init(). +5. ZRTP Protocol version was changed to 0.90 according to ZRTP Internet Draft. +6. Some changes in Linux config files: surplus configuration flags were removed + from ./cfg.XXX templates. +7. Added experimental ZRTP messages retries scheduler for slow channels. As + ex ample for GSM CSD channel with average bandwidth 6Kb/s. To use this + option build library with BUILD_FOR_CSD flag. + + +libzrtp 0.6.6 27.06.2008 +-------------------------------------------------------------------------------- +ZRTP +1. Small bug was fixed in S0 calculation: when RS1 is corrupted the library uses + RS2 instead; +2. Some changes in Makefile and building process: unused header were eliminated + from the installation process. +3. -DBUILD_WITH_ZRTP_MUTEXES was replaced with --enable_mutexes option passed to + ./configure script. This change allows not to specify any libzrtp compilation + flags during user application compilation. --enable-mutexes adds + BUILD_ZRTP_MUTEXES definition to the ./config/zrtp_unix_config.h so if you + build libzrtp on other platforms - define this flag manually (windows + configuration file already includes this option). +4. Clean-up in .h and .c comments was made. + + +libzrtp 0.6.5 04.06.2008 +-------------------------------------------------------------------------------- +ZRTP +1. New names for: other_secret - pbxs; srtps - auxs. In bits and secrets storages; +2. RS2 secret was eliminated form DH s0 calculation; +3. Protocol version number was increased to 0.85 + + +libzrtp 0.6.4 19.05.2008 +-------------------------------------------------------------------------------- +ZRTP +1. According to the new version of the Internet Draft Signaling shared secret was + removed from the protocol and from the sources. It was not used by interface + functions and developers may change nothing in libzrtp based applications. + +2. DH4K Key echange was eleminated from the specification and from the sources. + Now ECDH is used for all larger AES key sizes. + + +libzrtp 0.6.2 04.02.2008 +-------------------------------------------------------------------------------- +ZRTP +1. New behaviour for Secure --> Clear --> Secure scenario was implemnted. According + to ZRTP ID 06 section 5.7.2.1 new value of ZRTPSess computed as hash(ZRTPSess). + +DOC: + Libzrtp documentation was updated up to version 0.6.2. + + +libzrtp 0.6.1 03.14.2008 +-------------------------------------------------------------------------------- +ZRTP +1. Multistream mode was implemented according to ZRTP Internet Draft 05.n: + - new stream mode zrtp_stream_mode_t:: ZRTP_STREAM_MODE_MULT; + - Multistream key exchange component was added with ID zrtp_pktype_id_t:: + ZRTP_PKTYPE_MULT and symbolic name ZRTP_MULT. To allow libzrtp use Multistream + mode - ZRTP_PKTYPE_MULT have to be added to the stream profile in the first + position; + - According to the new draft SAS and ZRTPSess key are Session option and + were moved to the zrtp_conn_ctx_t structure. New specification defines + single SAS values for all streams within the session; + - ZRTP state-machine was changed to handle Multistream mode. In .Fast. mode + DH exchange is omitted and stream skips ZRTP_STATE_WAIT_CONFIRM1 and + ZRTP_STATE_PENDINGSECURE for the Initiator and Responder state-machines, + respectively; + +2. Hash preimages were added to prevent DOS attacks. See ZRTP ID sec 9.0 for detail + information. This option is available using zrtp_set_signaling_hash() and + zrtp_get_signaling_hash() functions. + +3. Hmac values were added to every packet to allow eliminate SAS validation + if SIP is protected; + +4. Autosave. of the default realization of the ZRTP cache to the hard drive was + implemented; + +5. Lot of other internal changes and improvements according to the latest ZRTP + specification v06. + + +libzrtp 0.4.5-6 +-------------------------------------------------------------------------------- + 1. Full PBX support. Tested on GS-Labs Asterisk + API: + DOC: + + 2. Resolved problem with BG ciphers compilation: initialization of AES hash tables. + + 3. Fixed bug in SRTP replay protection. (Undeleted nodes for mulsy-stream encryption) + (May resulted in a error zrtp_protocol_error_t::zrtp_status_rp_fail) + + 4. Vrification is a session option. Input parameter of zrtp_set_verified() was + changed from stream to ZRTP session structure. + + 5. Fixed bug with malformed ZRTP Hello packet. + + 5. fast video + +libzrtp 0.4.4 31.07.2007 +-------------------------------------------------------------------------------- + 1. New extra error code for replay protection was added. + See zrtp_status_t::zrtp_status_rp_fail. + + 2. Fixed bug which may resulted in a dammage with decrypt failed 7 error. It + was happen when libzrtp passed RTP alerts packet to the replay protection + engine and ROC was broken. + + 3. Fixed RTCP encryption/decryption. + + 4. Fixed bug with RS1 and RS2 swapping when one of the sides lost RS1. + (May resulted in a error zrtp_protocol_error_t::zrtp_error_auth_decrypt ) + + +libzrtp 0.4.3 06.07.2007 +-------------------------------------------------------------------------------- + 1. Beta version of API for PBX support according to the latest ZRTP draft. + Not tested. For internal development only. Follow // PBX comments; + - secret's cache format was changed. + + 2. S0 calculation according to NIST recommendations; Internal change + - ZRTP protocol version was increased to 0.07. + + 3. All libzrtp sources was audited with coverity code analyzer. http://coverity.com/ + +libzrtp (0.3.9 - 0.4.2) 27.06.2008 +-------------------------------------------------------------------------------- + 1. Changes according to new draft 04a. All changes are internal. + a) new DH packets: pvi/pvr, nonce field is at the end of the DH packet. + In "Preshared" mode both DH packets contain nonce value instead of pvi/r; + b) new hvi value the same for all modes (DH and Preshared) + hvi = hash(initiator's DHPart2 message | responder's Hello message); + c) new algorithm of SAS computing: sasvalue = HMAC(hmackeyi,"SAS"); + + 2. New GUI based test-unite forSymbian platform + + 3. Default implementation of the packet retries unite for Symbian was added + to the libzrtp package. Except besides scheduler, libzrtp includes + realization of some synchronization and threading routines. These + components written in C++ and can't be linked with the library. One should + add them to own Symbian project project. + + 4. Compilation of default realization of ZRTP mutexes was separated from + the other system interfaces. To build library with default mutexes + BUILD_ZRTP_MUTEXES flag should be used; + + 5. New clearing logic. Goals: + API: + - state-machine states were changed + - goclear reason was eliminated. Now we can switch to CLEAR just on + user action. + - ZRTP_EVENT_IS_INITIATINGCLEAR was removed as a uperfluous event. As a + result all event codes were changed. + - new clear_hmac = HMAC(hmakkeyi/r, "Clear Hmac") + 6. New Errors handling logic. See updated state-macine diagram and "developers + guide". + API: + - ZRTP_STATE_ERROR was added to handle error requests. Libzrtp switches + to this state after the Error exchange. From ZRTP_STATE_ERROR stream + cxan be started again or destroyed, depending on application strategy. + - ZRTP_ERRORACK and ZRTP_ERROR packets were added + - new event ZRTP_ENEVT_NO_ZRTP inform's user that other side doesn't + support ZRTP encryption. + + 7. -D WITH_STACK_MINIM compilation flag allows to minimize coasts for the + system stack. In the most critical places dynamic allocation will be used + instead of static variables. This option can be useful on mobile platforms + in kernel mode, etc. + + 8. Several bug fixes in scheduler. Improved built-in realization of Symbian + platform. If you use our default realization on Symbian - please update. + + 9. David A. McGrew's srtp was replaced with our own. We did it to get control + over all crypto functions, generalize interface of crypto component. It + allows us to port libsrtp to any platforms more smoothly. We have one + configuration file, all platform-dependent function and definitions are + concentrated at one place. We eliminated superfluous functionality from + libsrtp, made it crossplatform and thread-safe. In SRTP engine we use our + own crypto-components based on by Dr. Brian Gladman's sources. Each component + has strong self-test function allows it to be tested on any platform and + in any environment. + - project structure was changed; + - bgaes folder includes AES and SHA routines by Dr. Brian Gladman. For details + see dgaes/howto and bg2zrtp.h files; + - libzrtp supports external realizations of SRTP (Use zrtp_srtp.h API and flag + -D WITHOUT_BUILTIN_SRTP ); + + 10. Header files were refactored: one can add just single zrtp.h include to use + any libzrtp function or data type; + + 11. Solved problem with deadlock during Video conferences. (One side starts + negotioation with Video and another one with Audio stream) + + 12. Some changes in test-unite: + - test vectores and test-cases for all cryptio components are available; + - zrtp_system_test.h checks environment and compilation flags + - use ZRTP_ENABLE_TEST flag to build library with all tests + 13. Full documentation review and updating. + + 14. Sources clean up and some refactoring; + + 15. Fixing in "break the tie" logic. See diagrams and zrtp_preparse_commit(), + zrtp_preparse_init_commit(); + + 16. Some changes according to the lates ZRTP specification: + - sasvalue was trancated to 32 bits and used mostleft parts of the hashvalue. + + 17. Small bug fixes (zrtp_can_start_dh and zrtp_can_start_preshared() mixed into + zrtp_can_start_stream); + + 18. New key derivation mechanism according to NIST standarts. See ZRTP Draft + 5.4.4 and 5.5.4. + +libzrtp (0.3.7) +-------------------------------------------------------------------------------- + 1. New, more clear and useful test-unite + 2. Eliminated zrtp_stop_protocol(). Now zrtp_done_session_ctx() includes + protocol stopping. + 3. Some simplifications in project structure: removed zrtp_inet.h and bnase32.h, + zrtp_iface.c was removed to src\iface folder; + 4. ZSTR_GET_VALUE should be used to convert zrtp_stringxx_t to zrtp_stringn_t; + 5. Some changes for windows CE; + 6. Changed default options: SAS base256 enabled by defauld and "staysecure" is on. + +libzrtp (0.3.6) +-------------------------------------------------------------------------------- + FIXES: + a) CRC now covers the whole ZRTP packet, not just a body + b) improved names of some crypto-components in HELLO/COMMIT packets + c) improved messages hash: hash function covers all ZRTP message with + magic number and length fields; + d) fixed DHPart1 and DHPart2 packets format according to last version + of ZRTP Internet draft. + e) fixed retain secrets sorting algorithm according to the last version + of the internet draft. + + 1. Windows CE support. Now library is fully compatible with Windows CE. + - .\libzrtp\projects\libzrtp_wince_vc8.sln project file for MS VS 2005 + - .\libzrtp\test\WinCE contains sources of simple test-unite ( We have + just started working in this direction and more intelligent test unite + will be available soon. Tested on HTC S620 with Windows CE 2005 ) + + 2. Added previous state field to ZRTP stream structure. It can be used to + analyze conditions of switching from one state to another. (For libzrtp + developers only) + API: + - zrtp_stream_ctx_t#_prev_state was added + - _zrtp_change_state() MUST be used to switch from one state to another + + 3. Some changes in PENDING_CLEAR state handler. In case of error during + transition from CLEAR to SECURE state-machine will switch back to CLEAR + without the confirmation by user. + + +libzrtp (0.3.5) +-------------------------------------------------------------------------------- + Full description is in progress + + 1. Support of all crypto futures according to the new ZRTP draft v 0.3. Lots + of internal changes were provided in ZRTP kernel. + + 2. Symbian support. Now you can build libzrtp and test unites on Symbian + platforms. There are .inf and .mmp files in corresponded directories. + (Symbian project files are a little bit row and we will appreciate any + suggestions and advices.) + + 3. ZRTP stream became more independent. You can use different configurations + for different streams. So + ZRTP profile: profile; + "staysecure" flag: staysecure; + SAS values: sas_values; + cache TTL: cache_ttl; + and all used crypto components were removed from session context + (zrtp_conn_ctx_t) to stream context (zrtp_stream_ctx_t). + API: + - you should configure every stream in the same way as the whole session in + previous version has been done. See zrtp_init_session_ctx() + and zrtp_attach_stream() + + 4. "Multistream" mode was replaced by "Preshared" (based on retain secrets + from previous call. See http://zfoneproject.com/docs/ietf/draft-zimmermann-avt-zrtp-03.html#anchor19 . + Preshared mode is available as a normal ZRTP crypto component e.g."DH3K" + or "DH4K". If you enable Preshared mode in profile and libzrtp finds + secrets in your cache - "Preshared" mode will be used for all next calls + API: + - the choice of stream mode was removed from zrtp_start_stream() and + from zrtp_secure_stream(). + + 5. Integer enumerations for all crypto components e.g. Hash type, cipher type + etc. You should use these values instead of character values for optional + profile configuration. (as an example for enabling "preshared" mode) + API: + - enumerations types zrtp_hash_id, zrtp_cipher_idzrtp_atl_id, + zrtp_pktype_id, zrtp_sas_id in zrtp_crypto.h + - all crypto components structures now have id field and libzrtp + operates with this field to find, register or delete crypto + components. + - ZRTP profile: zrtp_profile_t uses this integer values too. (list of + crypto-components is a zero terminated array of values of necessary + type) + - zrtp_find_in_profile() and zrtp_find_comp() operate with component + integer identifiers + - there are two special functions to convert component ID to ZRTP + character name: zrtp_comp_id2type(), zrtp_comp_type2id. + + 6. Integer error codes were provided instead of 4-character values. One should + use them to analyze zrtp_stream_ctx_t#last_error value in your ZRTP + errors handlers. + API: + - zrtp_protocol_error_t was added to zrtp_error.h. + - zrtp_stream_ctx_t#last_error now is an integer value from + zrtp_protocol_error_t space. + + 7. Special function for verification of SAS value was added. One should use + this function to set/unset SAS verification flag from his own + application. + API: + - zrtp_set_verified() was added to zrtp.h + + 8. Some optimization of types was provided. Here are some possible changes which you + need to make in your product: + - libzrtp uses it own strings (zrtp_stringXX_t group) to operate with + binary and character strings. In this version we made attempt to + minimize memory coasts and replaced zrtp_string_t with zrtp_stringXX_t + group, where XX - maximum length in bytes. zrtp_stringxx_t contains + its length and as a result all functions for work with strings are + type independent. So one should use one of these types to store binary + strings and zrtp_stringn_t as a type of operand in all global functions. + - all retain secrets holders and flags were removed to zrtp_secrets + structure in zrtp_conn_ctx_t#secrets. + - zrtp_packet_string4_t was replaced by zrtp_ucharXX_t group where XX - + type length in bytes. These types are used in library for packets + construction instead of char arrays. + + 9. Packets retries synchronization was added. zrtp_retry_task_t structure + from zrtp_types_t is used for all operations with scheduler. One should + use #callback and #timeout fields from this structure. + API: + - zrtp_send_packet_later(), zrtp_cancel_send_packet_later() + +libzrtp (0.3.4) +-------------------------------------------------------------------------------- + 1. ZRTP state-macine was fully refactored. All transitions between states + are absolutely identical to diagram attached to documentation. + DOC: + - See doc/img/png/state_mach_ext.png + + 2. ZRTP uses new packets format according to draft-zimmermann-avt-zrtp-03i + + 3. Improved some mistakes in libbn make-files for windows. Unused + functions were omitted. + + 4. Provided types optimization to decrease RAM memory costs. + + 5. Packets retries were synchronized. + + 6. zrtp_voip_proto_t was removed from the library + API: + - if you need this enumeration see zfone_types.h in zfone project + + 7. "GoClear reasons" support + + 8. Some internal changes according to draft-zimmermann-avt-zrtp-03i + a) Commit hash covers the whole Hello body + b) GoClear hmac includes "Reason string" + c) Confirm body encrypted by AES CDB cipher + d) Confirm hmac covers whole encrypted part of the packet + + 9. Use BUILD_ZRTP_DEBUG_LOG flag instead of BUILD_DEBUG_LOG to build the + library with debug logs. + +libzrtp (0.3.3) 21.02.2007 +-------------------------------------------------------------------------------- + 1. libzrtp test application refactored for better performance and usability. + For addition information see test application README file and + "libzrtp test suite" chapter in main documentation page. + + 2. Some changes in documentation for better English + + 3. Use microseconds in zrtp_time_t instead of milliseconds. + API changes: + - change zrtp_get_time() function realization if needed + + 4. Fixed several small mistakes + + +libzrtp (0.3.2) 09.02.2007 +-------------------------------------------------------------------------------- + 1. Global context allocation removed to user space. + This was made to able RNG using before library initialization. + API changes: + - zrtp_init(), zrtp_down() + - zrtp_randstr(), zrtp_add_system_state() + + 2. Fixed bug in srtp SHA1 calculation for Windows. + + 3. Confirm and GoClear HMAC was truncated to 64 bits. + + 4. Calls stack minimized for library using in kernel mode + + 5. Default realization of secrets' cache is available. Cache was implemented + as a simple binary file and can be built using -DBUILD_DEFAULT_CACHE file. + API: + - realization at src\iface\zrtp_cache.c + DOC: + - 1.4 libZRTP setup and building + - 2.2 System-dependent functions + + 6. Default cross-platform realization of time-out sending unite is available. + This unite is available for Linux, MacOS and Windows. It can be built using + -DBUILD_DEFAULT_TIMER flag. + API: + - realization at src\iface\zrtp_scheduler.c + DOC: + - 1.4 libZRTP setup and building + - 2.2 System-dependent functions + + 7. "HOWTO libzrtp" was added to the library documentation + +libzrtp (0.3.1) 06.12.2006 +-------------------------------------------------------------------------------- + 1. Global variables were removed from c-files. Added global context + zrtp_global_ctx_t for necessary data storing. This was made to allow + to build library in some special environment as Symbian OS ed2. + DOC changes: + - 2.1.2 data structure + API changes: + - zrtp_global_ctx_t added + - zrtp_init(), zrtp_down(), zrtp_init_session(), zrtp_down_session() + + 2. Added multithreading support. Now libzrtp is thread-safe. About all + conditions of usage in multithreading application and synchronization + schemes see section "2.3.3 Multithreading and concurrent streams" in + developers guide. + DOC changes: + - 2.2.3 Multithreading and concurrent streams + API changes: + - mutex were added to main data structures + - mutex interface section at zrtp_iface.c, default realization at + zrtp_iface.c + + 3. Session configuration routine was simplified. ZRTP profile is applied on + session initialization. Some configuration functions were removed and + changed. + DOC changes: + - 2.3.1 Setup, initialization and deinitialization + API: + - zrtp_profile_autoload() removed + - zrtp_init_session(), zrtp_check_profile() + + 4. Default realizations of system interfaces was added (for Windows, Linux + and MacOS). + API: + - zrtp_iface.c added + + 5. Test suit developed. + Simple test-unite created. It runs several ZRTP sessions, enters SECURE + mode, shows statistics and is closed. To build test-suite on Unix - use C + flags -DBUILD_DEBUG_LOG -DBUILD_WITH_CFUNC -DBUILD_EMPTY_CACHE + -DBUILD_EMPTY_TIMER and configure param. --enable-test. To run tests: + make check. To build test-suite on Windows use necessary project files. + DOC changes: + - 1.4 libZRTP setup and building + API: + - Sources can be found at /test directory + + 6. Some changes in project structure, configuration and make files according + to new functionality. + DOC changes: + - 1.4 libZRTP setup and building + \ No newline at end of file diff --git a/README b/README new file mode 100644 index 0000000000..c6d90aae2e --- /dev/null +++ b/README @@ -0,0 +1,10 @@ +# +# 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. +# + +- Check HTML Documentation ./doc +- Visit the Zfone Project Home Page http://zfoneproject.com/ +- Report bugs via the Zfone Bugs Page http://zfoneproject.com/bugs.html diff --git a/doc/Doxyfile b/doc/Doxyfile new file mode 100644 index 0000000000..b01900e4d5 --- /dev/null +++ b/doc/Doxyfile @@ -0,0 +1,1553 @@ +# Doxyfile 1.5.8 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = libzrtp + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = v0.91 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ./out + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, +# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, +# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, +# Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = /Users/dimitri/doxygen/mail/1.5.7/doxywizard/ + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it parses. +# With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this tag. +# The format is ext=language, where ext is a file extension, and language is one of +# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, +# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ./manuals/main.dox \ + ./manuals/howto.dox \ + ./manuals/changelog.dox \ + ./manuals/rng.dox \ + ./../include/zrtp_config_user.h \ + ./../include/zrtp.h \ + ./../include/zrtp_iface_system.h \ + ./../include/zrtp_iface.h \ + ./../include/zrtp_error.h \ + ./../include/zrtp_types.h \ + ./../include/zrtp_string.h \ + ./../include/zrtp_pbx.h + + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.vhd \ + *.vhdl + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = header.html + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = footer.html + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = doxygen.css + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = YES + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. +# For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's +# filter section matches. +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to FRAME, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. Other possible values +# for this tag are: HIERARCHIES, which will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list; +# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which +# disables this behavior completely. For backwards compatibility with previous +# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE +# respectively. + +GENERATE_TREEVIEW = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = NO + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Options related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/doc/doxygen.css b/doc/doxygen.css new file mode 100644 index 0000000000..1d38770349 --- /dev/null +++ b/doc/doxygen.css @@ -0,0 +1,451 @@ +BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { + font-family: Geneva, Arial, Helvetica, sans-serif; +} + +BODY,TD { + font-size: 100%; +} + +CODE { + font-size: 120%; + font-family: monospace; +} + +.fragment, pre { + font-size: 110%; + font-family: monospace; +} +H1 { + text-align: center; + font-size: 240%; +} +H2 { + font-size: 180%; + margin-top: 60px; +} +H3 { + font-size: 140%; +} +H4 { + font-size: 120%; +} + +caption { + font-weight: bold; +} + +div.qindex, div.navtab{ + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + padding: 2px; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #153788; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #1b77c5; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #6666cc; + color: #ffffff; + border: 1px double #9295C2; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code { +} + +a.codeRef { +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +.fragment { + font-family: monospace, fixed; + font-size: 105%; +} + +pre.fragment { + border: 1px solid #CCCCCC; + background-color: #f5f5f5; + padding: 4px 6px; + margin: 4px 8px 4px 2px; +} + +div.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + margin-bottom: 6px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background: white; + color: black; + margin-right: 20px; + margin-left: 20px; +} + +td.indexkey { + background-color: #e8eef2; + font-weight: bold; + border: 1px solid #CCCCCC; + margin: 2px 0px 2px 0; + padding: 2px 10px; +} + +td.indexvalue { + background-color: #e8eef2; + border: 1px solid #CCCCCC; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #f0f0f0; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl { + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +/* @end */ + +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #84b0c7; +} + +th.dirtab { + background: #e8eef2; + font-weight: bold; +} + +hr { + height: 0; + border: none; + border-top: 1px solid #666; +} + +/* @group Member Descriptions */ + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #FAFAFA; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memItemLeft, .memItemRight, .memTemplParams { + border-top: 1px solid #ccc; +} + +.memTemplParams { + color: #606060; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtemplate { + font-size: 80%; + color: #606060; + font-weight: normal; + margin-left: 3px; +} + +.memnav { + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.memitem { + padding: 0; +} + +.memname { + white-space: nowrap; + font-weight: bold; +} + +.memproto, .memdoc { + border: 1px solid #84b0c7; +} + +.memproto { + padding: 0; + background-color: #d5e1e8; + font-weight: bold; + -webkit-border-top-left-radius: 8px; + -webkit-border-top-right-radius: 8px; + -moz-border-radius-topleft: 8px; + -moz-border-radius-topright: 8px; +} + +.memdoc { + padding: 2px 5px; + background-color: #eef3f5; + border-top-width: 0; + -webkit-border-bottom-left-radius: 8px; + -webkit-border-bottom-right-radius: 8px; + -moz-border-radius-bottomleft: 8px; + -moz-border-radius-bottomright: 8px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} + +/* @end */ + +/* @group Directory (tree) */ + +/* for the tree view */ + +.ftvtree { + font-family: sans-serif; + margin: 0.5em; +} + +/* these are for tree view when used as main index */ + +.directory { + font-size: 9pt; + font-weight: bold; +} + +.directory h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +/* +The following two styles can be used to replace the root node title +with an image of your choice. Simply uncomment the next two styles, +specify the name of your image and be sure to set 'height' to the +proper pixel height of your image. +*/ + +/* +.directory h3.swap { + height: 61px; + background-repeat: no-repeat; + background-image: url("yourimage.gif"); +} +.directory h3.swap span { + display: none; +} +*/ + +.directory > h3 { + margin-top: 0; +} + +.directory p { + margin: 0px; + white-space: nowrap; +} + +.directory div { + display: none; + margin: 0px; +} + +.directory img { + vertical-align: -30%; +} + +/* these are for tree view when not used as main index */ + +.directory-alt { + font-size: 100%; + font-weight: bold; +} + +.directory-alt h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +.directory-alt > h3 { + margin-top: 0; +} + +.directory-alt p { + margin: 0px; + white-space: nowrap; +} + +.directory-alt div { + display: none; + margin: 0px; +} + +.directory-alt img { + vertical-align: -30%; +} + +/* @end */ + +address { + font-style: normal; + color: #333; +} diff --git a/doc/footer.html b/doc/footer.html new file mode 100644 index 0000000000..292249e9d9 --- /dev/null +++ b/doc/footer.html @@ -0,0 +1,4 @@ +
+Generated on $datetime for $projectname  zfone
+ + diff --git a/doc/header.html b/doc/header.html new file mode 100644 index 0000000000..41c1d88fd7 --- /dev/null +++ b/doc/header.html @@ -0,0 +1,6 @@ + + +$title + + + diff --git a/doc/manuals/changelog.dox b/doc/manuals/changelog.dox new file mode 100644 index 0000000000..eb13ef2b5a --- /dev/null +++ b/doc/manuals/changelog.dox @@ -0,0 +1,197 @@ +# +# 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 + +/** + * \file changelog.dox + * \brief libzrtp ChangeLog + */ + +/*! +\page changelog libzrtp ChangeLog + +**************************************************************************************************** +\section v091 DEVELOPERS BUILD Release Notes - libzrtp - Version 0.91 build XXX (ZRTP ID v16x, protocol 1.X) +**************************************************************************************************** +\note To build Libzrtp Enterprise with Elliptic Cure Diffie-Hellman support on Unix platform, use + "./configure --enable-enterprise". By default libzrtp will be build with no ECDH support. + +
+***\subsection v091_feature New features and improvements. + +***\subsection v091_bugs Bug fixes + *- [LZRTP-179] Fixed bug in build scripts when commercial version of libzrtp v0.90 was built + with ZRTP_ENABLE_EC set to 1 by default. + *- [LZRTP-181] Fixed zrtp_init() crash on Mac OSX 10.6 + *- [LZRTP-182] Fixed libzrtp build issue on Free-BSD + + +**************************************************************************************************** +\section v090 Release Notes - libzrtp - Version 0.90 build 577 (ZRTP ID v15x, protocol 1.1) +**************************************************************************************************** +
+***\subsection v090_feature New features and improvements. + *- [LZRTP-178] After the cache mismatch don't update the cache automatically, wait for the SAS verification. More details at this feature could be found in ZRTP ID section 4.6.1.1 + *- [LZRTP-151] Add secrets flags to \ref zrtp_info_t to allow user monitor secrets state + *- [LZRTP-169] Check and optimize build process on Windows mingw and msys. + +***\subsection v090_bugs Bug fixes + *- [LZRTP-176] Added -fPIC flag to Linux and Mac builds to be able to link the library into 64bit applications. + *- [LZRTP-175] Change SHA1 definition name to SRTP_SHA1 and move to private part of the API to eliminate ambiguity. + *- [LZRTP-155] Session info should display current, updated value of the TTL, not the old one from previous negotiation. + *- [LZRTP-177] Diffie-Hellman secret exponent for DH2K should be 256bits instead of 128. + + +**************************************************************************************************** +\section v082 Release Notes - libzrtp - Version 0.82 build 540 (ZRTP ID v15, protocol 1.1) +**************************************************************************************************** +
+Minor improvements. Zfone and libZRTP projects moved to public bug-tracking and wiki system. + +***\subsection v082_feature New features and improvements. + *- Improved libzrtp resistance to long delays during DH calculations on slow hardware. + *- Structures Members alignment in Microsoft Visual Studio projects was changed from 1 byte to "Default". + *- Implemented entropy collection from dropped RTP messages. Don't forget to store RNG seed when you done with libzrtp and upload it agan on next session. + *- Implement default entropy collector for Win32 platform. RtlGenRandom() system call is used. Together with the entropy collection from dropped RTP message, it should guaranty good enough entropy. + *- zrtp_def_cache_reset_since() was implemented as call-back, similar to the rest of ZRTP cache interfaces. + *- Eliminated secure logs from the public build. + *- Public bug-tracker and wiki launched (in addition to our internal tools) + *- libzrtp API documentation is available at developers.zfoneproject.com + + +**************************************************************************************************** +\section v081 Release Notes - libzrtp - Version 0.81 build 514 (ZRTP ID v15, protocol 1.1) +**************************************************************************************************** +
+***\subsection v081_bugs Bug + *- [LZRTP-161] Improvement in ZRTP state-machine\n + libzrtp state-machine didn't process incoming Hello message in StartInitiatingSecure state. + In some situations this issue could cause libzrtp not responding on incoming HELLO messages and freeze the protocol. + + *- [LZRTP-166] Fixed "Secure Since" logic.\n + Previous version of libzrtp computed secure since in a wrong way. libzrtp 0.81 remembers secure since date when new RS1 secret is generated and keep it unchanged while RS secrets are matched for all next calls. + \n + Use zrtp_def_cache_get_since() to get secure since for the particular pair of ZIDs. + \warning Secure since function is available for the build-in implementation of ZRTP cache. + +***\subsection v081_feature New Feature + *- [LZRTP-157] Implement algorithms negotiation according to ZRTP ID v15 section 4.1.2\n + This method is provided to allow the two parties to mutually and deterministically choose the same DH key size and algorithm before a Commit message is sent. No API changes required. + + *- [LZRTP-158] Zfone Ping response implemented.\n + New Zfone3 software uses specific VoIp calls detection algorithms and uses ZRTP Ping to discover the call topology. Each ZRTP endpoint may response with PingAck to be compatible with Zfone3. libzrtp based products don't need to do anything more to support Zfone3. The library handles this automatically. Ping-Response doesn't affect res of ZRTP logic. + \n + \sa Check ZRTP RFC sec 5.16 for more information. + +***\subsection v081_improv Improvement + *- [LZRTP-164] New ZRTP security event was added.\n + Libzrtp rises special event when after switching to secure state, the secrets are not expired, cached, but don't match. In other words: it is typical condition for the MitM attacks. Developer should use this event to notify user about the situation. Check zrtp_security_event_t#ZRTP_EVENT_MITM_WARNING for more detail information. + + *- [LZRTP-153] New Project files to build libzrtp on Windows CE.\n + Check ./projects/win_ce directory to find appropriate Microsoft Visual Studio projects. + + + +**************************************************************************************************** +\section v080 Release Notes - libzrtp - Version 0.80 +**************************************************************************************************** +
+***\subsection v080_bugs Bug + - [LZRTP-97] zrtp_hex2str and zrtp_st2hex don't work correct.\n + Fixed bug in str2hex() providing wrong converting. Previous versions of libzrtp were affect, + but str2hex wasn't used in crypto logic and there was no security weakness. + - [LZRTP-154] zrtp_register_with_trusted_mitm() on storing MiTM secret didn't set the "matches" flag for ZRTP_BIT_PBX. In result, zrtp_is_user_enrolled() returned false right after ZRTP_STATE_SECURE event. This issue affected ZRTP MitM endpoints only and for the very first enrollment stream with the endpoint. In all next calls with the endpoint zrtp_is_user_enrolled() worked correct. + +***\subsection v080_improv Improvement + *- [LZRTP-26] Refactoring in the test-unite\n + Test-unite was redesigned: platform independent test-core and UI parts, specific for every + target platform. test-core has cleaner API and internal structure. UI part allow to simplify + application and separate business logic from UI routine. + + *- [LZRTP-46] Change zrtp_time_t to literal integer type.\n + zrtp_tim_now() just returns current time in milliseconds instead of zrtp_time_t structure. + + *- [LZRTP-83] Refactoring in libzrtp debug logging.\n + Made logs easy to read and analyze. Used indention. + + *- [LZRTP-84] Refactoring in libzrtp terms.\n + Following changes in functions names and data structures were made: + zrtp_stream_ctx_t - zrtp_stream_t\n + zrtp_conn_ctx_t - zrtp_session_t\n + zrtp_global_ctx_t - zrtp_global_t\n + (in zrtp.h more explicitly reflect meaning of data types)\n + \n + ZSTR_GET_VALUE/P - ZRTP_GV/P\n + SET_EMPTY_ZRTP_STRING - ZSTR_SET_EMPTY\n + (in zrtp_string.h just cleaner and shorter names)\n + \n + zrtp_init() (Allocates memory)\n + zrtp_init_session_ctx() - zrtp_session_init(). (Allocates memory)\n + zrtp_add_entropy() - zrtp_entropy_add() \n + zrtp_secure_stream() - zrtp_stream_secure()\n + zrtp_clear_stream() - zrtp_stream_clear()\n + zrtp_done_session_ctx - zrtp_session_down()\n + zrtp_attach_stream - zrtp_stream_attach()\n + zrtp_start_stream() - zrtp_stream_start()\n + zrtp_stop_stream() - zrtp_stream_stop()\n + zrtp_set_verified - zrtp_verified_set()\n + zrtp_check_profile - zrtp_profile_check()\n + (in zrtp.h used following approach: zrtp prefix; module name; action name) + + *- [LZRTP-85] Hide private fields in zrtp_session_ctx and zrtp_stream_ctx.\n + zrtp_stream_t and zrtp_session_t structures were hidden inside libzrtp internal data-types. General libzrtp-based application shouldn't use these structures directly. zrtp_stream_info_t and zrtp_session_info_t structures should be used instead. To implement data encapsulation, libzrtp provides following functions: + zrtp_stream_get(), zrtp_session_get()\n + zrtp_stream_set_userdata(), zrtp_stream_get_userdata()\n + zrtp_session_set_userdata(), zrtp_session_get_userdata()\n + \n + Advanced zrtp products may access zrtp_stream_t and zrtp_session_t directly but implementer can avoid this in most of the cases. + + *- [LZRTP-88] Create a macro for UNALIGNED constructions on mobile platforms.\n + + *- [LZRTP-89] Code style for crypto components sources.\n + Public API not affected. Internal changes: + - more compact code because fo using more general crypto functions + - code stayle and comments + - test-vectors were moved inside c-files fof appropriate crypto components. + + *- [LZRTP-99] zrtp_session_init should allocate memory for zrtp_session_t.\n + + *- [LZRTP-112] Modify zrtp logger to be able write \\n and NON \\n logs.\n + ZRTP_LOG by default doesn't add \\n at the end of the log string. ZRTP_LOGC print plain log message without header and any formatting. + + *- [LZRTP-116] Review synchronization objects in libzrtp.\n + - zrtp_global_t#comp_protector was removed. This mutex protected crypto components list. Since v0.80 libzrtp doesn't allow users to manage list of crypto components. libzrtp loads all available components at zrtp_init() and destroys them on zrtp_down(). Any modification with the list performed between these two call - don't need mutex. + - zrtp_secrets_t#protector was removed, just unused in the code + - zrtp_global_t#cache_protector was removed. Third-party ZRTP cache implementation should be thread-safe. It was made because it is simpler and more flexible solution. + + *- [LZRTP-120] Add file with version number to identify builds.\n + zrtp_version.h have been added to the project. + + *- [LZRTP-128] Eliminate Sound event from libzrtp.\n + zrtp_callback_misc_t::on_sound_event() was eliminated. This message was originally deigned for early versions of ZFone project. Event is supernumerary and duplicated other protocol and security events. Users, who need such event may perform the same actions using zrtp_callback_event_t events. + + *- [LZRTP-133] Move ssrc parameter from stream_create() to stream_start()\n + SSRC parameter was moved from zrtp_stream_attach() to zrtp_stream_start(). Such improvement should allow users to create zrtp streams before media starts and ssrc is unknown. It may be useful for proxy products: ZFone, UM-Lab software and other. + + *- [LZRTP-143] Speedup DH key exchange procedure.\n + DH crypto context data was moved directly to zrtp_stream_t and statically allocated. On creating protocol routine, libzrtp checks is DH context have been already initialized with the same type of key exchange scheme. If so - new DH value will not be recalculated. + +***\subsection v080_feature New Feature + - [LZRTP-14] Add DH2K public key exchange scheme\n + DH2K public key exchange scheme was implemented and available for developers the same way as rest of crypto components. + +***\subsection v080_tasks Task + *- [LZRTP-24] Implement Self-tests for DH and ECDH components.\n + Test cases for DH components were implemented and added to the libzrtp test-unite routine. DH checks algorithm correctness and performance as well. Besides test-vectors, it emulates DH exchange computing public and secret values for both endpoints. + + *- [LZRTP-122] Print out all zrtp configuration settings and adjustments on initialization. + + *- [LZRTP-123] Create standard error codes and error text descriptions.\n + New functions zrtp_log_error2str() and zrtp_log_status2str() were added to convert status codes to text description. Some clean-up in zrtp_status_t was made, removed unused or ambiguous status codes. + + *- [LZRTP-132] Replace HMAC with KDF function call.\n + Since ZRTP draft 12b defines ZRTP KDF to be in compliance with the recommendations in NIST SP 800-108. KDF function implemented as _zrtp_kdf() in zrtp_utils_proto.c. All KDF operations were replaced with from hmac to kdf function. +*/ diff --git a/doc/manuals/howto.dox b/doc/manuals/howto.dox new file mode 100644 index 0000000000..8792b6bed7 --- /dev/null +++ b/doc/manuals/howto.dox @@ -0,0 +1,489 @@ +# +# 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 + + +/** + * \file howto.dox + * \brief How to Get Up and Running Quickly with libZRTP + */ + +/** +\page howto How to Get Up and Running Quickly with libZRTP + +**************************************************************************************************** +\section howto_about 1. About +**************************************************************************************************** +
+The libzrtp library is a cross-platform implementation of ZRTP, a VoIP encryption protocol developed by Phil Zimmermann. libzrtp is suitable for inclusion in software VoIP clients, firmware for hardware VoIP phones, VoIP PBX servers, mobile VoIP clients, and SIP border control servers, enabling a VoIP application to interoperate and make secure calls with the rest of the ZRTP +community. + +The libzrtp library consists of three main components: the protocol module responsible for the safe connection of a call, the encryption module, and a set of interfaces. ZRTP works by assuming control of the VoIP traffic and initiating an encrypted connection between two ZRTP endpoints after a safe mode is achieved. To integrate the library, please review our documentation on the +ZRTP interfaces, connections management, and integration plan. + + +**************************************************************************************************** +\section howto_quick 2. Quick Info +**************************************************************************************************** +
+ ***

Building with GNU tools (Linux, *BSD, MacOS X, mingw, etc.)

+ + Generally these should be all that are needed to build the libraries, applications, and samples: + -# go to ./projects/gnu and run +\code +$ ./configure +$ make clean && make +\endcode + + **

Building Win32 Target with Microsoft Visual Studio

+ Generally we can just do these steps: + -# Visual Studio 8: open projects/win/libzrtp_vc8.sln solution, + -# build the libzrtp_test application. + + **

Building for Windows Mobile

+ Generally these are all that are needed: + -# Visual Studio 8: open projects/win/libzrtp_wince_vc8.sln solution, + -# build the libzrtp_test application. + + **

Locating Output Binaries/Libraries

+ For GNU targets, library files will be placed to ./projects/gnu/build and ./third_party/bnlib. + + **

Running the Applications

+ After successful build, you can try running libzrtp_test application on projects/gnu/build/test directory. + +**************************************************************************************************** +\section howto_getting_source 3. Getting the Source Distribution +**************************************************************************************************** +
+***\subsection howto_getting_source_tar 3.1 Getting the Release tarball + + Getting the released tarball is the best way to obtain stable version of libzrtp. The tarball may not contain the latest features or bug-fixes, but normally it is considered more stable, tested and well documented. + + The latest released tarball can be downloaded from the http://zfoneproject.com/prod_sdk.html + +***\subsection howto_getting_source_svn 3.2 Getting from Subversion trunk + At the moment, SVN repository is available for libzrtp developers only. It will be opened for public soon. + +***\subsection howto_getting_source_layout 3.3 Source Directories Layout + + The top-level directories (denoted as $TOP here) in the source distribution contains the following sub-directories: + + \c $TOP/doc - documentation folder; + + \c $TOP/include - header files: + - \c zrtp_config_user.h - user defined ZRTP configuration options; + - \c zrtp_config_win.h - Windows related configuration options; + - \c zrtp_config.h - libzrtp automatic configuration routine. + - \c zrtp_crypto.h - contains definitions of the data types and functions necessary to + strengthen the crypto-segment of the library. These functions are used only by libzrtp + developers only. Typical projects based on libzrtp do not use these functions; + - \c zrtp_engine.h - contains types and functions needed by the ZRTP state-machine For + internal use only; + - \c zrtp_error.h - contains error codes returned by the libzrtp functions; + - \c zrtp_iface_system.h - contains a set of OS-related interface functions which must be + implemented in order to use the library; + - \c zrtp_iface.h - contains a set of ZRTP utility interface functions which must be + implemented in order to use the library; + - \c zrtp_legal.h - libzrtp license agreement; + - \c zrtp_list.h - contains functions and macros for safe operations with linked lists. All + lists in libzrtp are based on these functions. They can be used to avoid mistakes in list operations; + - \c zrtp_log.h - contains functions to track bugs and store the error log.; + - \c zrtp_pbx.h - conatins declarations of the main PBX related functions. Use this header if you are the implementor of some VoIP-server solutions; + - \c zrtp_srtp.h - SRTP crypto types and interfaces. Used to integrate libzrtp with third + party SRTP implementations; + - \c zrtp_srtp_builtin.h - data structures for built-in realization of SRTP. + - \c zrtp_string.h - contains functions for the use of the special, safe strings, + zrtp_stringn_t, used by libzrtp. + - \c zrtp_types.h - contains the definitions of the internal data types which are used by + libzrtp developers and experienced users. + - \c zrtp.h - conatins declarations of the main dataypes and function + functions necessary to operate libzrtp. This file header is only must to + be included in each module using the libzrt functions; + + \c $TOP/projects + - \c gnu - make files for Unix-like systems using autotools; + - \c symbian - configuration and make files for Symbian platform; + - \c win - Set of Microsoft Visual Studio project files for Windows and Windows CE. + - \c win_kernel - makefiles for Windows Kernel mode. + - \c xcode - project files for Apple Xcode. + + \c $TOP/src - libzrtp source files;\n + + \c $TOP/test - test suite for libZRTP kernel logic. Includes versions for Unix, Windows, + Windows CE and Symbian. + + \c $TOP/third_party + - \c bnlib - libbn files which are not intended for external use; + - \c bgaes - AES encryption library and hash functions by Brian Gladman; + + +**************************************************************************************************** +\section howto_praparations 4. Build Preparation +**************************************************************************************************** +
+***\subsection howto_praparations_config 4.1 zrtp_cinfig_user.h + + Before building libzrtp, some adjustments may be performed according to developers needs. In order to do this, \c include/zrtp_cinfig_user.h should be used. Most of configuration parameters are optional and libzrtp can be build without any modifications. + + Check \ref zrtp_config for more information. + +***\subsection howto_praparations_iface 4.2 libzrtp platform-dependent interfaces + + The library requires external implementation of some system-dependent functions to enable cross-platform operation. The libzrtp distribution contains almost all interface implementations for the following platforms: Windows, Linux, Mac OSX, Symbian, Windows CE. The Quick Start allows a fast integration of the library. Built-in implementations are used by default and developer don't need to anything more. + + In order to start using libzrtp, developer should implement just few feedback interfaces. Libzrtp uses callbacks to notify application about some events in ZRTP protocol, such as: + - zrtp_callback_event_t#on_zrtp_secure - notify user about switching to secure; + - zrtp_callback_event_t#on_zrtp_not_secure - notify about ZRTP security issues. + + Another callback which must be implemented - transport routine: + - zrtp_callback_misc_t#on_send_packet - libzrtp uses this function to deliver ZRTP protocol message to the remote party. + + These only two callbacks which must be implemented to start using libzrtp. Example can be found at the end of this article. + + For more detail information about libzrtp platform-dependent interfaces check \ref XXX. + +**************************************************************************************************** +\section howto_unix 5. Building Linux, *nix, *BSD, and MacOS X Targets with GNU Build Systems +**************************************************************************************************** +
+***\subsection howto_unix_targets Supported Targets + + The new, autoconf based GNU build system can be used to build the libraries/applications for the following targets: + - Linux (i386, Opteron, Itanium, MIPS, PowerPC, etc.), + - MacOS X (Intel, PowerPC), + - mingw (i386), + - FreeBSD (i386, Opteron, etc.), + - etc. + +***\subsection howto_unix_requir 5.1 Requirements + + In order to use libzrtp's GNU build system, these typical GNU tools are needed: + - GNU make, + - GNU binutils for the target, and + - GNU gcc for the target. + + In addition, the appropriate libraries must be installed for platform-dependent interfaces implementation. This could just be a libc and the appropriate system abstraction library such as Posix. + + The build system is known to work on the following hosts: + - Linux, many types of distributions. + - MacOS X 10.4 and higher + +***\subsection howto_unix_build 5.2 Running configure and make + + Run "./configure" without any options to let the script detect the appropriate settings for the host: +\code + $ cd libzrtp + $ ./configure + ... +\endcode + + Once the configure script completes successfully, libzrtp is ready to be built. Use following commands: +\code + $ cd libzrtp + $ make clean + $ make +\endcode + + Description of all make targets supported by the Makefile's: + - \c all. The default (or first) target to build the library binary; + - \c clean. Clean the object files and libzrtp binary; + - \c check. Build test cases and start libzrtp_test application; + - \c distclean. Remove all generated files (object, libraries, binaries, and + dependency files). + - \c install. Make install of libzrtp headers and binaries; + - \c uninstall. Remove installed headers and binaries. + +**************************************************************************************************** +\section howto_osx 6. Building MacOS X Targets with Xcode +**************************************************************************************************** +
+***\subsection howto_osx_requir 6.1 Requirements + + To build libzrtp on OS X using Xcode you need following: + - Mac OSX 10.4 or later. + - Apple developers Tools installed. + - Xcode 3.1 or higher. + +***\subsection howto_osx_build 6.2 Building the Projects + + Follow the steps below to build libzrtp using Apple Xcode: + -# For Apple Xcode: open \c projects/xcode/libzrtp.xcodeproj project file. + -# Set "libzrtp" or "libzrtp_ec" as Active Target. + -# Select Debug or Release build as appropriate. + -# Build "configure" target. + -# Build the project. This will build libzrtp with all dependencies. + -# After successful build, libzrtp will be placed in \c projects/xcode/build/Debug or Release. + + Use \c projects/xcode/libzrtp_test.xcodeproj by analogy to build the test application. + +**************************************************************************************************** +\section howto_win 7. Building for Windows Targets with Microsoft Visual Studio +**************************************************************************************************** +
+***\subsection howto_win_requir 7.1 Requirements + + The Microsoft Visual Studio based project files can be used with one of the following: + - Microsoft Visual C++ 2005 (including Express edition), + + For the host platform, the following are required: + - Windows NT, 2000, XP, 2003, or later , + - Sufficient amount of RAM for the build process (at least 256MB). + +***\subsection howto_win_build 7.2 Building the Projects + + Follow the steps below to build libzrtp using Visual Studio: + -# For Visual Studio 8 (VS 2005): open libzrtp_vs8.sln solution file. + -# Set "libzrtp" or "libzrtp_ec" as StartUp Project. + -# Select Debug or Release build as appropriate. + -# Build the project. This will build libzrtp and all dependencies. + -# After successful build, libzrtp will be placed in \c projects/win/Debug or Release. + + To build libzrtp test-cases use "libzrtp_test" as StartUp Project and perform steps listed above. + +**************************************************************************************************** +\section howto_wince 8. Building for Windows Mobile Targets (Windows CE/WinCE/PDA/SmartPhone) +**************************************************************************************************** +
+***\subsection howto_wince_requir 8.1 Requirements + + The Microsoft Visual Studio based project files can be used with one of the following: + - Microsoft Visual C++ 2005 + + For the host platform, the following are required: + - Windows NT, 2000, XP, 2003, or later , + - Sufficient amount of RAM for the build process (at least 256MB). + +***\subsection howto_wince_build 8.2 Building the Projects + + Follow the steps below to build libzrtp using Visual Studio: + -# For Visual Studio 8 (VS 2005): open libzrtp_wince_vs8.sln solution file. + -# Set "libzrtp" or "libzrtp_ec" as StartUp Project. + -# Select Debug or Release build as appropriate. + -# Build the project. This will build libzrtp and all dependencies. + -# After successful build, libzrtp will be placed in \c projects/win/Debug or Release. + +\note + The Test Application is not available for Windows Mobile platform at the moment. We will fix this in next version of libzrtp. + +**************************************************************************************************** +\section howto_symbian 9. Building for Symbian +**************************************************************************************************** +
+ +**************************************************************************************************** +\section howto_using 10. Using libzrtp with Applications +**************************************************************************************************** +
+ Regardless of the build system being used, the following tasks are normally needed to be done in order to build application to use libzrtp: + -# Add following include directories in the include search path: + - \c libzrtp/include + - \c libzrtp/include/enterprise (if you are using Enterprise version of libzrtp) + - \c libzrtp/third_party/bgaes + - \c libzrtp/third_party/bnlib + - \c libzrtp/projects/gnu/config (for GNU Autoconf targets) + -# Put these library directories in the library search path: + - \c libzrtp/third_party/bnlib + - \c libzrtp/projects/gnu/build (for GNU Autoconf targets) + - \c libzrtp/projects/xcode/build/Release (when building with Xcode) + - \c libzrtp/projects/win/Release (when building with Visual Studio) + -# Include \c libzrtp.h header file to the application. + -# Link with \c libzrtp and \c bnlib. + -# Link with system spesific libraries: + - Windows: Add (among other things): ws2_32.lib. + - Linux, *nix, *BSD: Add (among other things): '-lpthread'. + - MacOS X: Add (among other things): '-lpthread'. + +**************************************************************************************************** +\section howto_example 11. Quick Start Example +**************************************************************************************************** +
+ +An overview for creating an encrypted channel using libzrtp: + +*** \subsection howto_example_init 11.1 Initialization + + The library supports profiling and dictating different channel parameters, though the initialization can be performed by one function call with default parameters. + +\code +typedef struct testcon_t +{ + zrtp_session_t *zrtp_session; // ZRTP Session structure + zrtp_stream_t *zrtp_audio; // ZRTP stream for voice encryption + zrtp_stream__t *zrtp_video; // ZRTP stream for video encryption +} testcon_t; + +testcon_t safe_connection; // Secure channel instance +zrtp_global_t zrtp_global; // Persistent storage for libzrtp data +\endcode + +\code +zrtp_status_t s = zrtp_status_ok; +zrtp_config_t zrtp_config; + +// Initialize zrtp config with default values +zrtp_config_defaults(&zrtp_config); + +// Make some adjustments: +// - Set Client ID to identify ourself +// - Set appropriate license mode +// - We going to use default zrtp cache implementation, so let's specify cache file path +strcpy(zrtp_config.client_id, TEST_CLIENT_ID); +zrtp_config.lic_mode = ZRTP_LICENSE_MODE_ACTIVE; +zrtp_zstrcpyc( ZSTR_GV(zrtp_config.def_cache_path), TEST_CACHE_PATH); + +// Define interface callback functions +zrtp_config.cb.misc_cb.on_send_packet = on_send_packet; +zrtp_config.cb.event_cb.on_zrtp_secure = on_zrtp_secure; +zrtp_config.cb.event_cb.on_zrtp_security_event = on_zrtp_event; + +// Everything is ready - initialize libzrtp. +s = zrtp_init(&zrtp_config, &zrtp_global); +if (zrtp_status_ok != s) { + // Check error code and debug logs +} + +// The library has been initialized and is ready to use +. . . +\endcode + +*** \subsection howto_example_sessions 11.2 Sessions/Streams + + The library operates with the ZRTP streams concept, where each packet is encrypted within this stream. The streams are created before the start of the encryption process. + +\code +// +// Allocate zrtp session with default parameters +// +z = zrtp_session_init( zrtp_global, + NULL, + zid, + is_initator, + &safe_connection->zrtp_session); +if (zrtp_status_ok != s) { + // Check error code and debug logs +} + +// Set call-back pointer to our parent structure +zrtp_session_set_userdata(safe_connection->zrtp_session, &safe_connection); + +// +// Attach Audio and Video Streams +// +s = zrtp_stream_attach(safe_connection->zrtp_session, &safe_connection->zrtp_audio); +if (zrtp_status_ok != s) { + // Check error code and debug logs +} +zrtp_stream_set_userdata(safe_connection->zrtp_audio, &safe_connection); + +s = zrtp_stream_attach(safe_connection->zrtp_session, &safe_connection->zrtp_video); +if (zrtp_status_ok != s) { + // Check error code and debug logs +} +zrtp_stream_set_userdata(safe_connection->zrtp_video, &safe_connection); +\endcode + + +*** \subsection howto_example_protocol 11.3 Protocol Handling + + To create an encrypted channel, run the ZRTP engine for each stream added to the session. In our case we have two streams. The library will notify when achieving safe mode through the feedback path interface. + +\code +// +// Streams are ready - initiate ZRTP protocol +// +zrtp_stream_start(safe_connection->zrtp_audio, assrc); +zrtp_stream_start(safe_connection->zrtp_video, vssrc); +\endcode + +The three steps above create the encrypted channel. After entering the "Secure" state, you provide a plain packet to the library and receive an encrypted packet ready to be sent. Decryption works in the analogous way. + +\code +zrtp_status_t s = zrtp_status_fail; +char packet[MAX_RTP_SIZE]; +int size = 0; + +// Some abstract function for packets receiving +size = get_packet(packet); + + // + // Processing incoming packets. + // You must determine media type and choose corresponding ZRTP stream + // +s = zrtp_process_srtp(safe_connection->zrtp_audio, packet, &size); +switch (s) { + case zrtp_status_ok: + // + // Packet was successfully decrypted. Dont forget that packet + // size was changed during decryption. New size now in size + // + + case zrtp_status_drop: + // + // This is a protocol ZRTP packet or masked RTP media. + // In either case the packet must be dropped to protect your + // private data and media codec + + case zrtp_status_fail: + // + // This is some kind of error - see logs for more information. + // Don't put such packet to the network. It is not secure. + // +} +\endcode + +*** \subsection howto_example_callbacks 11.4 Callbacks + + libzrtp informs the user application about all changes in protocol state through a system of callback functions. The developer's guide considers this question in detail in \ref XXX. In most cases we need to display the SAS string and some other stream options after switching to the Secure state. An example of doing this is follow: + +\code +static void on_zrtp_secure(zrtp_stream_t *stream, unsigned event) +{ + test_options_t* info; // some user-defined stream options + + switch (event) { + case ZRTP_EVENT_IS_SECURE: + { + safe_connection_t* safe_connection = zrtp_stream_get_userdata(stream); + zrtp_session_info_t zrtp_session_info; + + zrtp_session_get(safe_connection->zrtp_session, &zrtp_session_info); + // + // Print out SAS there. + // + } break; + + // ... + // handle other events there + + default: + break; + } +} +\endcode + +An overview for closing an secure channel using libzrtp: + +*** \subsection howto_example_utilization 11.5 Utilization + + The uninstall session permits libzrtp to dispose of all engaged resources and release memory for session context storage. ZRTP streams will be also released, so you don't need to call separate functions. + +\code +zrtp_session_down(safe_connection->zrtp_session); +\endcode + + When you no longer need the library, dispose of all resources allocated before the beginning of the operation. + +\code +zrtp_down(&zrtp_global); +\endcode + +**************************************************************************************************** +\section howto_summary 12. Summary +**************************************************************************************************** +
+Integration of libzrtp requires familiarity with the protocol and the library operation features. While the encryption of VoIP is not a trivial task, we have attempted to simplify as much as possible the work required to integrate libzrtp. + +*/ diff --git a/doc/manuals/main.dox b/doc/manuals/main.dox new file mode 100644 index 0000000000..e36cffd489 --- /dev/null +++ b/doc/manuals/main.dox @@ -0,0 +1,38 @@ +# +# 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 + +/** +\mainpage ZRTP VoIP security + +**************************************************************************************************** +\section intro Intro +**************************************************************************************************** + + ZRTP Protocol finally goes RFC and we going to stabilize SDK as well. Libzrtp series 0.9X builds + will contain bug-fixes, performance and stability improvements only. + + So, please, be a patient with new API changes. We hope you will find them useful. + +**************************************************************************************************** +\section aboutdoc About this Documentation +**************************************************************************************************** + + Libzrtp, since v0.80 includes new, documentation. We have updated "How to Get Up and Running Quickly with libZRTP" and Public API documentation. + + We working on new "Libzrtp Developers Guide" which will give more detail information about ZRTP protocol and libzrtp architecture. This document will be available in next versions of libzrtp. But even now, libzrtp contains enough documentation to start using it comfortable. + + \note + libzrtp private API may have outdated information from previous version (links like this: \ref XXX). We working hard on that part of the documentation and it will be published in next versions of libzrtp. + +**************************************************************************************************** +\section zrtp Libzrtp Documents +**************************************************************************************************** +-# \ref changelog +-# \ref howto +-# \ref rng + +*/ diff --git a/doc/manuals/rng.dox b/doc/manuals/rng.dox new file mode 100644 index 0000000000..60d10646cc --- /dev/null +++ b/doc/manuals/rng.dox @@ -0,0 +1,74 @@ +# +# 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 + + +/** + * \file rng.dox + * \brief Random Number Generation in libzrtp + */ + +/** +\page rng Random Number Generation in libzrtp + +\section rng Random number generation + + The generation of cryptographic key material is a highly sensitive process. To do this, you need high entropy random numbers that an attacker cannot predict. This section discusses the random number generator used by libzrtp, and how suitable entropy can be collected on different hardware platforms. + + Failure to use true entropy from the physical environment as a basis for generating random cryptographic key material would lead to a disastrous loss of security. + +**************************************************************************************************** +\subsection rng_algorithm Deterministic Random Bit Generator +**************************************************************************************************** +
+ Libzrtp uses a cryptographically strong Deterministic Random Bit Generator (DRBG), based on running the AES-256 block cipher in counter mode. The output of this DRBG is used for key material by libzrtp for the Diffie-Hellman private keys, and other random protocol components such as nonces. The 256-bit AES key and 128-bit initialization vector for the DRBG are drawn from an entropy pool + created by a SHA-512 hash of raw entropy sources. These raw entropy sources are highly platform dependent and thus are not included in libzrtp. The library provides only a set of interfaces for adding the entropy to the entropy pool. We will discuss the entropy collection in the next section. + + When a random number is required by the ZRTP protocol, the library kernel calls the Deterministic Random Bit Generator interface function zrtp_randstr(). That function requires the existance of an entropy pool that has already been seeded with sufficient entropy. This entropy pool must be seeded by calling zrtp_entropy_add(). + + The zrtp_entropy_add() function takes a buffer of raw unprocessed entropy provided by the caller and adds it to the entropy pool via the SHA-512 hash function. + +**************************************************************************************************** +\subsection rng_accumulation Entropy accumulation +**************************************************************************************************** +
+ Random numbers for cryptographic key material must be derived from a physical entropy source, such as RF noise, acoustic noise, thermal noise, high resolution timings of environmental events, or other unpredictable physical sources of entropy. For a detailed explanation of cryptographic grade random numbers and guidance for collecting suitable entropy, see RFC 4086 and Chapter 10 of "Practical Cryptography" by Ferguson and Schneier. The raw entropy must be distilled and processed through a Deterministic Random Bit Generator (DRBG). We supply a suitable DRBG in libzrtp, which is accessed through the zrtp_randstr() function. + + To add entropy to the entropy pool maintained by the libzrtp random number generator, the application calls the zrtp_entropy_add() function. This entropy accumulation function may be called whenever new entropy becomes available. + + \warning + The entropy pool builds up more precious entropy each time you call zrtp_entropy_add(). Once in a while, it is a good idea to save the entropy in nonvolatile storage, by calling zrtp_randstr() and writing the output to a file, or to flash memory, or to some nonvolatile system storage area. This can be done whenever the VoIP application shuts down, or perhaps at the end of each secure VoIP call. A minimum of 512 bits (64 bytes) of output from zrtp_randstr() should be stored this way, but there is no need to store more than 256 bytes. When the VoIP application starts back up again, the contents of this nonvolatile entropy file should be added back into the active entropy pool by passing it to the zrtp_entropy_add() function. + +**************************************************************************************************** +\subsection rng_default Libzrtp built-in entropy sources +**************************************************************************************************** +
+ The SDK library provides a default implementation of entropy accumulation for Windows Kernel and Unix based platforms. + + For the Windows kernel mode it gathers current system state information as an entropy source. Among them are the performance counter, the current value of the system interrupt-time count, the count of the interval timer interrupts, and the values of some CPU registers. + + For Unix platforms, libzrtp calls \c /dev/urandom. + + If you are running libzrtp on a Windows Kernel or a full-blown desktop *nix-like system - you need not do anything more to implement the RNG. If you are using some other platform - carefully read the next section. + +**************************************************************************************************** +\subsection rng_guidelines Entropy sources for your platform. +**************************************************************************************************** +
+ On a desktop or laptop PC running Linux, FreeBSD, NetBSD, or OpenBSD, a good source of entropy may be found by reading from \c /dev/random or \c /dev/urandom. This is because \c /dev/random is seeded by entropy from keyboard timings, mouse movements, disk latency measurements, or other physical noise sources, some of them involving unpredictable human interaction. + + However, some low cost embedded Linux systems have no keyboard, no mouse or trackpad, no disk drive, and are starving for high quality entropy. There are some low cost Asterisk PBX boxes that are built this way. Or hardware Analog Telephone Adapters. Or low cost consumer routers. Many of them have no \c /dev/random implemented, or worse, have only a stub for /dev/random that does not actually collect any environmental entropy. This creates a dangerous illusion that entropy is available, because \c /dev/urandom appears to work, but is not backed by true entropy. This is bad, and not only for ZRTP. Platforms like these might not be able to generate strong cryptographic key material for SSH or SSL. + + If you are an OEM that builds hardware like this, and you wish to implement the ZRTP protocol with our libzrtp SDK, you really should provide a properly implemented \c /dev/random and \c /dev/urandom, properly supplied with true environmental entropy. If you are building a telephone, you can easily collect entropy from raw audio samples from the microphone. If the phone includes a video camera, you can collect entropy by sampling a few raw uncompressed video frames. If it's a mobile phone or a cordless phone, you can collect entropy from the RF noise in your wireless circuitry. If it's an embedded box like a router or low cost PBX, you can do high resolution timings of packet arrivals and use the timer readings as entropy sources. A PBX might include an analog interface to PSTN phone lines, and those interfaces usually include registers that measure analog voltage levels, which can serve as a source of entropy. The entropy sources do not need to produce much entropy, just a few bits at a time, but it can build up slowly until you have accumulated a few hundred bits of entropy. That's enough to generate cryptographically useful keys. Even if it takes some seconds or even minutes to accumulate this much entropy the first time your product is activated, it can be stored in nonvolatile storage so that it will be ready to reseed the entropy pool instantly the next time your product is powered up. + + In the ideal case, if you are designing the embedded hardware yourself, you could provide a good source of entropy by including a simple ring oscillator in the hardware. A ring oscillator is a circular chain (a ring) of NOT gates, and has nothing whatsoever to do with a telephone ring generator. The oscillation frequency drifts from thermal noise, and sampling the output at some low sampling rate is a good way to get some entropy. However, most designers have to work with existing hardware designs, and don't have the luxury of adding special hardware to generate entropy, which means you have to improvise with whatever you can collect from the environment, using any of the methods described above. + + If the library is used on another platform, the potential entropy sources should be thoroughly analyzed and a custom implementation must be developed for that platform. You can get your entropy collection ideas by looking at the default implementation of \c zrtp_add_system_state() provided in \c zrtp_rng.c. Again, microphone noise can be a good entropy source for VoIP clients. Raw, uncompressed, unfiltered audio samples should be used. + + If you have entropy gathering schemes for platforms not already supported in libzrtp, or if you doubt the correctness of your entropy collection approach, contact us to discuss how it may be done. We will do our best to provide you with technical assistance. + +*/ diff --git a/doc/out/html/zfone.jpg b/doc/out/html/zfone.jpg new file mode 100644 index 0000000000000000000000000000000000000000..739e3a45454ccfb8706a2bd80db6d04c448f1c42 GIT binary patch literal 8517 zcmb_=2UJwc(r!;C=Oj@iOOhy2M6!S&DkvaBkR*~pP{Jr8NpcVc1d)tHNs1hDP!Lg~ zfRZIhaF8^}F!OKDIrrYT{{P+e?tAOi%&h%Q@9OUQs=9Y|ZSoiL3}85~YoH5YFc{E> zK7c$&&tagYg*7!Z(KRsAfo=dmPhscfbqfvvaQE=@G1EJD{OUE!{t#KDYnWg(ijd1Mq+P{}<=Kdmy0T90iyGC;>mv4wHpVz-tlB z$ZfPY1q0WI($k555<@Xi8 zD%GllsA;QjYvgF^og3D^tW%}vIz+*+J+|Yr zv%ed=$G2Ba&?b!Ud;UiKes-XAFhcY_WIk*lS&;!5MIFuKVw!4zW{_@$5ygCrRhXUo7@Bj5dx*F0c;1N=!Ej*@QQMOS5(-kx(yKB}a$yQ; zipxrgDq^bj>RM;&&T?v6pL?$LP3M^IWxa>`bp~^WG)A($dCDHv6^=cEa{b4*EB)INCeibPjaExyIZ~b<4R`;$G*`eI#2x;-Y(X@^s1Oix5W0^$xOaG;`~ZZ*9)gFY2vQV?M#s=T zVu|IA6N{HmIFqQ8WSnfCVwq}_X8RbMZvDjkscD93rg4_xGyQC>9JS|ixneK4^Jw#k z`Ktxvg>6N}#R(<1OD$fil<|}!%eO0*DkrNxR=2#WtjVg4s`IVC-k|sT)EkaBCn&&o$0_FNiM8 zd{17~S=?JHST*-%#xB@x z+6y3@A}sA^{5Jf3a8N=tKZG5YlPpN&zvE8}q<}5R1)DGrI12tAQH|_I9bjxICaBzK zC}~UR&oeAA`7`gchOuKf9&xg974WF=b{@aLKOx{CxFl>ZGA?FtvQmOl(q5`mdR^v} z>~*;i`6z`%#njX3O6kfeDzU2f)o!c1oUzc*J}afks!2RItJR}jsuQQ{t#?V^z(C`? ztf8>cF=I+&!iDc9gQm?FOU=?Q;V$30VqvarA$OJk8vQl0<%(6Ob=vhCHZoX%9k9)@ z^RQQUpmmtKQQ>&c>9Vt^Gtp(pwfttJ8}^ohJHox+BgNC&OW146yUi!T7waeONAmBx z{W!ojP%LocPW4^iAgQ3`;Jgs0(2F?Ld&2h_?(c?;KWGfkcz8R)G*T=IM2$tij0t^Y z7Aq9H7xz9sJHao}GU;5hSPFg0cIub3w~w>ZgP&Y~dM1NE6PdZ3)&HzE`&mxpbH7~s z7w7YY@^+oeG$0$k zysmwd)adortm*V0yv>;A&6dg5uD0^_#~mS^_FcN&B0cDyrFY}+dwbjaYCe?oKl_+C z5cVnH^UXo)p$o$rBQm4>V@zL=U$)2RCx$0`zRpacr%%mT&nC?EEiiv~S?pcbTNz#r zU03_bzDd8uy`#Msx&M`@K}tE=|9|DaqnvBZ#0$V)J_P^BA2PrUcz`Hq1vP+=U;*sI=wJdcC73bH0Tu{LfEB=+V8gIA zI2z6eSAmYFyp;Bo#gv;=+EnROtJGT58PwY} zrZknbbhO^IqjYL?`SkSk!St&P*BL%D>M}MlDKJ$sOE8zRh_bw7J<0l#O^U6KU7fv$ z;|j;pvAdj%oG-cbxt6$Nc%*oSc|-X``38^U_@(*3oro7O5Tp_OEc6sw^Wq|VqFrLC zC+)>$CEyanlKE1;(mJPDPc6vQ$UcxWmlu=YSNNd#;&gzLiL!t)QDsE6O6`&Q%`-+C zGH1CpF`B>5t!PbYkLyh6e$!jj-!a%Xq%dMO7P_EhVrJ@dG1;u?(()B9b5n~)R|hOv zt*ospY+%?+wz+om4kvGTJGMA8xVX4>xry9*47$T>lD;@>LX(rGl4kSNKwSLT zUa{3$*Vn&!*|gp&)?wEj`M%^s=fK3^$_Qzk`78Z2#T?Cd+GW;Nwhg9D%+~7e`~4K6 z&7b*00a$_{@C3X9yylJ8TlR4X1;P!FAyd@Gy8Tyd6G| zKq7<@=b_jqA?gql2r^O#X@vAcW+6L~8z>Hx7Rm#aiF%JBpheNw(2vk9=xvNR<_0Dk zGfu%qVNUUcVgic0GvzBPIF%Ju4K+QrJM{+|Nt$GueOi0kk5JUh>G|o?85kJi7^xW_ zG0`!lFmo~&ut>4IWj)K_>i=tv;2(hV?Z^Y9id?hbRNlDX4ubz4*Qy?2I=Ok~SAgy@p zG~)Dz(wK6KN~vn9TBy3~8FLN2v#OfX=LEF)wRv=Sb%pe#^wkZF&YK&$7zG%|UdS_P zHJvd-UXr|QbtTrk#e#TE-SVDQ_jPs~M{I-bK9masZ@h7WIiGjQaNTgzxs~Hi^tAG7 z^AYw<^xMDf6!7_u=H0i!Mj>ms$orCEgW(|&B9Vj9_a8~ePRA!Eo=e(JDNZv_r+PAy zQI-{xZS`F41$Ew!g3h9%lK7YR%7ZF{t7B@i>pB~LHVQPEH$Q7#>^Rp|@Q%GVy$WfM9_$wqZU2nFDsTkRpcK3Vi!eBh z7mB?(%ommjtAO>x)}gq|z^}lA;Cb*q_%?zMVTcGoC>`_lq zgJ@c`0Xh=hgQ3J+z&yrGQHWCnQS?(Dr@Tw~g-VmEoSKI^kp@MBqao6U(!uFs=-KEC z8B`bs8QqzvnaY^Wmv&W11 zy-z3$&rvgwJ7ShK=Q_$!*`sTM!4nOIg@ zvs@3g`EF}ymu|mwL)kIG>4%HHYndDKt-J2?o`zoaK778>e)!v01Dc>SOlt7SkP%$K z{o`R>;Ws0wBJ-owV?M>&#;qp=C6be4Qt8tY(m9^AXFSN#dv=ghk!zDjnO|LKUUX3M z{H1=`PDOr|#VdxIfx0IRH{Q@RzHYkKOxaS^X4ApY+0pIy?&SOVzUTed2Y5cs4!#(6 z8I>O+j(1ENeC?Q0p01h|n2VeL`Q2bKV`+AU?}yQ<*INAgvyGykrTE;<)L%hccH5de zd^oyYdeVT!AsL0}g-HX;3RbGXRj~c7$4nl88sw|5f}P1ECrY04-0i zJ3g+?E`G-~p(@o;;<$l_gOtQ^*;A*K0eKe0>IAwv0bpzlpvn%K6%9iJC_h5g8e|QO z>2C~`QZP=aGCpbtz#PW)PizAd{g-~ED?t9O1C9Bo=>PryuPgjH{GS@p&k_H`l1IAa zNuUMbFldv(;Be>*2?B*U5;PKtKw;1r3(3_5ZbyTLB{lkOa{P*a-kpk{4Fpz z0*Qhwg6x14>KGvN5ePVBED8xZ0u}<@2S`Q~6Tgfmn)#v~=7cwk?ER!%3W0OgZLDUW z@q%*pK4FwpZ0sDzIE92oM8!_ZD=3~;QdZH@*3s3|H#mRk@)dInsEl^F;ppV-;(F89 z&;NEn;GMeU7!|0MP=UK4-@I>Esi5sW|sOp`%aFRsl|!&Q1*k3^-nDbT6`NCISF8)$fz)UT*0 za&~Z|DM>Ni*<1RjbKM;-zZ(5%Ic|^ERzRO!-ZInJ(tzp|6RPYCIj_F}8|isaYtO-} z$x*#mmOxMn(7+Qs9}zUR(L^$+mM2=o5(0MPKW+a3@16*9H~3!P5HCE=l&Eh?zd1JS z)ot;3G3}(*sm>sA%PHq~n;xDSjx4!qmGtXY-)^6|PX>|8phO?Nbi0)9A>X7L6Y z%)G_bAI8=62W<+NMu-mAs0OO)!p?4(d~u5%s*EqNW0@1n-AYu7H$@by-SaZJx!E$o zH;3IV-~3c7W~k{gy>cOc&SIWQJw0A^X`*>3ia>qxofkd3gi+>!xXGQGnb+7(qv@zE z*06ZClj3uCn=dyz4{6Zjj%f3BwXj*bXi%Tw|3MNO{TV+Q#3R>csovk&bNFPwN64_VB;m4y<>07QSnACNV1kTb(V2O2(41_x~FJyPS7FQQOL04ulcwU*0;vk|~VfB>4K=OIAUyNfU%ip9{s0GoN4_lW)xjTvo=RrdA%gCOG3h^9p3 zr;R4N0_%{NONW`WWI*RqmG3DUt=D@$N~5(o1tDmJ<+7u>_@{-FA(DIg%zBlvrt#!2;(r z!51RZbJ$3d35=Fc2ya#$3pOcjIWc5_S4_F1sD8f3R-bn%W(P}<7$Y*7T)4P`6r)03@({!P1L|({D1JXN-8khRf zP!@bZ_$~7#i(z7p?3P&~XueT~-d{?3N7bB<0`~Vbjt7T8wopS|vWZgotsm12vxKz# zl_aTssUm`VAx9q8!g1)G=7zV85^iR8dXiqmvx|7od*GoT#Haqs0qX%XuI)}JCFv`U z`_k-Q$1>4kc7S2Jth}J2!HwnAk4cudf+j4L^~TSublZ+AD$fv;$N(dbYm+64%~nQu z2Zs=(^Cny@%j@%46JpBCW*Ia?Q<$o!?zpu+F{tAp1BN7n{nTXG*7TYIWa#)|DM>nX ze43(3WRrO=XE);hTmt9v?+Zn4WI!>Mz&=s#+#Dh1FwK+E=%MHMwT#30_=A3&jw)uK zl^74LF~!#q(`X`s+k2C%at16$hI8R4t zb>2((@bI1S|j&%moq!q{gl-fMK45Ukhr^Ar>1XWs{5db>gqUO}AuTl$9u z7UzbJ*9>k`2hP-=je6vB7K(>&%cTwDkO1_+$&Pt*5&7a&yVAJKMV#R78S(hMEPL6# zi1#Z~zMtO~^fqpcE|n5i>YVTkn*=G*g_b8QdI1zCFfW}Crn2`dDaJx+S4nJjDiLp4 z;8V(%-$ti>d2B1IXH%pwg6p_qk}ZD~hle)frb7BWc7hJe8R+A#Vk{+!EQ__aX6qhB zde?eq9BfE^RPu}xYaCz}F_YOlk#e3CFS5kVoU~~{YaWMs7*nJyqO6!zP6qe=G+wqm zoJebqKF}c8Z(Z@`DKCnYSbSRl_{$@ghw?%hc8y6%#Z!_m)$IE6 ztKN0kX~@CLbT!Q=E87zyTNwSP!>1I7f_3l%=FOjW)=xOTu4%4G?NMlYkc$je3s`pB z?wi39d9G|?TbqwH43U%w)a}`-Z|*CSfoq4qaGI}1-ucp3x>m!bmGZFPLS%r1_IlVY zLJEnp|3J-+Goah}T>H0|LGH8kNWB*W-pn3)uMK=pJeYQEC5mq~>_QA5q=zb!K20(H@hOyLMTNfoP|h?i z_x0-`r{t|mf$#X!JRGS6-p#x^(U4o2ft$&};xBr#L4Hv^BfZM2Kyc1q4iy;je<@u3 z`ueSp@7i*F&)EChcPS!`&74{O&#i(`-OsTW%8(P*Atyu< z@<^0#H?7P!1KLBFJ0^BWs34hQ4eNAxGP-8 zu=ZfylT)QDZ`nq?C1~X;od5pdlt^NNHj~Gh4)wE@MbN3_Ma!!kq8eiN#HK|Dw5V1U z8$-sT%4hx<^oJWg?w7w%qitPi5Vt#joEuF8>lWYNf~-k~p5R1pXrj}DO=8ZQxQvqN+{j0hHTp1qoRe)DJ88ZcBB zw~=04S=I=f`XS51a$9dIPlQSoQHUQPa?Kt%1WRrHQBjSb*7;o9kJZcSb0~Gqma1=f zj9H+x3z;2D$X&|5nXo>4AViv+M&X=kO)L-ViB@wVhO_h6tt_V|uM@uBOzIPVe^5R; zXZ|hH)JL!PtipCa7JqxO=6gbIFy-K*`DC>#qL}3~eLaIs(j=;i4&FGofkY*Or@0%fi{B$D>4bO>&1x-gy(Nj}4KMMJt=)Pse(_CH9!OT)xMfwX45#dUh?}{^1pG>?hClI5I#J zf;kS~;9SUnk$8zvGv^uo8yBT^ao4lXYK1c{R?+(~dz9<)uR$v@Zb!*aS#S2EyU}1v znh?IX>rV!`1M?;%+U)_7#l$xTO4CXyO?^Xjm1hQttIOx>tAPSza1%@ z(p^gNx^a?4jP)QINdo_lL$D^Yr)_DN-X&gK&CCWBL)tHo&%FXoukj!-d?2WUhBkZSa2aeC1k-;1$%=s|g zeOp{f!X)O!5aZMAZdSB!vHr(C*;Wy`D77-DON_Bq-7_qtAu{L`X{o6^q{DII@ScUZ zUyTX>!xN^MIj6cgKDz#clgo{`$PGXJy5$>B>qKMDHY6iXrgpp2l>bTzYoG$$C5ufp zI>Q$d$|kO_g?ZMTf5ovFYshu)u53sayOvnhc^$aL(A@+$4EulT90u!FPYY zP0F8Zt7M>+)15=)TFD_+Jg4upN?;|(?(L?;EVd6ARpUc)PmRBveEJ;wjVJknqDKnT zDZwHTpUi-WhgD9t z{10{)|94RUM6HoJY0QcS2azh#Fdw`8TWh?q&et8GQ2v?uXKGsD{Y2!xfv9goZfQ$x zWo(nee4K-B6TywP>D1x9^6>+C^F7{xC;Log3|)+Xm8$otD6_X@#$oq=O1=X-KH163 zFsPtzE*)FHJK)IL_~W*u84=p-Bym=~ z&NO?Ktvj;)*_Y+FPi^5Yg+*_oU>S`P;6HAAs;zPo`=2_1YtWyEN*Ya=Pz{gv^vE7w zp1b-;zqF=0RltEN_|==GoV!1E$RNgsrS|ZdpET`?r8av8@wZ>t@71-@_q*Z=>&Nn$ z?zA{>OhFkU}KuhmI2=q)&8^-GF1srPC{O)?{>5Rgx-N6Aj i6%)?h65BG<+M68WVggFGUV6)g-8&@Q{8>Ko_ + */ + +/** + * \file zrtp.h + * \brief Defines basic libzrtp functions and data types + */ + +#ifndef __ZRTP_H__ +#define __ZRTP_H__ + +#include "zrtp_config.h" +#include "zrtp_base.h" +#include "zrtp_error.h" +#include "zrtp_types.h" +#include "zrtp_protocol.h" +#include "zrtp_engine.h" +#include "zrtp_crypto.h" +#include "zrtp_iface.h" +#include "zrtp_iface_system.h" +#include "zrtp_iface_scheduler.h" +#include "zrtp_list.h" +#include "zrtp_legal.h" +#include "zrtp_log.h" +#include "zrtp_srtp.h" +#include "zrtp_srtp_builtin.h" +#include "zrtp_string.h" +#include "zrtp_pbx.h" +#include "zrtp_legal.h" +#include "zrtp_version.h" +#include "zrtp_iface_cache.h" +#if (defined(ZRTP_ENABLE_EC) && (ZRTP_ENABLE_EC == 1)) +#include "zrtp_ec.h" +#endif + + + +/** + * \defgroup zrtp_api API + * + * In this section the basic functions for using the library are defined. They include + * initialization and deinitialization functions, functions for session and stream management and + * functions for RTP traffic management. + * + * In most cases this section is all you need to start working with libzrtp. The typical simplified + * order of operations in using libzrtp is the following: + * -# library configuration + * -# library initialization; + * -# ZRTP session creation and configuration; + * -# ZRTP stream attaching and Protocol initiation; + * -# RTP stream processing; + * -# ZRTP protocol stopping and releasing resources. + * For each of these actions there is a set of corresponding functions. + * \sa + * - \ref howto + * - \ref XXX_GUIDE + */ + + + +/*======================================================================*/ +/* Public ZRTP libzrtp datatypes */ +/*======================================================================*/ + + +/** + * \defgroup zrtp_types Types and Definitions + * \ingroup zrtp_api + * The data types used in libzrtp are defined in this section + * \{ + * + */ +/** + * \typedef typedef uint32_t zrtp_id_t; + * \brief libzrtp general identifier used to debug connections management. + * \ingroup zrtp_main_init + */ + +/** + * \brief Enumeration for ZRTP Licensing modes + * \ingroup zrtp_main_init + * + * A ZRTP endpoint that is Passive will never send a Commit message, which means that it cannot be + * the initiator in the ZRTP exchange. Since at least one of the two parties must be the initiator, + * two Passive endpoints cannot make a secure connection. However, a non-Passive ZRTP endpoint can + * send a Commit message, enabling it to act as the initiator in a ZRTP exchange. This allows it to + * make a secure connection to a Passive endpoint, or to another non-Passive endpoint. + * + * In addition, a Passive ZRTP endpoint declares that it is Passive by setting the passive flag in + * the Hello message, which means the other party will recognize it as Passive. This allows for a + * Passive mode and two forms of Active mode-- Active, or Unlimited. These three possible behaviors + * for a ZRTP endpoint are defined as: + * - \b Passive: Never send a Commit message, and thus can never be the initiator. + * - \b Active: Will send a Commit message, but only to non-Passive ZRTP partners. + * - \b Unlimited: Will send a Commit message to any ZRTP partner, Passive or non-Passive. + * + * This can be used to provide three classes of service, which can be licensed t different price + * points. Passive can be used in freeware for widest possible deployment, Active can be used in + * discount products that can only talk to non-freeware, and Unlimited can be used in full-price + * products that will benefit from the network effect of widely deployed Passive freeware. + */ +typedef enum zrtp_license_mode_t +{ + /** @brief Never send a Commit message, and thus can never be the initiator. */ + ZRTP_LICENSE_MODE_PASSIVE = 0, + /** @brief Will initiate ZRTP exchange, but only to non-Passive ZRTP partners. */ + ZRTP_LICENSE_MODE_ACTIVE, + /** @brief Will send a Commit message to any ZRTP partner, Passive or non-Passive. */ + ZRTP_LICENSE_MODE_UNLIMITED +} zrtp_license_mode_t; + + +/** @brief 12-byte ZID for unique ZRTP endpoint identification. */ +typedef unsigned char zrtp_zid_t[12]; + +/** \brief 16-byte ID for ZRTP endpoint's software identification. */ +typedef char zrtp_client_id_t[16]; + +/** + * \brief ZRTP global configuration options + * \ingroup zrtp_main_init + * \warning Use \ref zrtp_config_defaults() before start configuring this structure. + */ +typedef struct zrtp_config_t +{ + /** @brief Symbolic client identifier */ + zrtp_client_id_t client_id; + + /** @brief libzrtp license mode defined protocol behavior */ + zrtp_license_mode_t lic_mode; + + /** @brief Set this flag to 1 if you product is MiTM box */ + uint8_t is_mitm; + + /** @brief Set of interfaces required to operate with libzrtp */ + zrtp_callback_t cb; + + /** @brief Path to zrtp cache file (set if you use built-in realization) */ + zrtp_string128_t def_cache_path; +} zrtp_config_t; + +/** + * \brief zrtp stream information structure + * \ingroup zrtp_main_management + * + * libzrtp, since v0.80 takes data incapsulating approach and hides all private date inside + * zrtp_stream_t structure. Developers shouldn't access them directly. \ref zrtp_stream_get() should + * be used instead to fill zrtp_stream_info_t structure. zrtp_stream_info_t contains all needed + * information in safe and easy to use form. + */ +struct zrtp_stream_info_t +{ + /** \brief Stream unique identifier for debug purposes */ + zrtp_id_t id; + + /** \brief Pointer to the parent zrtp session */ + zrtp_session_t* session; + + /** \brief Stream mode. Defines libzrtp behavior related to specified contexts. */ + zrtp_stream_mode_t mode; + + /** \brief Defines ZRTP Trusted mitm mode for the current session. */ + zrtp_mitm_mode_t mitm_mode; + + /** \brief Reflects current state of ZRTP protocol */ + zrtp_state_t state; + + /** + * \brief Last protocol error code + * + * Available for reading in ERROR state on zrtp_security_event_t#ZRTP_EVENT_PROTOCOL_ERROR. + */ + zrtp_protocol_error_t last_error; + + /** + * \brief Remote passive flag + * + * This flag shows when remote side is "passive" (has license mode PASSIVE) available in CLEAR + * state and later. + */ + uint8_t peer_passive; + + /** + * \brief Allowclear flag. + * + * Current value of "allowclear" option exchanged during ZRTP negotiation. Available in SECURE + * state. + */ + uint8_t res_allowclear; + + /** + * \brief Peer disclose bit flag + * + * Indicates the ability of the remote side to disclose its session key. Specifies that the + * remote side allows call monitoring. If this flag is set, the end user must be informed. It + * can be read in the SECURE state. + */ + uint8_t peer_disclose; + + /** + * \brief Defines that remote party is ZRTP MiTM endpoint + * + * Enabled by (Asterisk PBX, UMLab SIP Firewall or etc.) Available for reading in CLEAR state + * ande later. + */ + uint8_t peer_mitm; +}; + +/** + * \brief zrtp session information structure + * \ingroup zrtp_main_management + * libzrtp, since v0.80 takes data incapsulating approach and hides all private date inside + * zrtp_session_t structure. Developers shouldn't access them directly. \ref zrtp_session_get() + * should be used instead to fill zrtp_session_info_t structure. zrtp_session_info_t contains all + * needed information in safe and easy to use form. + */ +struct zrtp_session_info_t +{ + /** \brief Session unique identifier for debug purposes */ + zrtp_id_t id; + + /** + * \brief Local ZID + * + The unique 12-characters string that identifies the local ZRTP endpoint.This ID allows remote + * peers to recognize this ZRTP endpoint. + */ + zrtp_string16_t zid; + + /** + * \brief Remote ZID + * + * Extracted from the Hello packet of the very first ZRTP stream. Uniquely identifies the remote + * ZRTP peer. + */ + zrtp_string16_t peer_zid; + + /** \brief Character name identified remote ZRTP endpoint.*/ + zrtp_string16_t peer_clientid; + + /** \brief ZRTP Protocol version supported by the remote endpoint. */ + zrtp_string16_t peer_version; + + /** + * \brief Indicates that SAS related data is available for reading. + * \note + * As SAS is computed in SECURE state only, it may contain unknown values in other states. Check + * sas_is_ready before displaying SAS to the user. + */ + uint8_t sas_is_ready; + + /** \brief First Short Authentication String */ + zrtp_string16_t sas1; + + /** + * \brief Second Short Authentication string. + * \note + * Second SAS is available for \c base256 authentication only (\c sas_is_base256 is set). In + * other case, \c sas1 contains \c base32 value and \c sas2 is empty. + */ + zrtp_string16_t sas2; + + /** \brief Binary SAS digest (ZRTP_SAS_DIGEST_LENGTH bytes) */ + zrtp_string32_t sasbin; + + /** + * \brief Bit-map to summarize shared secrets "Cached" flags. + * + * 1 at appropriate bit means that the secrets was found in the cache and restored successfully. + * Value equal to 0 indicates that secret for the remote endpoint was not found in the cache + * and was generated randomly. + * Use ZRTP_BIT_RS1, ZRTP_BIT_RS2, ZRTP_BIT_AUX and ZRTP_BIT_PBX bit-masks to get "cached" value + * for the appropriate secret. + */ + uint32_t cached_flags; + + /** + * \brief Bit-map to summarize shared secrets "Matched" flags. + * + * 1 at appropriate bit means that the secret, locally computed by your ZRTP endpoint is equal + * to the secret, received from the remote endpoint. Secrets may not match if one of the + * endpoints doesn't use cache of the shared secrets, if the cache was deleted or in case of + * an attack. + * Use ZRTP_BIT_RS1, ZRTP_BIT_RS2, ZRTP_BIT_AUX and ZRTP_BIT_PBX bit-masks to get "cached" value + * for the appropriate secret. + */ + uint32_t matches_flags; + + /** + * \brief Bit-map to summarize shared secrets "Wrong" flags. + * + * 1 at appropriate bit means that the secret was restored from the cache, but doesn't match + * to the remote endpoint's secret. Such situation may happen if the remote endpoint lost cache + * or in case of attach. + * Use ZRTP_BIT_RS1, ZRTP_BIT_RS2, ZRTP_BIT_AUX and ZRTP_BIT_PBX bit-masks to get "cached" value + * for the appropriate secret. + */ + uint32_t wrongs_flags; + + /** + * \brief SAS Verification flag. + * + * The SAS Verified flag (V) is set based on the user indicating that SAS comparison has been + * successfully performed. Each party sends the SAS Verified flag from the previous session in + * the Confirm message of the current session. + * \sa + * - ZRTP RFC section. "7.1. SAS Verified Flag" for more information about Verification Flag. + * - zrtp_verified_set() + */ + uint32_t sas_is_verified; + + /** \brief Indicates base256 SAS encoding */ + uint8_t sas_is_base256; + + /** + * \brief actual lifetime of the secrets + * + * This variable contains the interval for retaining secrets within an established session. In + * accordance with ZRTP RFC this value is calculated as the minimal of local and remote TTLs + * after confirmation. Value is given in seconds and can be read in the SECURE state. + */ + uint32_t secrets_ttl; + + /** \brief Hash crypto component name used in ZRTP calculations. */ + zrtp_string32_t hash_name; + + /** \brief Cipher crypto component name used in ZRTP encryption. */ + zrtp_string32_t cipher_name; + + /** \brief SRTP Authentication crypto component name used in ZRTP exchange. */ + zrtp_string32_t auth_name; + + /** \brief SAS scheme crypto component name used in ZRTP exchange. */ + zrtp_string32_t sas_name; + + /** \brief Publik Key Exchange name used in ZRTP exchange. */ + zrtp_string32_t pk_name; +}; + +/* \} */ + + +/*======================================================================*/ +/* libzrtp Public API: Streams management */ +/*======================================================================*/ + + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/** + * \defgroup zrtp_main_init Initalization and Configuration + * \ingroup zrtp_api + * \{ + */ + +/** + * \brief Initializes libzrtp global config + * + * zrtp_config_defaults() prepares all fields of zrtp_config_t for further usage in zrtp_init(). + * This function allocates all necessary resources and initialize zrtp_config_t#cb with default + * implementations. + * + * \param config - libzrtp config for initialization. + * \warning this function must be used before start operating with the config. + */ +void zrtp_config_defaults(zrtp_config_t* config); + +/** + * \brief Initializing libzrtp + * + * This function initializes the library and all its components. zrtp_init() initialize global data + * for all sessions and streams. Fields of the global zrtp context are initialized automatically and + * shouldn't be modified. For correct memory management, global context should be released by + * calling zrtp_down(). + * + * \param config - libzrtp inital parameters + * \param zrtp - out parameter, pointer to allocated zrtp global context structure; + * \warning this function \b must be called before any operation with libzrtp. + * \return + * - zrtp_status_ok in successfully initialized or one of zrtp status errors in other case. + * \sa zrtp_down() +*/ +zrtp_status_t zrtp_init(zrtp_config_t* config, zrtp_global_t** zrtp); + +/*! + * \brief Shutting down the library + * + * Frees all allocated structures and resources. This function \b must be called at the end of use + * to stop libzrtp correctly. zrtp_down() doesn't stop in-progress ZRTP streams. To avoid mistakes, + * close all sessions before library deinitialization. + * + * \param zrtp - global ZRTP context previously allocated by zrtp_init(); + * \return + * - zrtp_status_ok if successfully shut down; + * - zrtp_status_fail if an error occurred. + * \sa zrtp_init() + */ +zrtp_status_t zrtp_down(zrtp_global_t* zrtp); + +/* \} */ + +/** + * \defgroup zrtp_main_management ZRTP Connections + * \ingroup zrtp_api + * \{ + */ + +/** + * \brief ZRTP Session Initialization. + * + * This function allocates and initializes the internal session context data. The given context is + * associated with the specified ZRTP identifier. Only after initialization does the session contain + * ZRTP_MAX_STREAMS_PER_SESSION streams ready to be used. + * + * After successfully initialization, configuration will be done according to the relevant profile + * \c profile. Profile will be applyed to every stream allocated within this session. Before using + * the profile, call zrtp_profile_check() function to make sure that the profile you are applying + * is correct. + * + * \warning Don't call zrtp_session_init() in parallel with other operations on this session. + * \param zrtp - global libzrtp context; + * \param profile - the session configuration profile. If value of this parameter is NULL, default + * profile will be used. NULL profile usage is equivalent to calling zrtp_profile_defaults(). + * \param zid - ZRTP peer identificator. + * \param is_initiator - identifies if the endpoint was the signaling initiator of the call. Used to + * provide Passive Mode options to the developer. If your application doesn't control signaling + * or you don't want to support Passive Mode features - set this flag to 1. Check \ref XXX for + * more information. + * \param session - allocated session structure. + * \return + * - zrtp_status_ok if initialization is successful; + * - zrtp_status_fail if an error occurs. + * \sa zrtp_session_down() + */ +zrtp_status_t zrtp_session_init( zrtp_global_t* zrtp, + zrtp_profile_t* profile, + zrtp_zid_t zid, + uint8_t is_initiator, + zrtp_session_t **session); +/** + * \brief ZRTP Session context deinitialization + * + * This function releases all resources allocated for internal context operations by zrtp_init(). + * + * \warning Don't call zrtp_session_init() in parallel with other operations on this session. + * \param session - session for deinitialization. + * \sa zrtp_session_init() + */ +void zrtp_session_down(zrtp_session_t *session); + + +/** + * \brief Obtain information about ZRTP session + * + * Function initialize and fills all fields of zrtp_session_info_t structure accordint to + * current state of ZRTP session. + * + * \param session - zrtp session which parameters should be extracted; + * \param info - out structure to be initialized. + * \return + * - zrtp_status_ok in case of success. + * - zrtp_status_fail if an error occurs. + */ +zrtp_status_t zrtp_session_get(zrtp_session_t *session, zrtp_session_info_t *info); + +/** + * \brief Allow user to associate some data with current zrtp session. + * \param session - zrtp session to attach data to. + * \param udata - pointer to the user-data context. + * \sa zrtp_session_get_userdata() + */ +void zrtp_session_set_userdata(zrtp_session_t *session, void* udata); + +/** + * \brief Return user data associated with the zrtp session + * \param session - zrtp session to extract user data. + * \return + * - pointer to the user-data context previously set by zrtp_session_set_userdata(). + * - NULL if the user data unavailable. + * \sa zrtp_session_set_userdata() + */ +void* zrtp_session_get_userdata(zrtp_session_t *session); + +/** + * \brief Attaching a new stream to the session + * + * This function call initializes a ZRTP stream and prepares it for use within the specified + * session. The maximum number of streams for one session is defined by the + * ZRTP_MAX_STREAMS_PER_SESSION variable. All newly created streams are equivalent and have + * ZRTP_STREAM_MODE_CLEAR mode and ZRTP_ACTIVE state. Only after attaching a stream, ZRTP protocol + * can be initiated. + * + * \param session - the ZRTP session within which a new stream is to be + * \param stream - out parameter, attached stream will be stored there + * \return + * - zrtp_status_ok if stream was attached successfully + * - one of zrtp_status_t errors in case of failure + * \sa zrtp_stream_start() zrtp_stream_stop() + */ +zrtp_status_t zrtp_stream_attach(zrtp_session_t *session, zrtp_stream_t** stream); + +/** + * \brief Starting a ZRTP stream + * + * ZRTP stream setup is initiated by calling this function. Exchange of command packets begins + * immediately according to protocol. If the option "autosecure" is on, calling this function is the + * only requirement for setting up the ZRTP connection within a stream. If "autosecure" mode is not + * available, calling this function activates only connection within a ZRTP stream. A connection can + * be established manually later by calling zrtp_stream_secure(). + * + * Setup of the stream/connection takes a certain interval of time. This function just initiates + * this process. The system of callbacks informs the user about the progress of libzrtp protocol. + * + * \param stream - ZRTP stream to be started. + * \param ssrc - ssrc which will be used in ZRTP protocol messages. It should match with ssrc of + * appropriate RTP stream which will be encrypted by this ZRTP stream. + * \return + * - zrtp_status_ok in case of success; + * - one of zrtp_status_t errors in case of failure + * \sa + * - \ref XXX_GUIDE_CB \ref XXX_GUIDE_MANAGEMENT + * - zrtp_stream_stop() zrtp_stream_secure() zrtp_stream_clear() + */ +zrtp_status_t zrtp_stream_start(zrtp_stream_t* stream, uint32_t ssrc); + +/** + * \brief ZRTP protocol stopping + * + * This function stops all protocol operations for the specified stream, releases resources + * allocated on the zrtp_stream_start() and prepares the stream structure for the next use. + * + * This function will stop the protocol at any stage: all delayed tasks are canceled, and the + * protocol packet exchange and encryption is stopped. After this function call it is necessary to + * stop processing traffic using the zrtp_process_xxx() function. + * + * \param stream - the stream being shutdown. + * \return + * - zrtp_status_ok in case of success; + * - one of zrtp_status_t errors in case of failure + * \sa + * - \ref XXX_GUIDE_CB \ref XXX_GUIDE_MANAGEMENT + * - zrtp_stream_start() zrtp_stream_secure() zrtp_stream_clear() + */ +zrtp_status_t zrtp_stream_stop(zrtp_stream_t* stream); + +/*! + * \brief Initiating an interruption of the secure connection + * + * This function initiates the shutting down of the ZRTP connection within a stream. In other words, + * after successfully switching to secure mode (\ref XXX SECURE state, fig. 1.5), calling this + * function begins the exchange of packets switching back to insecure (CLEAR) mode. + * + * This function can only be implemented from the SECURE state. Attempt to call this function from + * any other state will end in failure. The client application is informed about protocol + * progress through a system of callbacks. + * + * \param stream - ZRTP stream . + * \return + * - zrtp_status_ok - if shutting down the connection is started successfully. + * - zrtp_status_fail - if shutting down the connection is initiated from an incorrect state. + * \sa + * - \ref XXX_GUIDE_CB \ref XXX_GUIDE_MANAGEMENT + * - zrtp_stream_start() zrtp_stream_secure() zrtp_stream_clear() + */ +zrtp_status_t zrtp_stream_clear(zrtp_stream_t *stream); + +/** + * \brief Initiating a secure connection setup + * + * The function initiates a ZRTP connection setup within a stream. In other words, after the + * protocol has started and Discovery phase have been successfully accomplished, calling this + * function will begin the exchange of packets for switching to SECURE mode. + * + * This function can be successfully performed only from the CLEAR state (\ref XXX Figure 1.6). + * Attempting to call this function from any other state will result in failure. The client + * application is informed about protocol progress through a system of callbacks. + * + * \param stream - ZRTP stream to be secured. + * \return + * - zrtp_status_ok - if switching to secure mode started successfully. + * - zrtp_status_fail - if switching to secure mode is initiated from a state other than CLEAR. + * \sa + * - \ref XXX_GUIDE_CB \ref XXX_GUIDE_MANAGEMENT. + * - zrtp_stream_start() zrtp_stream_clear(). + */ +zrtp_status_t zrtp_stream_secure(zrtp_stream_t *stream); + +/** + * \brief Obtain information about zrtp stream + * + * Function initialize and fills all fields of zrtp_stream_info_t structure accordint to + * current state of zrtp stream. + * + * \param stream - zrtp stream which parameters should be extracted + * \param info - out structure to be initialized + * \return + * - zrtp_status_ok in case of success. + * - zrtp_status_fail if an error occurs. + */ +zrtp_status_t zrtp_stream_get(zrtp_stream_t *stream, zrtp_stream_info_t *info); + +/** + * @brief Allow user to associate some data with zrtp stream. + * @param stream - zrtp stream to attach data to. + * @param udata - pointer to the user-data context. + * @sa zrtp_stream_get_userdata() + */ +void zrtp_stream_set_userdata(zrtp_stream_t *stream, void* udata); + +/** + * \brief Return user data associated with the zrtp stream + * \return + * - pointer to the user-data context previously set by zrtp_stream_set_userdata() + * - NULL if user data unavailable; + * \sa zrtp_stream_set_userdata() + */ +void* zrtp_stream_get_userdata(const zrtp_stream_t *stream); + +/* \} */ + +/*======================================================================*/ +/* libzrtp Public API: Encryption */ +/*======================================================================*/ + +/** + * \defgroup zrtp_main_proto Traffic Processing + * \ingroup zrtp_api + * \{ + */ + +/** + * \brief Processing outgoing RTP packets + * + * This is the main function for processing outgoing RTP packets. As soon as the protocol is + * started, each outgoing RTP packet (not encrypted) has to go through this function. + * + * It performs different actions depending on the connection state and packet type: + * - In setup ZRTP connection mode, it encrypts outgoing RTP packets. The packet is encrypted right + * in the transferred buffer; + * - Protects codec and data privacy by deleting certain packets from the stream. In this case the + * body and the length of the packet remain unchanged. + * + * \param stream - ZRTP stream to process RTP packet; + * \param packet - buffer storing the RTP packet for encryption. After processing, the encrypted + * packet is stored in the same buffer. + * \param length - the length of the buffered packet. After processing, the length of encrypted + * packet is stored here. + * \warning During encryption, the data length increases in comparison to the source data. Because + * the function uses the same buffer both for incoming and resulting values, the length of the + * buffer must be larger than size of source packet. + * \return + * - zrtp_status_ok if encryption is successful. The packet should be sent to the recipient. + * - zrtp_status_fail if there was an error during encryption. The packet should be rejected. + * - zrtp_status_drop if there was interference in the VoIP client codec protection mechanism. The + * packet should be rejected. + * \sa zrtp_process_srtp() zrtp_process_rtcp() zrtp_process_srtcp() + */ +zrtp_status_t zrtp_process_rtp( zrtp_stream_t *stream, + char* packet, + unsigned int* length); + +/** + * \brief Processing incoming RTP packets + * + * This is the main function for incoming RTP packets processing. It is an analogue of + * zrtp_process_rtp() but for an incoming stream. After the protocol is started, each (encrypted) + * incoming RTP packet has to go through this function. + * + * It performs different actions depending on the connection state and packet type: + * - during setup/interruption of ZRTP connection, processes incoming protocol packets. The body + * and length of the packet remain unchanged; + * - in setup ZRTP connection mode, decrypts incoming RTP packet. The packet is decrypted right in + * the transferred buffer; + * - protects codec and data privacy by deleting certain packets from the stream. In this case the + * body and the length of the packet remain unchanged. + * + * \param stream - ZRTP stream for processing + * \param packet - buffer storing the packet for decrypting. After processing, the decrypted packet + * is stored in the same buffer; + * \param length - the length of the buffered packet. After processing, the length of decrypted + * packet is stored here; + * \return + * - zrtp_status_ok if decrypting is successful. Such a packet should be sent to the recipient; + * - zrtp_status_fail if an error occurred during decrypting or command packet processing. The + * packet should be rejected; + * - zrtp_status_drop if the command packet processing is successful or if there was interference + * in the VoIP client codec protection mechanism. The packet should be rejected in either case; + * \sa zrtp_process_rtp() zrtp_process_rtcp() zrtp_process_srtcp() + */ +zrtp_status_t zrtp_process_srtp( zrtp_stream_t *stream, + char* packet, + unsigned int* length); + +/*! + * \brief Processing outgoing RTCP packets + * + * This is the main function for processing outgoing RTCP packets. The function behavior is similar + * to that of zrtp_process_rtp(): + * - In SECURE mode, encrypts outgoing RTCP packets. The packet is encrypted right in the + * transferred buffer. The length of encrypted packet is returned in the \c length variable; + * - protects codec and data privacy by deleting certain packets from the stream. In this case the + * body and the length of the packet remain unchanged. + * + * \param stream - ZRTP session for processing; + * \param packet - buffer storing RTCP packet; + * \param length - length of the buffered packet. + * \return + * - zrtp_status_ok if encryption is successful. The packet should be sent to the recipient. + * - zrtp_status_fail if there was an error during encryption. The packet should be rejected. + * - zrtp_status_drop if there was interference in the VoIP client codec protection mechanism. The + * packet should be rejected. + * \sa zrtp_process_srtp() zrtp_process_rtp() zrtp_process_srtcp() + */ +zrtp_status_t zrtp_process_rtcp( zrtp_stream_t *stream, + char* packet, + unsigned int* length); + +/** + * \brief Processing incoming RTCP packets + * + * This is the main function for processing incoming RTCP packets. The function behavior is similar + * to that of zrtp_process_srtp(): + * - In SECURE mode, decrypts incoming RTCP packets. The packet is decrypted right in the + * transferred buffer. The length of the encrypted packet is returned in the \c length variable; + * - In transition states, drops all incoming RTCP traffic. In this case the body and the length of + * the packet remain unchanged. + * + * \param stream - ZRTP stream for processing; + * \param packet - buffer storing the RTCP packet; + * \param length - length of the buffered packet. + * \return + * - zrtp_status_ok if decrypting is successful. Such a packet should be sent to the recipient; + * - zrtp_status_drop if the command packet processing is successful or if there was interference + * in the VoIP client codec protection mechanism. The packet should be rejected in either case; + * - zrtp_status_fail if there was an error during encryption. The packet should be rejected. + * \sa zrtp_process_srtp() zrtp_process_rtp() zrtp_process_rtcp() + */ +zrtp_status_t zrtp_process_srtcp( zrtp_stream_t *stream, + char* packet, + unsigned int* length); + +/* \} */ + +/** + * \defgroup zrtp_main_utils Utilites + * \ingroup zrtp_api + * \{ + */ + +/** + * \brief Specifies the hash of the peer Hello message for verification. + * + * In accordance with the ZRTP RFC sec. 9, this protocol can prevent DOS attacks by verification of + * the Hello message hash sent through the signaling protocol. + * + * This function allows the user to specify the Hello hash for verification. If after the + * discovering phase the Hello hashes don't match, libzrtp raises the + * zrtp_event_t#ZRTP_EVENT_WRONG_SIGNALING_HASH event. This function should only be called before + * starting the protocol from the ZRTP_STATE_ACTIVE state. + * + * \param stream - stream for operating with; + * \param hash_buff - signaling hash buffer. Function accpt string, not a binary value!; + * \param hash_buff_length - signaling hash length in bytes (must be 64 bytes); + * \return: + * - zrtp_status_ok if the operation finished successfully + * - one of the errors otherwise + * \sa + * - ZRTP RFC. sec 8; + * - zrtp_signaling_hash_get() + */ +zrtp_status_t zrtp_signaling_hash_set( zrtp_stream_t* stream, + const char *hash_buff, + uint32_t hash_buff_length); + +/** + * \brief Returns the hash of the Hello message to be transferred in signaling. + * + * To prevent DOS attacks, the hash of the Hello message may be sent through signaling. + * zrtp_signaling_hash_get() may be called after attaching the stream to receive the value of this + * hash. + * + * \param stream - stream for operating with + * \param hash_buff - buffer for storing signaling hash. Function returns already parsed hex string. + * String is null-terminated. + * \param hash_buff_length - buffer length in bytes (not shorter than 65 bytes) + * \return: + * - zrtp_status_ok if the operation finished successfully + * - one of the errors otherwise + * \sa + * - ZRTP RFC. sec 8; + * - zrtp_signaling_hash_set() + */ +zrtp_status_t zrtp_signaling_hash_get( zrtp_stream_t* stream, + char* hash_buff, + uint32_t hash_buff_length); + +/** + * \brief Changing the value of the secret's verification flag + * + * This function is used to change (set, unset) the secret's verification flag. zrtp_verified_set() + * changes the relevant internal data and stores a flag in the cache. + * \note + * Special synchronization mechanisms are provided to protect the cache from race conditions. Don't + * change the verified flag directly in the cache - use this function. + * + * \param zrtp - zrtp global data; + * \param zid1 - ZID of the first party; + * \param zid2 - ZID of the second party; + * \param verified - Boolean value of the verified flag. + * \return + * - zrtp_status_ok - if successful; + * - one of zrtp_status_t errors if fails. + */ +zrtp_status_t zrtp_verified_set( zrtp_global_t *zrtp, + zrtp_string16_t *zid1, + zrtp_string16_t *zid2, + uint8_t verified); + +/** + * \brief Verifying the ZRTP profile + * + * zrtp_profile_check() checks the correctness of the values in the profile. The following checks + * are performed: + * - the number of components in each group does not exceed ZRTP_MAX_COMP_COUNT; + * - the components declared are supported by the library kernel. + * - presence of the set of obligatory components defined by ZRTP RFC. + * + * \param profile - ZRTP profile for validation; + * \param zrtp - global ZRTP context. + * \return + * - zrtp_status_ok - if profile passed all available tests; + * - one of ZRTP errors - if there are mistakes in the profile. See debug logging for additional + * information. + */ +zrtp_status_t zrtp_profile_check(const zrtp_profile_t* profile, zrtp_global_t* zrtp); + +/** + * \brief Configure the default ZRTP profile + * + * These options are used: + * \code + * "active" is enabled; + * "allowclear" is disabled by default and enabled for Zfone only; + * "autosecure" is enabled; + * "disclose_bit" is disabled; + * cache_ttl = ZRTP_CACHE_DEFAULT_TTL defined by ZRTP RFC; + * + * [sas_schemes] = ZRTP_SAS_BASE256, ZRTP_SAS_BASE32; + * [cipher_types] = ZRTP_CIPHER_AES128; + * [pk_schemes] = ZRTP_PKTYPE_DH3072; + * [auth_tag_lens] = ZRTP_ATL_HS32; + * [hash_schemes] = ZRTP_HASH_SHA256; + * \endcode + * + * \param profile - ZRTP stream profile for filling; + * \param zrtp - libzrtp global context. + */ +void zrtp_profile_defaults(zrtp_profile_t* profile, zrtp_global_t* zrtp); + +/** + * \brief Search for a component in the profile by ID + * + * The utility function returning the position of an element of the specified type in the profile. + * Used by libZRTP kernel and for external use. + * + * \param profile - ZRTP profile; + * \param type - sought component type; + * \param id - sought component ID. + * \return + * - component position - if component was found; + * -1 - if the component with the specified ID can't be found in profile. + */ +int zrtp_profile_find(const zrtp_profile_t* profile, zrtp_crypto_comp_t type, uint8_t id); + +/* \} */ + +/** + * \defgroup zrtp_main_rng Random Number Generation + * \ingroup zrtp_api + * \{ + * The generation of cryptographic key material is a highly sensitive process. To do this, you need + * high entropy random numbers that an attacker cannot predict. This section \ref rng gives basic + * knowliges andbot the RNG and it's implementation in libzrtp. + * \warning + * \ref rng \c MUST be read by every developer using libzrtp. + */ + +/** + * \brief Entropy accumulation routine + * + * The random number generation scheme is described in detail in chapter \ref XXX. This function + * gets \c length bytes of entropy from \c buffer and hashes it into the special storage. This + * function should be called periodically from the user's space to increase entropy quality. + * \warning + * RNG is a very important and sensitive component of the crypto-system. Please, pay attention to + * \ref rng. + * \param zrtp - libzrtp global context; + * \param buffer - pointer to the buffer with entropy for accumulating; + * \param length - entropy size in bytes. + * \return: number of hashed bytes. + */ +int zrtp_entropy_add(zrtp_global_t* zrtp, const unsigned char *buffer, uint32_t length); + +/** + * \brief Random string generation + * + * zrtp_randstr() generates \c length bytes of "random" data. We say "random" because the + * "randomness" of the generated sequence depends on the quality of the entropy passed to + * zrtp_entropy_add(). If the user provides "good" entropy, zrtp_randstr() generates sufficiently + * "random" data. + * + * \param zrtp - libzrtp global context; + * \param buffer - buffer into which random data will be generated; + * \param length - length of required sequence in bytes. + * \return + * - length of generated sequence in bytes or -1 in case of error + * \sa \ref rng + */ +int zrtp_randstr(zrtp_global_t* zrtp, unsigned char *buffer, uint32_t length); + +/* \} */ + +#if defined(__cplusplus) +} +#endif + +#endif /* __ZRTP_H__ */ diff --git a/include/zrtp_base.h b/include/zrtp_base.h new file mode 100644 index 0000000000..9e32143cfa --- /dev/null +++ b/include/zrtp_base.h @@ -0,0 +1,211 @@ +/* + * 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 + */ + +#ifndef __ZRTP_BASE_H__ +#define __ZRTP_BASE_H__ + +#include "zrtp_config.h" + +typedef double uint64_t_; + +typedef uint8_t zrtp_uchar4_t[4]; +typedef uint8_t zrtp_uchar8_t[8]; +typedef uint8_t zrtp_uchar12_t[12]; +typedef uint8_t zrtp_uchar16_t[16]; +typedef uint8_t zrtp_uchar32_t[32]; +typedef uint8_t zrtp_uchar64_t[64]; +typedef uint8_t zrtp_uchar128_t[128]; +typedef uint8_t zrtp_uchar256_t[256]; +typedef uint8_t zrtp_uchar1024_t[1024]; + +typedef uint32_t zrtp_id_t; + +typedef struct zrtp_profile_t zrtp_profile_t; +typedef struct zrtp_stream_t zrtp_stream_t; +typedef struct zrtp_session_t zrtp_session_t; +typedef struct zrtp_global_t zrtp_global_t; + +typedef struct zrtp_protocol_t zrtp_protocol_t; +typedef struct zrtp_srtp_ctx_t zrtp_srtp_ctx_t; +typedef struct zrtp_shared_secret_t zrtp_shared_secret_t; +typedef struct zrtp_retry_task_t zrtp_retry_task_t; + +typedef struct zrtp_hash_t zrtp_hash_t; +typedef struct zrtp_cipher_t zrtp_cipher_t; +typedef struct zrtp_auth_tag_length_t zrtp_auth_tag_length_t; +typedef struct zrtp_pk_scheme_t zrtp_pk_scheme_t; +typedef struct zrtp_sas_scheme_t zrtp_sas_scheme_t; +typedef struct zrtp_sig_scheme_t zrtp_sig_scheme_t; + +typedef struct zrtp_mutex_t zrtp_mutex_t; +typedef struct zrtp_sem_t zrtp_sem_t; + +typedef struct zrtp_stream_info_t zrtp_stream_info_t; +typedef struct zrtp_session_info_t zrtp_session_info_t; + +#include "sha2.h" +#define MD_CTX sha512_ctx +#define MD_Update(a,b,c) sha512_hash((const unsigned char *)(b),c,a) + + +/** + * \brief Function computing minimum value + * + * This macro returns the lesser of two values. If the numbers are equal, either of them is returned. + * + * \param left - first value for comparison; + * \param right - second value for comparison. + * \return + * - lesser of compared numbers. + */ +#define ZRTP_MIN(left, right) ((left < right) ? left : right) + + +/*! + * \brief zrtp_htonXX, zrtp_ntohXX - convert values between host and network + * byte order + * + * To avoid ambiguities and difficulties with compilation on various platforms, + * we designed our own swap functions. Byte order detection is based on zrtp_system.h. + * + * On the i80x86 the host byte order is little-endian (least significant byte + * first), whereas the network byte order, as used on the Internet, is + * big-endian (most significant byte first). + */ + +ZRTP_INLINE uint16_t zrtp_swap16(uint16_t x) { + return (x >> 8 | x << 8); +} + +uint32_t zrtp_swap32(uint32_t x); +uint64_t zrtp_swap64(uint64_t x); + +#if ZRTP_BYTE_ORDER == ZBO_BIG_ENDIAN +/*! Converts 16 bit unsigned integer to network byte order */ +#define zrtp_hton16(x) (x) +/*! Converts 32 bit unsigned integer to network byte order */ +#define zrtp_hton32(x) (x) +/*! Converts 64 bit unsigned integer to network byte order */ +#define zrtp_hton64(x) (x) + +/*! Converts 16 bit unsigned integer to host byte order */ +#define zrtp_ntoh16(x) (x) +/*! Converts 32 bit unsigned integer to host byte order */ +#define zrtp_ntoh32(x) (x) +/*! Converts 64 bit unsigned integer to host byte order */ +#define zrtp_ntoh64(x) (x) +#else /* ZBO_BIG_ENDIAN */ +/*! Converts 16 bit unsigned integer to network byte order */ +#define zrtp_hton16(x) (zrtp_swap16(x)) +/*! Converts 32 bit unsigned integer to network byte order */ +#define zrtp_hton32(x) (zrtp_swap32(x)) +/*! Converts 64 bit unsigned integer to network byte order */ +#define zrtp_hton64(x) (zrtp_swap64(x)) + +/*! Converts 16 bit unsigned integer to host byte order */ +#define zrtp_ntoh16(x) (zrtp_swap16(x)) +/*! Converts 32 bit unsigned integer to host byte order */ +#define zrtp_ntoh32(x) (zrtp_swap32(x)) +/*! Converts 64 bit unsigned integer to host byte order */ +#define zrtp_ntoh64(x) (zrtp_swap64(x)) +#endif + + +/* + * 128 and 256-bit structures used in Ciphers and SRTP module + */ +typedef union + { + uint8_t v8[16]; + uint16_t v16[8]; + uint32_t v32[4]; + uint64_t v64[2]; + } zrtp_v128_t; + +typedef union + { + uint8_t v8[32]; + uint16_t v16[16]; + uint32_t v32[8]; + uint64_t v64[4]; + } zrtp_v256_t; + +/* + * The following macros define the data manipulation functions. + * + * If DATATYPES_USE_MACROS is defined, then these macros are used directly (and + * function-call overhead is avoided). Otherwise, the macros are used through + * the functions defined in datatypes.c (and the compiler provides better + * warnings). + */ + +#define _zrtp_v128_xor(z, x, y) \ +( \ +(z)->v32[0] = (x)->v32[0] ^ (y)->v32[0], \ +(z)->v32[1] = (x)->v32[1] ^ (y)->v32[1], \ +(z)->v32[2] = (x)->v32[2] ^ (y)->v32[2], \ +(z)->v32[3] = (x)->v32[3] ^ (y)->v32[3] \ +) + +#define _zrtp_v128_get_bit(x, bit) \ +( \ +( (((x)->v32[(bit) >> 5]) >> ((bit) & 31)) & 1) \ +) + +#define zrtp_bitmap_get_bit(x, bit) \ +( \ +( (((x)[(bit) >> 3]) >> ((bit) & 7) ) & 1) \ +) + +#define zrtp_bitmap_set_bit(x, bit) \ +( \ +( (((x)[(bit) >> 3])) |= ((uint8_t)1 << ((bit) & 7)) ) \ +) + +#define zrtp_bitmap_clear_bit(x, bit) \ +( \ +( (((x)[(bit) >> 3])) &= ~((uint8_t)1 << ((bit) & 7)) ) \ +) + +void zrtp_bitmap_left_shift(uint8_t *x, int width_bytes, int index); + +void zrtp_v128_xor(zrtp_v128_t *z, zrtp_v128_t *x, zrtp_v128_t *y); + + + +//WIN64 { +#if (ZRTP_PLATFORM == ZP_WIN32_KERNEL) + +#ifdef WIN64 // For 64-bit apps + +unsigned __int64 __rdtsc(void); +#pragma intrinsic(__rdtsc) +#define _RDTSC __rdtsc + +#else // For 32-bit apps + +#define _RDTSC_STACK(ts) \ +__asm rdtsc \ +__asm mov DWORD PTR [ts], eax \ +__asm mov DWORD PTR [ts+4], edx + +__inline unsigned __int64 _inl_rdtsc32() { + unsigned __int64 t; + _RDTSC_STACK(t); + return t; +} +#define _RDTSC _inl_rdtsc32 + +#endif + +#endif +//WIN64 } + + +#endif /*__ZRTP_BASE_H__*/ diff --git a/include/zrtp_config.h b/include/zrtp_config.h new file mode 100644 index 0000000000..ca002d8c43 --- /dev/null +++ b/include/zrtp_config.h @@ -0,0 +1,239 @@ +/* + * 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 + */ + +#ifndef __ZRTP_CONFIG_H__ +#define __ZRTP_CONFIG_H__ + +#include "zrtp_config_user.h" + +/* + * ZRTP PLATFORM DETECTION + * If platworm is not specified manually in zrtp_config_user.h - try to detect it aytomatically + */ +#if !defined(ZRTP_PLATFORM) +# if defined(linux) || defined(__linux) +# include +# define ZRTP_PLATFORM ZP_LINUX +# elif defined(__MACOSX__) || defined (__APPLE__) || defined (__MACH__) +# define ZRTP_PLATFORM ZP_DARWIN +# elif defined(_WIN32_WCE) || defined(UNDER_CE) +# include +# define ZRTP_PLATFORM ZP_WINCE +# elif defined(__SYMBIAN32__) +# define ZRTP_PLATFORM ZP_SYMBIAN +# elif defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) || defined(WIN32) || defined(__TOS_WIN__) +# if defined(__BUILDMACHINE__) && (__BUILDMACHINE__ == WinDDK) +# define ZRTP_PLATFORM ZP_WIN32_KERNEL +# else +# define ZRTP_PLATFORM ZP_WIN32 +# endif +# endif +#endif + +#if (ZRTP_PLATFORM == ZP_LINUX) || (ZRTP_PLATFORM == ZP_DARWIN) || (ZRTP_PLATFORM == ZP_BSD) || defined(ZRTP_AUTOMAKE) +# include "zrtp_config_unix.h" +#elif (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WIN32_KERNEL) || (ZRTP_PLATFORM == ZP_WINCE) +# include "zrtp_config_win.h" +#elif (ZRTP_PLATFORM == ZP_SYMBIAN) +# include "zrtp_config_symbian.h" +#endif + +#if !defined(ZRTP_PLATFORM) +# error "Libzrtp can't detect software platform: use manual setup in zrtp_config_user.h" +#endif + +#if ZRTP_HAVE_LINUX_VERSION_H == 1 +#include +#endif +#if ZRTP_HAVE_ASM_TYPES_H == 1 +#include +#endif + +/* + * ZRTP BYTEORDER DETECTION + * If the byte order is not specified manually in zrtp_config_user.h - try to detect it aytomatically + */ +#if !defined(ZRTP_BYTE_ORDER) + +#if defined(_i386_) || defined(i_386_) || defined(_X86_) || defined(x86) || defined(__i386__) || \ + defined(__i386) || defined(_M_IX86) || defined(__I86__) +/* + * Generic i386 processor family, little-endian + */ +#define ZRTP_BYTE_ORDER ZBO_LITTLE_ENDIAN + +#elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_AMD64_) +/* + * AMD 64bit processor, little endian + */ +#define ZRTP_BYTE_ORDER ZBO_LITTLE_ENDIAN + +#elif defined( __sparc__) || defined(__sparc) +/* + * Sun Sparc, big endian + */ +#define ZRTP_BYTE_ORDER ZBO_BIG_ENDIAN + +#elif defined(ARM) || defined(_ARM_) || defined(ARMV4) || defined(__arm__) +/* + * ARM, default to little endian + */ +#define ZRTP_BYTE_ORDER ZBO_LITTLE_ENDIAN + +#elif defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) || defined(__ppc__) || \ + defined(_M_PPC) || defined(_ARCH_PPC) +/* + * PowerPC, big endian + */ +#define ZRTP_BYTE_ORDER ZBO_BIG_ENDIAN + +#endif /* Automatic byte order detection */ + +#endif + +#if !defined(ZRTP_BYTE_ORDER) +# error "Libzrtp can't detect byte order: use manual setup in zrtp_config_user.h" +#endif + + +/* + * Define Unaligned structure for target platform + */ +#if (ZRTP_PLATFORM == ZP_WINCE) +# define ZRTP_UNALIGNED(type) UNALIGNED type +#else +# define ZRTP_UNALIGNED(type) type +#endif + + +/* + * Define basic literal types for libzrtp + * We use this definitions in SRTP, AES and Hash implementation + */ +#if (ZRTP_PLATFORM != ZP_WIN32_KERNEL) +# if ZRTP_HAVE_STDLIB_H == 1 +# include +# endif +# if ZRTP_HAVE_STDINT_H == 1 +# include +# endif +# if ZRTP_HAVE_INTTYPES_H == 1 +# include +# endif +# if ZRTP_HAVE_SYS_TYPES_H == 1 +# include +# endif +# if ZRTP_HAVE_SYS_INT_TYPES_H == 1 +# include +# endif +# if ZRTP_HAVE_MACHINE_TYPES_H == 1 +# include +# endif +#endif + +#if (ZRTP_PLATFORM == ZP_WINCE) || (ZRTP_PLATFORM == ZP_SYMBIAN) +# define ALIGNMENT_32BIT_REQUIRED +#endif + +#ifdef ZRTP_HAVE_UINT64_T +# if ZRTP_HAVE_UINT64_T == 0 +# if defined(WIN32) || defined(WIN64) +# if defined(_MSC_VER) && (_MSC_VER < 1310) + typedef __int64 uint64_t; +# else + typedef unsigned long long uint64_t; +# endif +# else +# if SIZEOF_UNSIGNED_LONG == 8 + typedef unsigned long uint64_t; +# elif SIZEOF_UNSIGNED_LONG_LONG == 8 + typedef unsigned long long uint64_t; +# else +# define ZRTP_NO_64BIT_MATH 1 +# endif +# endif /* WIN32 */ +# endif +#endif + +#ifdef ZRTP_HAVE_INT64_T +# if ZRTP_HAVE_INT64_T == 0 +# if defined(WIN32) || defined(WIN64) +# if defined(_MSC_VER) && (_MSC_VER < 1310) + typedef __int64 int64_t; +# else + typedef long long int64_t; +# endif +# else +# if SIZEOF_UNSIGNED_LONG == 8 + typedef long int64_t; +# elif SIZEOF_UNSIGNED_LONG_LONG == 8 + typedef long long int64_t; +# else +# define ZRTP_NO_64BIT_MATH 1 +# endif +# endif /* WIN32 */ +# endif +#endif + +#define SIZEOF_UNSIGNED_LONG_LONG 8 + +#if defined(WIN32) || defined(WIN64) +# if defined(_MSC_VER) && (_MSC_VER < 1310) +# define li_64(h) 0x##h##ui64 +# else +# define li_64(h) 0x##h##ull +# endif +#else +# if SIZEOF_UNSIGNED_LONG == 8 +# define li_64(h) 0x##h##ul +# elif SIZEOF_UNSIGNED_LONG_LONG == 8 +# define li_64(h) 0x##h##ull +# else +# define ZRTP_NO_64BIT_MATH 1 +# endif +#endif /* WIN32 */ + + +#ifdef ZRTP_HAVE_UINT8_T +# if ZRTP_HAVE_UINT8_T == 0 + typedef unsigned char uint8_t; +# endif +#endif + +#ifdef ZRTP_HAVE_UINT16_T +# if ZRTP_HAVE_UINT16_T == 0 + typedef unsigned short int uint16_t; +# endif +#endif + +#ifdef ZRTP_HAVE_UINT32_T +# if ZRTP_HAVE_UINT32_T == 0 + typedef unsigned int uint32_t; +# endif +#endif + +#ifdef ZRTP_HAVE_INT8_T +# if ZRTP_HAVE_INT8_T == 0 + typedef char int8_t; +# endif +#endif + +#ifdef ZRTP_HAVE_INT16_T +# if ZRTP_HAVE_INT16_T == 0 + typedef short int int16_t; +# endif +#endif + +#ifdef ZRTP_HAVE_INT32_T +# if ZRTP_HAVE_INT32_T == 0 + typedef int int32_t; +# endif +#endif + +#endif /*__ZRTP_CONFIG_H__ */ diff --git a/include/zrtp_config_symbian.h b/include/zrtp_config_symbian.h new file mode 100644 index 0000000000..1cda65dbb2 --- /dev/null +++ b/include/zrtp_config_symbian.h @@ -0,0 +1,69 @@ +/* + * 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 + */ + +#ifndef ZRTP_SYMB_CONFIG_H__ +#define ZRTP_SYMB_CONFIG_H__ + + +/* + * Used to map system integer types to zrtp integer definitions. + * Define to 1 if you have the header file. + */ +#undef ZRTP_HAVE_INTTYPES_H + +/* + * This header is needed for operations with binary file in deefault realization + * of the secrets' cache. Can be eliminated if default cache isn't used. + * Define to 1 if you have the header file. + */ +#ifndef ZRTP_HAVE_STDIO_H +# define ZRTP_HAVE_STDIO_H 1 +#endif + +#ifndef ZRTP_HAVE_STDARG_H +# define ZRTP_HAVE_STDARG_H 1 +#endif + +/* + * Used by bnlib, but we don't need this on Symbian platform. + */ +#ifndef NO_ASSERT_H +# define NO_ASSERT_H 1 +#endif + +/* + * Used by bnlib. We have stdlib in Symbian platform - set it to 1. + */ +#ifndef NO_STDLIB_H +# define NO_STDLIB_H 0 +#endif + +#ifndef ZRTP_HAVE_SYS_TIME_H +# define ZRTP_HAVE_SYS_TIME_H 1 +#endif + + +#define ZRTP_HAVE_INT64_T 0 +#define ZRTP_HAVE_INT32_T 0 +#define ZRTP_HAVE_INT16_T 0 +#define ZRTP_HAVE_INT8_T 0 + +#define ZRTP_HAVE_UINT64_T 0 +#define ZRTP_HAVE_UINT32_T 0 +#define ZRTP_HAVE_UINT16_T 0 +#define ZRTP_HAVE_UINT8_T 0 + +#define ZRTP_BYTE_ORDER ZBO_BIG_ENDIAN + +#define SIZEOF_UNSIGNED_LONG 4 +#define SIZEOF_UNSIGNED_LONG_LONG 8 + +#define ZRTP_INLINE static __inline + +#endif /* ZRTP_WIN_CONFIG_H__ */ diff --git a/include/zrtp_config_user.h b/include/zrtp_config_user.h new file mode 100644 index 0000000000..660e341937 --- /dev/null +++ b/include/zrtp_config_user.h @@ -0,0 +1,182 @@ +/* + * 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 + */ + +/** + * @file zrtp_config_user.h + * @brief libzrtp user configuration routine + */ + +#ifndef __ZRTP_CONFIG_USER_H__ +#define __ZRTP_CONFIG_USER_H__ + +/** + * \defgroup zrtp_config Build Configuration + * \{ + * + * As libzrtp based on few OS dependent components, target platform and byte-order must be defined + * on compilation level. libzrtp provides automatic platform and byte-order detection. Developer + * needs to define these parameters manually in very specific cases only. + * + * libzrtp originaly supports folowwing platforms: + * - 32/64-bit Windows platform; + * - Windows kernel mode; + * - Apple Mac OS X and iPhone; + * - Linux and *nix platforms; + * - Symbian OS. + * + * In order to specify platform manually, developer should define ZRTP_PLATFORM value. If + * ZRTP_PLATFORM is not defined - libzrtp will try to detect it automatically (see zrtp_config.h). + * + * In order to specify platform byte-order manually, developer should define ZRTP_BYTE_ORDER value. + * If ZRTP_BYTE_ORDER is not defined - libzrtp will try to detect it automatically. + */ + +/** \brief Constant to define ZRTP Windows 32-bit platform */ +#define ZP_WIN32 100 +/** \brief Constant to define ZRTP Windows 64-bit platform */ +#define ZP_WIN64 106 +/** \brief Constant to define ZRTP Windows Kernel mode */ +#define ZP_WIN32_KERNEL 101 +/** \brief Constant to define ZRTP Windows CE platform */ +#define ZP_WINCE 102 +/** \brief Constant to define Linux and *nux platforms */ +#define ZP_LINUX 103 +/** \brief Constant to define Mac OS X Platform */ +#define ZP_DARWIN 104 +/** \brief Constant to define Symbian OS */ +#define ZP_SYMBIAN 105 +/** \brief Constant to define ZRTP BSD platform */ +#define ZP_BSD 107 + + +/** \brief Define Platform manually there */ +//#undefine ZRTP_PLATFORM + + +/** \brief Constant to define Big Endian Platform */ +#define ZBO_BIG_ENDIAN 0x4321 +/** \brief Constant to define Little Endian Platform */ +#define ZBO_LITTLE_ENDIAN 0x1234 + +/** \brief Define Platform Byte Order manually there */ +//#define ZRTP_BYTE_ORDER + +/** \brief Defines the max length in bytes of a binary SAS digest */ +#ifndef ZRTP_SAS_DIGEST_LENGTH +#define ZRTP_SAS_DIGEST_LENGTH 32 +#endif + +/** \brief Defines maximum number of ZRTP streams within one session */ +#ifndef ZRTP_MAX_STREAMS_PER_SESSION +#define ZRTP_MAX_STREAMS_PER_SESSION 2 +#endif + +/** + * \brief Allows to build libzrtp against external srtp encryption library + * + * The latest version of libzrtp, starting with 0.3.9, supplies a built-in mechanism for SRTP + * encryption. However, if for some reason during development it is neccesary to use an external + * library, this flag must be set. + */ +#ifndef ZRTP_USE_EXTERN_SRTP +#define ZRTP_USE_EXTERN_SRTP 0 +#endif + +/** + * \brief Build libzrtp with minimum stack usage + * + * Set to 1 you build libzrtp in environment with strong limitation of stack size (Mobile platforms + * or in kernel mode). When this flag is set, some static data allocation will be changed to + * dynamic. The size of these data doesn't matter in "regular" PC applications, but on mobile + * platforms and in kernel mode, where the stack size is critical, libzrtp must work with optimized + * data. + */ +#ifndef ZRTP_USE_STACK_MINIM +#define ZRTP_USE_STACK_MINIM 0 +#endif + +#ifndef ZRTP_USE_BUILTIN +#define ZRTP_USE_BUILTIN 1 +#endif + +#ifndef ZRTP_USE_BUILTIN_SCEHDULER +#define ZRTP_USE_BUILTIN_SCEHDULER 1 +#endif + +#ifndef ZRTP_USE_BUILTIN_CACHE +#define ZRTP_USE_BUILTIN_CACHE 1 +#endif + +#ifndef ZRTP_ENABLE_EC +#define ZRTP_ENABLE_EC 1 +#endif + +#ifndef ZRTP_DEBUG_WITH_PJSIP +#define ZRTP_DEBUG_WITH_PJSIP 0 +#endif + +/** + * \brief Set to 1 if you build libzrtp against libzrtp-s. + * + * CSD-mode was implemented to support new ZRTP/S protocol designed by KHAMSA SA, Via Giacometti 1, + * CH-6900, Lugano - info@khamsa.ch. and Phil Zimmermann. ZRTP/S allows to make secure ZRTP calls + * over CSD channels. This option affect enterprise version of the library only. + */ +#ifndef ZRTP_BUILD_FOR_CSD +#define ZRTP_BUILD_FOR_CSD 1 +#endif + +/** + * \brief Maximum number of Preshared exchanges allowed since last retain secret update + * + * Preshared key exchange mode has lot of weaknesses comparing to DH. And one of them - lack of key + * continuity. Preshared mode is not recommended unless there is a strong necessity in using it + * (slow CPU device, low-latency channel). + * + * To minimize risk of using Preshared exchanges, libzrtp automatically limits number for preshared + * connection available for the same instance of RS value. In other words, libzrtp forces DH exchange + * every \c ZRTP_PRESHARED_MAX_ALLOWED calls. + */ +#define ZRTP_PRESHARED_MAX_ALLOWED 20 + +/** + * \brief Defines libzrtp log-level + * + * Defines maximum log level for libzrtp: log-level 3 contains debug messages, 2 - warnings and + * software errors, 1 - security issues. If you set this option to 0 - libzrtp will not debug + * output and will not even make a log function calls. + */ +#ifndef ZRTP_LOG_MAX_LEVEL +#define ZRTP_LOG_MAX_LEVEL 3 +#endif + +/** + * \brief Enables SRTP debug output + * + * \warning! ZRTP crypto debug logs may include security sensitive information and cause security + * weakness in the system. Enable SRTP debug logging only when it necessary. + */ +#ifndef ZRTP_DEBUG_SRTP_KEYS +#define ZRTP_DEBUG_SRTP_KEYS 0 +#endif + +/** + * \brief Enables ZRTP Crypto debug logging. + * + * \warning! ZRTP crypto debug logs may include security sensitive information and cause security + * weakness in the system. Enable ZRTP Protocol debug logging only when it necessary. + */ +#ifndef ZRTP_DEBUG_ZRTP_KEYS +#define ZRTP_DEBUG_ZRTP_KEYS 0 +#endif + + +/* \} */ + +#endif /*__ZRTP_CONFIG_USER_H__*/ diff --git a/include/zrtp_config_win.h b/include/zrtp_config_win.h new file mode 100644 index 0000000000..a1b2a6802a --- /dev/null +++ b/include/zrtp_config_win.h @@ -0,0 +1,67 @@ +/* + * 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 + */ + +#ifndef ZRTP_WIN_CONFIG_H__ +#define ZRTP_WIN_CONFIG_H__ + +/* + * Used to map system integer types to zrtp integer definitions. + * Define to 1 if you have the header file. + */ +#undef ZRTP_HAVE_INTTYPES_H + +#define ZRTP_HAVE_STRING_H 1 + +/* + * This header is needed for operations with binary file in deefault realization + * of the secrets' cache. Can be eliminated if default cache isn't used. + * Define to 1 if you have the header file. + */ +#ifndef ZRTP_HAVE_STDIO_H +# define ZRTP_HAVE_STDIO_H 1 +#endif + +#ifndef ZRTP_HAVE_STDARG_H +# define ZRTP_HAVE_STDARG_H 1 +#endif + +/* + * Used by bnlib, but we don't need this on Windows platform. + */ +#ifndef NO_ASSERT_H + #define NO_ASSERT_H 1 +#endif + +/* + * Used by bnlib. We have stdlib in any Windows platform - set it to 1. + */ +#ifndef NO_STDLIB_H + #define NO_STDLIB_H 0 +#endif + + +#define ZRTP_HAVE_INT64_T 0 +#define ZRTP_HAVE_INT32_T 0 +#define ZRTP_HAVE_INT16_T 0 +#define ZRTP_HAVE_INT8_T 0 + +#define ZRTP_HAVE_UINT64_T 0 +#define ZRTP_HAVE_UINT32_T 0 +#define ZRTP_HAVE_UINT16_T 0 +#define ZRTP_HAVE_UINT8_T 0 + +#define SIZEOF_UNSIGNED_LONG 4 +#define SIZEOF_UNSIGNED_LONG_LONG 8 + +#define ZRTP_INLINE static __inline + +#define ZRTP_VERSION "0.90" + + +#endif /* ZRTP_WIN_CONFIG_H__ */ diff --git a/include/zrtp_crypto.h b/include/zrtp_crypto.h new file mode 100644 index 0000000000..b9bbee1edc --- /dev/null +++ b/include/zrtp_crypto.h @@ -0,0 +1,664 @@ +/* + * 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 + */ + +#ifndef __ZRTP_CRYPTO_H__ +#define __ZRTP_CRYPTO_H__ + +#include "bn.h" +#include "zrtp_types.h" +#include "zrtp_error.h" +#include "zrtp_engine.h" +#include "zrtp_config_user.h" + +#if (defined(ZRTP_ENABLE_EC) && (ZRTP_ENABLE_EC == 1)) +#include "zrtp_ec.h" +#endif + + + +/*! + * \defgroup crypto Library crypto-components + * \ingroup zrtp_dev + * + * This section describes functions and data types for managing crypto-components. + * All these functions and structures are used by the libZRTP kernel for the + * built-in crypt-components management. The developer has the option of + * implementing and integrating her own components into the library. This is not + * a full manual on creating crypto-components. Its purpose is only to elucidate + * the library functionality. + * + * The concept behind crypto components is similar to that of classes in object + * oriented programming. The components are defined as structures and + * manipulated by functions. Component attributes are stored in 'contexts', and + * are defined during initialization. Resources allocated at initialization are + * freed with the 'free' function. + * + * Components are divided into 5 functional groups (component types): + * - ciphers; + * - hash/hmac components; + * - public key exchange schemes; + * - components defined SRTP authentication scheme; + * - SAS calculation schemes. + * Within a group, components are distinguished by integer identifiers and by + * their defined functionality. So to fully identify a component, you need to + * know its type and its identifier. (For example an AES cipher with a 128 bit + * key is defined as: ZRTP_CC_CIPHER, zrtp_cipher_id_t::ZRTP_CIPHER_AES128). + * The high number of components means that every component must have a minimal + * set of attributes and functions: type identifier, and function initialization + * and deinitialization. The base type of all components is zrtp_comp_t. Every + * new component MUST start with definitions of this structure strictly in the + * given order. + * \warning + * Every crypto-component included in libZRTP was developed and tested by + * professionals. Its presence is functionally based. Using only the built-in + * components gives you 100% crypto-strength and the guarantee of the fully + * tested code. Never use your own components without strong reasons. If you + * have noticed the absence of any important component in the library, contact + * the developers. Reasonable offers will be considered for implementation in + * the following versions. + * \{ + */ + + +/*============================================================================*/ +/* Types of libZRTP crypto-components definitions */ +/*============================================================================*/ + +/*! + * \brief Enumeration for crypto-components types definition + */ +typedef enum zrtp_crypto_comp_t +{ + ZRTP_CC_HASH = 1, /*!< hash calculation schemes */ + ZRTP_CC_SAS = 2, /*!< short autentification scheme components */ + ZRTP_CC_CIPHER = 3, /*!< ciphers */ + ZRTP_CC_PKT = 4, /*!< public key exchange scheme */ + ZRTP_CC_ATL = 5, +}zrtp_crypto_comp_t; + + +/*! + * This ID with code 0 is used as an error signal by all crypto-components + * groups to indicate a wrongly defined component identifier. + */ +#define ZRTP_COMP_UNKN 0 + +/*! Defines types of hash functions */ +typedef enum zrtp_hash_id_t +{ + ZRTP_HASH_SHA256 = 1, + /** + * \note SHA1 hash algorithm is for internal use only! It used for srtp authentication and does + * not used in ZRTP protocol itself. Don't use it in \ref zrtp_profile_t#hash_schemes configuration. + */ + ZRTP_SRTP_HASH_SHA1 = 2, + ZRTP_HASH_SHA384 = 3 +} zrtp_hash_id_t; + +/*! Defines types of ciphers */ +typedef enum zrtp_cipher_id_t +{ + ZRTP_CIPHER_AES128 = 1, + ZRTP_CIPHER_AES256 = 2 +} zrtp_cipher_id_t; + +/*! Defines SRTP authentication schemes */ +typedef enum zrtp_atl_id_t +{ + ZRTP_ATL_HS32 = 1, + ZRTP_ATL_HS80 = 2 +} zrtp_atl_id_t; + +/*! Defines public key exchange schemes */ +/* WARNING! don't change order of the PK components definitions! */ +typedef enum zrtp_pktype_id_t +{ + ZRTP_PKTYPE_PRESH = 1, + ZRTP_PKTYPE_MULT = 2, + ZRTP_PKTYPE_DH2048 = 3, + ZRTP_PKTYPE_EC256P = 4, + ZRTP_PKTYPE_DH3072 = 5, + ZRTP_PKTYPE_EC384P = 6, + ZRTP_PKTYPE_EC521P = 7, + ZRTP_PKTYPE_DH4096 = 8 +} zrtp_pktype_id_t; + +/*! Defines modes of short authentication scheme calculation */ +typedef enum zrtp_sas_id +{ + ZRTP_SAS_BASE32 = 1, + ZRTP_SAS_BASE256 = 2 +} zrtp_sas_id_t; + + +/*! + * \brief Global structure for all crypto-component types. + * \warning All developed components must have these 4 fields at the beginning. + */ +typedef struct zrtp_comp_t +{ + zrtp_uchar4_t type; /*!< 4-character symbolic name defined by ZRTP Draft */ + uint8_t id; /*!< Integer component identifier */ + zrtp_global_t* zrtp;/*!< ZRTP global context */ + + /*! + * \brief Component initiation function. + * This function body is for holding component initialization code. libzrtp + * calls the function before using a component, at its registration. If the + * component does not require additional actions for initialization, the + * value of this field can be NULL. + * \param self - self-pointer for fast access to structure data. + * \return + * - zrtp_status_ok - if initialized successfully; + * - one of \ref zrtp_status_t errors - if initialization failed. + */ + zrtp_status_t (*init)(void* self); + + /*! + * \brief Component deinitializtion function. + * This function body is for holding component deinitialization code and + * all code for releasing allocated resources. libzrtp calls the function + * at the end of component use, at context deinitialization. If the component + * does not require additional actions for deinitialization, the value of + * this field can be NULL. + * \param self - pointer to component structure for deinitialization. + * \return + * - zrtp_status_ok - if deinitialized successfully; + * - one of \ref zrtp_status_t errors - if deinitialization failed. + */ + zrtp_status_t (*free)(void* self); +} zrtp_comp_t; + + +/*! + * \brief Structure for defining the hash-value computing scheme + * The ZRTP context field zrtp_stream#_hash is initialized by the given type + * value and used for all hash calculations within the ZRTP sessions. Having + * implemented a structure of this type, it is possible to integrate new hash + * calculation schemes into libzrtp. + */ +struct zrtp_hash_t +{ + zrtp_comp_t base; + + /*! + * \brief Begin hash computation with update support. + * The following set of functions ( zrtp_hash#hash_begin, zrtp_hash#hash_update, + * zrtp_hash#hash_end) implements a standard hash calculation scheme with + * accumulation. The functions perform the required actions to start + * calculations and to allocate hash-contexts for preserving intermediate + * results and other required information. The allocated context will be + * passed-to by the subsequent calls zrtp_hash#hash_update and zrtp_hash#hash_end. + * \param self - self-pointer for fast access to structure data + * \return + * - pointer to allocated hash-context if successful; + * - NULL if error. + */ + void* (*hash_begin)(zrtp_hash_t *self); + + /*! + * \brief Process more input data for hash calculation + * This function is called in the hash-building chain to obtain additional + * data that it then processes and recalculates intermediate values. + * \param self - self-pointer for fast access to structure data; + * \param ctx - hash-context for current hash-value calculation; + * \param msg - additional source data for processing; + * \param length - length of additional data in bytes. + * \return + * - zrtp_status_ok - if successfully processed; + * - one of \ref zrtp_status_t errors - if error. + */ + zrtp_status_t (*hash_update)( zrtp_hash_t *self, + void *ctx, + const int8_t*msg, + uint32_t length ); + + /*! + * \brief Completes the computation of the current hash-value + * This function completes the computation of the hash-value with accumul. + * After completion, the hash-context previously allocated by the call to + * zrtp_hash#hash_begin, must be destroyed. The size of the calculated + * value must be kept in the parameter digest field zrtp_string#length. + * \param self - self-pointer for fast access to structure data; + * \param ctx - hash-context for current hash-value calculation; + * \param digest - buffer for storing result. + * \return + * - zrtp_status_ok - if computing finished successfully; + * - one of \ref zrtp_status_t errors - if error. + */ + zrtp_status_t (*hash_end)( zrtp_hash_t *self, + void *ctx, + zrtp_stringn_t *digest ); + + /*! + * \brief Calculate hash-value for current message + * This function implicitly calls the previous 3 functions. The only + * difference is that initial data for hash value construction is gathered + * in a single buffer and is passed to the function in the \c msg argument. + * The calculated value size must be stored in the digest zrtp_string#length + * parameter + * \param self - self-pointer for fast access to structure data; + * \param msg - source data buffer for hash computing; + * \param digest - buffer for storing result. + * \return + * - zrtp_status_ok - if computing finished successfully; + * - one of \ref zrtp_status_t errors - if error. + */ + zrtp_status_t (*hash)( zrtp_hash_t *self, + const zrtp_stringn_t *msg, + zrtp_stringn_t *digest ); + + /*! \brief Analogue of zrtp_hash::hash for C-string */ + zrtp_status_t (*hash_c)( zrtp_hash_t *self, + const char* msg, + uint32_t msg_len, + zrtp_stringn_t *digest ); + + /*! + * \brief HASH self-test. + * This function implements hmac self-tests using pre-defined test vectors. + * \param self - self-pointer for fast access to structure data; + * \return + * - zrtp_status_ok - if tests have been passed successfully; + * - one of \ref zrtp_status_t errors - if one or more tests have + * failed. + */ + zrtp_status_t (*hash_self_test)(zrtp_hash_t *self); + + + /*! + * \brief Begin HMAC computation with update support. + * The zrtp_hash#hmac_begin, zrtp_hash#hmac_update and zrtp_hash#hmac_end + * functions implement the HMAC calculation scheme with accumulation. The + * function performs all actions required before beginning the calculation + * and allocates a hash-context to store intermediate values. The allocated + * hash-context will be passed to successive hash_update and hash_end calls + * \param self - self-pointer for fast access to structure data; + * \param key - secret key for hmac-value protection. + * \return + * - pointer to allocated hmac-context if successful; + * - NULL - if error. + */ + void* (*hmac_begin)(zrtp_hash_t *self, const zrtp_stringn_t *key); + + /*! \brief Analogue of zrtp_hash::hmac_begin for C-string */ + void* (*hmac_begin_c)(zrtp_hash_t *self, const char *key, uint32_t length); + + /*! + * \brief Process more input data for HMAC calculation + * This function is called to transfer additional data to the HMAC hash- + * calculation. Processes new data and recalculates intermediate values. + * \param self - self-pointer for fast access to structure data; + * \param ctx - hmac-context for current hmac-value calculation; + * \param msg - additional source data for processing; + * \param length - additional data length in bytes. + * \return + * - zrtp_status_ok - if successfully processed; + * - one of \ref zrtp_status_t errors - if error. + */ + zrtp_status_t (*hmac_update)( zrtp_hash_t *self, + void *ctx, + const char *msg, + uint32_t length ); + + /*! + * \brief Complete current HMAC-value computation + * This function completes the hmac calculation. After the final iteration + * \a the hash_context allocated by zrtp_hash#hmac_begin is destroyed. The + * argument \c len holds the HMAC size. If the buffer contains more than \c + * length characters then only the first \c length are copied to \c digest. + * The calculated value size is stored in the digest parameter length. + * \param self - self-pointer for fast access to structure data; + * \param ctx - hmac-context for current hmac-value calculation; + * \param digest - buffer for storing result; + * \param len - required hmac-value size. + * \return + * - zrtp_status_ok - if computing finished successfully; + * - one of \ref zrtp_status_t errors - if error. + */ + zrtp_status_t (*hmac_end)( zrtp_hash_t *self, + void *ctx, + zrtp_stringn_t *digest, + uint32_t len); + + /*! + * \brief Calculate hmac-value for current message + * The function implicitly calls the previous 3 functions + * (zrtp_hash#hmac_begin, zrtp_hash#hmac_update and zrtp_hash#hmac_end). The + * difference is that the initial data for hash value construction is + * gathered in a single buffer and is passed to the function in the \a msg + * argument. The calculated value size must be stored in the \a digest + * zrtp_string#length parameter + * \param self - self-pointer for fast access to structure data; + * \param key - key for protecting hmac; + * \param msg - source data buffer for hash computing; + * \param digest - buffer for storing result. + * \return + * - zrtp_status_ok - if computing finished successfully; + * - one of \ref zrtp_status_t errors - if error. + */ + zrtp_status_t (*hmac)( zrtp_hash_t *self, + const zrtp_stringn_t *key, + const zrtp_stringn_t *msg, + zrtp_stringn_t *digest ); + + /*! \brief Analogue of zrtp_hash::hmac for C-string */ + zrtp_status_t (*hmac_c)( zrtp_hash_t *self, + const char *key, + const uint32_t key_len, + const char *msg, + const uint32_t msg_len, + zrtp_stringn_t *digest ); + + /*! + * \brief Truncated Hmac-calculation version + * This function acts just like the previous \a hmac except it returns the + * first \a length bytes of the calculated value in the digest. + * \param self - self-pointer for fast access to structure data; + * \param key - key for hmac protection; + * \param msg - source data buffer for hash computing; + * \param digest - buffer for storing result; + * \param len - required hmac-value size. + * \return + * - zrtp_status_ok - if computed successfully; + * - one of \ref zrtp_status_t errors - if error. + */ + zrtp_status_t (*hmac_truncated)( zrtp_hash_t *self, + const zrtp_stringn_t *key, + const zrtp_stringn_t *msg, + uint32_t len, + zrtp_stringn_t *digest ); + + /*! \brief Analogue of zrtp_hash::hmac_truncated for C-string */ + zrtp_status_t (*hmac_truncated_c)( zrtp_hash_t *self, + const char *key, + const uint32_t key_len, + const char *msg, + const uint32_t msg_len, + uint32_t necessary_len, + zrtp_stringn_t *digest ); + + /*! + * \brief HMAC self-test. + * This function implements the hmac self-tests using pre-defined test vectors. + * \param self - self-pointer for fast access to structure data; . + * \return + * - zrtp_status_ok - if tests have passed successfully; + * - one of \ref zrtp_status_t errors - if one or more tests have failed. + */ + zrtp_status_t (*hmac_self_test)( zrtp_hash_t *self); + + uint32_t digest_length; + uint32_t block_length; + mlist_t mlist; +}; + + +/*! + * \brief Structure for defining the SRTP authentication scheme + * The ZRTP context field zrtp_stream#_authtaglength is initialized by the + * given type value and used for SRTP encryption configuration. + */ +struct zrtp_auth_tag_length_t +{ + zrtp_comp_t base; + uint32_t tag_length; + mlist_t mlist; +}; + + +/** + * @brief Structure for describing the public key scheme + * The ZRTP context field zrtp_stream#_pubkeyscheme is initialized by the given + * type value and used by libzrtp in public key exchange. + */ +struct zrtp_pk_scheme_t +{ + zrtp_comp_t base; + + /** Generate Diffie-Hellman secret value and Calculate public value */ + zrtp_status_t (*initialize)( zrtp_pk_scheme_t *self, + zrtp_dh_crypto_context_t *dh_cc ); + + /** Calculate Diffie-Hellman result (ZRTP Internet Draft) */ + zrtp_status_t (*compute)( zrtp_pk_scheme_t *self, + zrtp_dh_crypto_context_t *dh_cc, + struct BigNum *dhresult, + struct BigNum *pv); + + /** Validate Diffie-Hellman public value */ + zrtp_status_t (*validate)(zrtp_pk_scheme_t *self, struct BigNum *pv); + + /** Diffie-Hellman self-test routine. */ + zrtp_status_t (*self_test)(zrtp_pk_scheme_t *self); + + /** Diffie-Hellman secret value size in bytes */ + uint32_t sv_length; + + /** Diffie-Hellman public value size in bytes */ + uint32_t pv_length; + + mlist_t mlist; +}; + + +/*! + * \brief Structure for defining SAS generation scheme + * The type of the ZRTP context's field zrtp_stream#_sasscheme. It is used + * to generate short authentication strings. LibZRTP functionality can be augmented + * with a new SAS scheme by supplying your own instance of zrtp_sas_scheme. + */ +struct zrtp_sas_scheme_t +{ + zrtp_comp_t base; + + /*! + * \brief Generate short authentication strings + * This function computes SAS values according to the specified scheme. It + * can use base32 or base256 algorithms. It stores the generated SAS values + * as a zrtp_sas_values_t structure (string and binary representation). + * \param self - self-pointer for fast access to structure data; + * \param session - ZRTP session context for additional data; + * \param hash - hmac component to be used for SAS calculation; + * \param is_transferred - if this flag is equal to 1 new SAS value should + * not be computed. It is already in sas->bin buffer and rendering only + * is required. + * \return + * - zrtp_status_ok - if generation successful; + * - one of zrtp_status_t errors - if generation failed. + */ + zrtp_status_t (*compute)( zrtp_sas_scheme_t *self, + zrtp_stream_t *stream, + zrtp_hash_t *hash, + uint8_t is_transferred ); + + mlist_t mlist; +}; + + +#include "aes.h" + +/*! Defines block cipher modes. */ +typedef enum zrtp_cipher_mode_values_t +{ + ZRTP_CIPHER_MODE_CTR = 1, + ZRTP_CIPHER_MODE_CFB = 2 +} zrtp_cipher_mode_values_t; + +typedef struct zrtp_cipher_mode_t +{ + uint8_t mode; +} zrtp_cipher_mode_t; + + +/* \brief Structure for cipher definition */ +struct zrtp_cipher_t +{ + zrtp_comp_t base; + + /*! + * \brief Start cipher. + * This function performs all actions necessary to allocate the cipher context + * for holding intermediate results and other required information. The allocated + * context should be related to the given key. It will be passed to the + * zrtp_cipher#set_iv, zrtp_cipher#encrypt and zrtp_cipher#decrypt functions. + * \param self - self-pointer for fast access to structure data; + * \param key - cipher key; + * \param extra_data - additional data necessary for cipher initialization; + * \param mode - cipher mode (one of \ref zrtp_cipher_mode_values_t values). + * \return + * - pointer to allocated cipher context; + * - NULL if error. + */ + void* (*start)( zrtp_cipher_t *self, + void *key, + void *extra_data, uint8_t mode ); + + /*! + * \brief Set Initialization Vector. + * Function resets the previous state of the cipher context and sets the new IV. + * \param self - self-pointer for fast access to structure data; + * \param cipher_ctx - cipher context for current key value; + * \param iv - new initialization vector value. + * \return + * - zrtp_status_ok - if vector has been set successfully; + * - one of \ref zrtp_status_t errors - if operation failed. + */ + zrtp_status_t (*set_iv)( zrtp_cipher_t *self, + void *cipher_ctx, + zrtp_v128_t *iv ); + + /*! + * \brief Encrypt data. + * Implements the encryption engine. + * \param self - self-pointer for fast access to structure data; + * \param cipher_ctx - cipher context for current key value; + * \param buf - buffer with data for encryption. If successful this + * buffer contains the resulting encrypted text; + * \param len - length of plain/encrypted data. + * \return + * - zrtp_status_ok - if data has been encrypted successfully; + * - one of \ref zrtp_status_t errors - if encryption failed. + */ + zrtp_status_t (*encrypt)( zrtp_cipher_t *self, + void *cipher_ctx, + unsigned char *buf, + int len ); + + /*! + * \brief Decrypt data. + * Implements the decryption engine. + * \param self - self-pointer for fast access to structure data; + * \param cipher_ctx - cipher context for current key value; + * \param buf - buffer with data for decryption. If successful this buffer + * contains the resulting plain text; + * \param len - length of encrypted/plain data. + * \return + * - zrtp_status_ok - if data has been decrypted successfully; + * - one of \ref zrtp_status_t errors - if decryption failed. + */ + zrtp_status_t (*decrypt)( zrtp_cipher_t *self, + void *cipher_ctx, + unsigned char *buf, + int len ); + + /*! + * \brief Cipher self-test. + * Implements cipher self-tests using pre-defined test vectors. + * \param self - self-pointer for fast access to structure data; + * \param mode - cipher mode (one of \ref zrtp_cipher_mode_values_t values). + * \return + * - zrtp_status_ok - if tests have passed successfully; + * - one of \ref zrtp_status_t errors - if one or more tests have failed. + */ + zrtp_status_t (*self_test)(zrtp_cipher_t *self, uint8_t mode); + + /*! + * \brief Destroy cipher context. + * Deallocs the cipher context previously allocated by a call to zrtp_cipher#start. + * \param self - self-pointer for fast access to structure data; + * \param cipher_ctx - cipher context for current key value. + * \return + * - zrtp_status_ok - if the context has been deallocated + * successfully; + * - one of \ref zrtp_status_t errors - if deallocation failed. + */ + zrtp_status_t (*stop)(zrtp_cipher_t *self, void* cipher_ctx); + + mlist_t mlist; +}; + +#if defined(__cplusplus) +extern "C" +{ +#endif + + +/*============================================================================*/ +/* Crypto-components management Private part */ +/*============================================================================*/ + + +/*! + * \brief Destroy components buffer + * This function clears the list of components of the specified type, destroys + * all components and releases all allocated resources. It is used on libzrtp + * down. zrtp_comp_done calls zrtp_comp_t#free() if it isn't NULL. + * \param zrtp - the ZRTP global context where components are stored; + * \param type - specifies the component pool type for destroying. + * \return + * - zrtp_status_ok - if clearing successful; + * - zrtp_status_fail - if error. + */ +zrtp_status_t zrtp_comp_done(zrtp_crypto_comp_t type, zrtp_global_t* zrtp); + +/*! + * \brief Registering a new crypto-component + * Correctness of values in the necessary structure is the developer's + * responsibility. zrtp_comp_register calls zrtp_comp_t#init() if it isn't NULL. + * \param type - type of registred component; + * \param comp - registered crypto-component; + * \param zrtp - the ZRTP global context where components are stored. + * \return + * - zrtp_status_ok if registration successful; + * - zrtp_status_fail if error (conflicts with other components). + */ +zrtp_status_t zrtp_comp_register( zrtp_crypto_comp_t type, + void *comp, + zrtp_global_t* zrtp); + +/*! + * \brief Search component by ID + * \param type - type of sought component; + * \param zrtp - the ZRTP global context where components are stored; + * \param id - integer identifier of the necessary element. + * \return + * - the found structure if successful; + * - NULL if the element with the specified ID can't be found or + * other error. + */ +void* zrtp_comp_find( zrtp_crypto_comp_t type, + uint8_t id, + zrtp_global_t* zrtp); + + +/*! Converts a component's integer ID to a symbolic ZRTP name */ +char* zrtp_comp_id2type(zrtp_crypto_comp_t type, uint8_t id); + +/*! Converts a component's ZRTP symbolic name to an integer ID */ +uint8_t zrtp_comp_type2id(zrtp_crypto_comp_t type, char* name); + + +/*! \} */ + +#if defined(__cplusplus) +} +#endif + +#endif /*__ZRTP_CRYPTO_H__ */ diff --git a/include/zrtp_engine.h b/include/zrtp_engine.h new file mode 100644 index 0000000000..8b818dee2d --- /dev/null +++ b/include/zrtp_engine.h @@ -0,0 +1,387 @@ +/* + * 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 + */ + + +#ifndef __ZRTP_ENGINE_H__ +#define __ZRTP_ENGINE_H__ + +#include "zrtp_config.h" +#include "zrtp_types.h" +#include "zrtp_crypto.h" + + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/** + * @defgroup engine_dev ZRTP Engine related types and functions + * @ingroup zrtp_dev + * \{ + */ + +#define ZRTP_IS_STREAM_DH(stream) \ +(stream->mode == ZRTP_STREAM_MODE_DH) + +#define ZRTP_IS_STREAM_FAST(stream) \ +(stream->mode != ZRTP_STREAM_MODE_DH) + +#define ZRTP_IS_STREAM_MULT(stream) \ +(stream->mode == ZRTP_STREAM_MODE_MULT) + +#define ZRTP_IS_STREAM_PRESH(stream) \ +(stream->mode == ZRTP_STREAM_MODE_PRESHARED) + + +/** + * @brief Test Passive Rule N1 + * A passive endpoint never sends a Commit message. Semi-active endpoint does + * not send a commit to a passive endpoint. + * Return 1 if the tast have been passed successfully and 0 in other case. + */ +#define ZRTP_PASSIVE1_TEST(stream) \ +( (ZRTP_LICENSE_MODE_UNLIMITED == stream->zrtp->lic_mode) || \ + ((ZRTP_LICENSE_MODE_ACTIVE == stream->zrtp->lic_mode) && (!stream->messages.peer_hello.pasive)) ) + +/** + * @brief Test Passive Rule N2 + * A passive phone, if acting as a SIP initiator (meaning it initiated the call), + * rejects all commit packets from everyone. + * Return 1 if the tast have been passed successfully and 0 in other case + */ +#define ZRTP_PASSIVE2_TEST(stream) \ +( !((ZRTP_LICENSE_MODE_PASSIVE == stream->zrtp->lic_mode) && \ + stream->session->is_initiator) ) + +/** + * @brief Test Passive Rule N3 + * A passive phone rejects all commit messages from a PBX. + * Return 1 if the tast have been passed successfully and 0 in other case + */ +#define ZRTP_PASSIVE3_TEST(stream) \ +( !(!stream->zrtp->is_mitm && stream->peer_mitm_flag && \ + (ZRTP_LICENSE_MODE_PASSIVE == stream->zrtp->lic_mode)) ) + + +/*===========================================================================*/ +/* PROTOCOL Logic */ +/*===========================================================================*/ + +/** + * @brief Allocate ZRTP protocol structure + * Allocates and initializes all necessary data according to the protocol mode. + * Initializes required DH crypto context info and generates secret IDs. + * @param stream - stream context in which protocol should be allocated; + * @param is_initiator - defines protocol type (1 - initiator, 0 - responder). + * @exception SOFTWARE exceptions. + */ +zrtp_status_t _zrtp_protocol_init( zrtp_stream_t *stream, + uint8_t is_initiator, + zrtp_protocol_t **proto); + +/** + * @brief Release protocol structure + * Stops all replay tasks, clears all crypto sources and SRTP engine, and + * releases memory. The protocol should be destroyed on: stream closing, or + * switching to CLEAR or ERROR states. + */ +void _zrtp_protocol_destroy(zrtp_protocol_t *proto); + +/** + * @brief Encrypts RTP/RTCP media + * After switching to Secure, the protocol structure is able to encrypt + * media using the SRTP crypto-engine. + * @param self - self-pointer to protocol instance; + * @param packet - media packet for encryption; + * @param is_rtp - defines type of media for encryption; value equal to 1 + * means RTP packet, 0 - RTCP. + * @return + * - zrtp_status_ok - if successfully encrypted; + * - one of zrtp_status_t errors otherwise. + */ +zrtp_status_t _zrtp_protocol_encrypt( zrtp_protocol_t *proto, + zrtp_rtp_info_t *packet, + uint8_t is_rtp); + +/** + * @brief Decrypts RTP/RTCP media + * After switching to Secure, the protocol structure is able to decrypt + * media using the SRTP crypto-engine. + * @param self - self-pointer to protocol instance; + * @param packet - media packet for decryption; + * @param is_rtp - defines type of media for decryption; value equal to 1 + * means RTP packet, 0 - RTCP. + * @return + * - zrtp_status_ok - if successfully decrypted; + * - one of zrtp_status_t errors otherwise. + */ +zrtp_status_t _zrtp_protocol_decrypt( zrtp_protocol_t *self, + zrtp_rtp_info_t *packet, + uint8_t is_rtp); + + +/*===========================================================================*/ +/* CRTPTO Utilites */ +/*===========================================================================*/ + +/** + * ZRTP KDF function. + * KDF(KI, Label, Context, L) = HMAC(KI, i | Label | 0x00 | Context | L). See + * Section "4.5.1. The ZRTP Key Derivation Function" in ZRTP RFC for more info. + * @param stream - used to obtain negotiated HMAC function and other parameters; + * @param ki- secret key derivation key that is unknown to the wiretapper + * (for example, s0); + * @param label - string of nonzero octets that identifies the purpose for the + * derived keying material; + * @param context - includes ZIDi, ZIDr, and some optional nonce material; + * @param length - needed digest length. (The output of the KDF is truncated to + * the leftmost length bits); + * @param digest - destination buffer. + */ +zrtp_status_t _zrtp_kdf( zrtp_stream_t* stream, + zrtp_stringn_t* ki, + zrtp_stringn_t* label, + zrtp_stringn_t* context, + uint32_t length, + zrtp_stringn_t* digest); + +/*! + * \brief Allocate shared secret structure + * This function allocates memory for a zrtp_shared_secret_t and initializes + * the secret value using a zrtp_fill_shared_secret() function call. Used in + * protocol allocating. + * \param session - ZRTP session for access to global data. + * \return + * - allocated secrets - on success; + * - NULL - if allocation fails. + */ +zrtp_shared_secret_t *_zrtp_alloc_shared_secret(zrtp_session_t* session); + +/*! + * \brief Restores secrets from the cache + * Uploads retained secrets from the cache and initializes secret flags. If + * the secret has expired (is_expired flag is set), its value will be randomly + * regenerated. _zrtp_prepare_secrets() is called after the discovery phase on + * the setting up the very first stream. After secrets are uploaded the + * zrtp_secrets_t#_is_ready flag is enabled to prevent secrets from reinitialization + * on setting up the next stream. + * \param session - ZRTP session in which secrets should be restored. + * - zrtp_status_ok - if secrets were restored successfully; + * - one of zrtp_status_t errors in case of failure. + */ +zrtp_status_t _zrtp_prepare_secrets(zrtp_session_t* session); + +/** + * @brief Validate confirm chmac message. + * In case of chmac failure it switches to Initiating Error state and generate + * ZRTP_EVENT_WRONG_MESSAGE_HMAC security event. + * @return + * -1 - in case of error and 0 - on success. + */ +int _zrtp_validate_message_hmac(zrtp_stream_t *stream, zrtp_msg_hdr_t* msg2check, char* hmackey); + +/** + * @brief Computes preshared key using available secrets. + * hash(len(rs1) | rs1 | len(auxsecret) | auxsecret | len(pbxsecret) | pbxsecret) + * Result key stored in key variable, if key_id not NULL - hmac + * of the preshared_key will be stored. + * return + * - zrtp_status_ok on success and one of libzrtp errors in case of failure + */ +zrtp_status_t _zrtp_compute_preshared_key( zrtp_session_t *session, + zrtp_stringn_t* rs1, + zrtp_stringn_t* auxs, + zrtp_stringn_t* pbxs, + zrtp_stringn_t* key, + zrtp_stringn_t* key_id); + +/** @brief Perform Key generation according to ZRTp RFC sec. 5.6 */ +zrtp_status_t _zrtp_set_public_value(zrtp_stream_t *stream, int is_initiator); + + +/*===========================================================================*/ +/* PROTOCOL Utilites */ +/*===========================================================================*/ + +/*! + * \brief Check availability to start stream (DH or Preshared) + * The ZRTP specification says that only one DH stream can be run at a time between + * two ZRTP endpoints. So _zrtp_can_start_stream(DH) looks over all sessions + * between two ZIDs and if any other stream is running it denies the start of + * another DH stream in parallel. Although the ZRTP standard says that Preshared + * or Multistream stream can't be run in parallel with DH streams between two + * ZRTP endpoints. So _zrtp_can_start_stream(PRESH) looks over all sessions between + * two ZIDs and if any other DH stream is running it denies the start of + * Preshared/Multistream stream in parallel. All operations with sessions and + * streams are protected by mutexes. Call this function every time before starting + * "initiating secure" process. For internal use only. + * \sa "break the tie schemes" internal document. + * \param stream - ZRTP stream which going to be started; + * \param conc - in this variable _zrtp_can_start_stream() returns pointer to the + * concurrent DH stream if it's in progress. It's used in "breaking the tie" + * scheme. + * \param mode - stream mode. + * \return + * - 1 if stream can be started; + * - 0 - if stream can't be started and should wait for concurrent stream + * establishment. + */ +int _zrtp_can_start_stream( zrtp_stream_t* stream, + zrtp_stream_t** conc, + zrtp_stream_mode_t mode); + +/** Return ZRTP Stream mode which sould be used for current stream. */ +zrtp_stream_mode_t _zrtp_define_stream_mode(zrtp_stream_t* stream); + +/*! + * \brief Chooses the best crypto component of the given type + * Selects the crypto component according to the local initiator's profile and + * the remote responder's Hello. + * \param profile - local profile; + * \param peer_hello - Hello packet, received from the remote peer; + * \param type - type of the crypto component to be chosen. + * \return: + * - identifier of the chosen component (according to type); + * - ZRTP_COMP_UNKN in case of error. + */ +uint8_t _zrtp_choose_best_comp( zrtp_profile_t* profile, + zrtp_packet_Hello_t* peer_hello, + zrtp_crypto_comp_t type); + +/*! + * \brief Computes replay timeouts + * This function computes messages replays schedule. There are some recomended + * values by ZRTP specification, but in some network environments values may be + * sligh different + */ +uint32_t _zrtp_get_timeout(uint32_t curr_timeout, zrtp_msg_type_t msg); + + +/*! + * \brief Terminates retransmission task + * This function is a wrapper around zrtp_cancele_send_packet_later() which + * unsets the zrtp_retry_task_t#_is_enabled flag to prevent the scheduler from + * re-adding tasks after their termination. + */ +void _zrtp_cancel_send_packet_later( zrtp_stream_t* stream, + zrtp_msg_type_t type); + +/*! + * \brief state switcher + * This function changes stream state to \c state, makes a backup of the previous + * state at zrtp_stream_t#_prev_state and prints debug information. + * \warning Don't change the stream state directly. Use this function. + * \param stream - ZRTP stream to be changed; + * \param state - new state. + */ +void _zrtp_change_state( zrtp_stream_t* stream, zrtp_state_t state); + + +/*===========================================================================*/ +/* Shared STATE-MACHINE Routine */ +/*===========================================================================*/ + +// TODO: clean this up +zrtp_status_t _zrtp_machine_enter_pendingsecure(zrtp_stream_t* stream, zrtp_rtp_info_t* commit); +zrtp_status_t _zrtp_machine_enter_initiatingsecure(zrtp_stream_t* stream); +zrtp_status_t _zrtp_machine_enter_secure(zrtp_stream_t* stream); +zrtp_status_t _zrtp_machine_enter_pendingclear(zrtp_stream_t* stream); +zrtp_status_t _zrtp_machine_enter_initiatingerror( zrtp_stream_t *stream, + zrtp_protocol_error_t code, + uint8_t notif); + +zrtp_status_t _zrtp_machine_create_confirm(zrtp_stream_t *stream, zrtp_packet_Confirm_t* confirm); +zrtp_status_t _zrtp_machine_process_confirm(zrtp_stream_t *stream, zrtp_packet_Confirm_t *confirm); +zrtp_status_t _zrtp_machine_process_goclear(zrtp_stream_t* stream, zrtp_rtp_info_t* packet); + +zrtp_status_t _zrtp_machine_start_initiating_secure(zrtp_stream_t *stream); +zrtp_statemachine_type_t _zrtp_machine_preparse_commit(zrtp_stream_t *stream, zrtp_rtp_info_t* packet); + + +/*===========================================================================*/ +/* PARSERS */ +/*===========================================================================*/ + +/*! + * \brief Prepare RTP/ZRTP media packet for the further processing. + * This function defines the packet type, parses SSRC and makes the sequence + * number implicit. If it is a ZRTP message, packet length correctness and CRC + * are checked as well. + * \param stream - ZRTP stream associated with this packet; + * \param packet - packet for preparing; + * \param length - packet length; + * \param info - resulting packet structure; + * \param is_input - 1 - assumes incoming and 0 - outgoing packet direction. + */ +zrtp_status_t _zrtp_packet_preparse( zrtp_stream_t* stream, + char* packet, + uint32_t *length, + zrtp_rtp_info_t* info, + uint8_t is_input); + +/*! + * \brief Fills ZRTP message header and computes messages HMAC + * _zrtp_packet_fill_msg_hdr() prepares a ZRTP message header for sending. It calculates + * the total message length in 4-byte words and fills the message type block. + * \param stream - stream within in the operation will be performed + * \param type - ZRTP message type; + * \param body_length - message body length (without header); + * \param hdr - message ZRTP header + * \return + * - zrtp_status_ok - if success; + * - zrtp_status_bad_param - if message \c type is unknown. + */ +zrtp_status_t _zrtp_packet_fill_msg_hdr( zrtp_stream_t *stream, + zrtp_msg_type_t type, + uint16_t body_length, + zrtp_msg_hdr_t *hdr); + +/** + * @brief Sends ZRTP message onto the network + * _zrtp_packet_send_message constructs a ZRTP header and prepares packet for sending, + * computes CRC and injects the packet into the network using the interface + * function zrtp_send_rtp(). + * @param ctx - ZRTP stream context; + * @param type - packet type to construct primitive ZRTP messages; + * @param message - ZRTP message for sending. + * @return + * - 0 - if sent successfully; + * - -1 - if error. + */ +int _zrtp_packet_send_message( zrtp_stream_t *stream, + zrtp_msg_type_t type, + const void *message); + +/** @brief Returns ZRTP message type by symbolic name in header. */ +zrtp_msg_type_t _zrtp_packet_get_type(ZRTP_UNALIGNED(zrtp_rtp_hdr_t)*hdr, uint32_t length); + +/** + * @brief Insert CRC32 to ZRTP packets + * This function computes the 32 bit ZRTP packet checksum according to RFC 3309. + * As specified at ZRTP RFC, CRC32 is appended to the end of the extension for every ZRTP packet. + * @param packet - zrtp packet wrapper structure. + */ +void _zrtp_packet_insert_crc(char* packet, uint32_t length); + +/** + * @brief Validate ZRTP packet CRC + * @return + * - 0 if correct CRC; + * - -1 if CRC validation failed. + */ +int8_t _zrtp_packet_validate_crc(const char* packet, uint32_t length); + +/* \} */ + +#if defined(__cplusplus) +} +#endif + +#endif /* __ZRTP_ENGINE_H__ */ diff --git a/include/zrtp_error.h b/include/zrtp_error.h new file mode 100644 index 0000000000..a50b68ba9f --- /dev/null +++ b/include/zrtp_error.h @@ -0,0 +1,136 @@ +/* + * 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 + */ + + +/** + * \file zrtp_error.h + * \brief libzrtp errors definitions + */ + +#ifndef __ZRTP_ERROR_H__ +#define __ZRTP_ERROR_H__ + +#include "zrtp_config.h" + +/** + * \defgroup zrtp_errors Libzrtp Error Definitions + * + * In this section the ZRTP protocol error codes and the library internal errors are defined. + * + * When ZRTP Protocl error detected, zrtp_callback_event_t#on_zrtp_security_event is called and + * zrtp_session_info_t#last_error contains error code. + * \{ + */ + +/** + * \brief Define protocol error codes according to ZRTP RFC sec. 5.9 + */ +typedef enum zrtp_protocol_error_t +{ + zrtp_error_unknown = 0, + zrtp_error_timeout = 1, + + zrtp_error_invalid_packet = 0x10, /** Malformed packet (CRC OK, but wrong structure) */ + zrtp_error_software = 0x20, /** Critical software error */ + zrtp_error_version = 0x30, /** Unsupported ZRTP version */ + zrtp_error_hello_mistmatch = 0x40, /** Hello components mismatch */ + + zrtp_error_hash_unsp = 0x51, /** Hash type not supported */ + zrtp_error_cipher_unsp = 0x52, /** Cipher type not supported */ + zrtp_error_pktype_unsp = 0x53, /** Public key exchange not supported */ + zrtp_error_auth_unsp = 0x54, /** SRTP auth. tag not supported */ + zrtp_error_sas_unsp = 0x55, /** SAS scheme not supported */ + zrtp_error_no_secret = 0x56, /** No shared secret available, Preshared mode required */ + + zrtp_error_possible_mitm1 = 0x61, /** DH Error: bad pvi or pvr ( == 1, 0, or p-1) */ + zrtp_error_possible_mitm2 = 0x62, /** DH Error: hvi != hashed data */ + zrtp_error_possible_mitm3 = 0x63, /** Received relayed SAS from untrusted MiTM */ + + zrtp_error_auth_decrypt = 0x70, /** Auth. Error: Bad Confirm pkt HMAC */ + zrtp_error_nonse_reuse = 0x80, /** Nonce reuse */ + zrtp_error_equal_zid = 0x90, /** Equal ZIDs in Hello */ + zrtp_error_service_unavail = 0xA0, /** Service unavailable */ + zrtp_error_goclear_unsp = 0x100,/** GoClear packet received, but not allowed */ + + zrtp_error_wrong_zid = 0x202, /** ZID received in new Hello doesn't equal to ZID from the previous stream */ + zrtp_error_wrong_meshmac = 0x203, /** Message HMAC doesn't match with pre-received one */ + zrtp_error_count +} zrtp_protocol_error_t; + +/** + * \brief libzrtp functions statuses. + * + * Note that the value of zrtp_status_ok is equal to zero. This can simplify error checking + * somewhat. + */ +typedef enum zrtp_status_t +{ + zrtp_status_ok = 0, /** OK status */ + zrtp_status_fail = 1, /** General, unspecified failure */ + zrtp_status_bad_param = 2, /** Wrong, unsupported parameter */ + zrtp_status_alloc_fail = 3, /** Fail allocate memory */ + zrtp_status_auth_fail = 4, /** SRTP authentication failure */ + zrtp_status_cipher_fail = 5, /** Cipher failure on RTP encrypt/decrypt */ + zrtp_status_algo_fail = 6, /** General Crypto Algorithm failure */ + zrtp_status_key_expired = 7, /** SRTP can't use key any longer */ + zrtp_status_buffer_size = 8, /** Input buffer too small */ + zrtp_status_drop = 9, /** Packet process DROP status */ + zrtp_status_open_fail = 10, /** Failed to open file/device */ + zrtp_status_read_fail = 11, /** Unable to read data from the file/stream */ + zrtp_status_write_fail = 12, /** Unable to write to the file/stream */ + zrtp_status_old_pkt = 13, /** SRTP packet is out of sliding window */ + zrtp_status_rp_fail = 14, /** RTP replay protection failed */ + zrtp_status_zrp_fail = 15, /** ZRTP replay protection failed */ + zrtp_status_crc_fail = 16, /** ZRTP packet CRC is wrong */ + zrtp_status_rng_fail = 17, /** Can't generate random value */ + zrtp_status_wrong_state = 18, /** Illegal operation in current state */ + zrtp_status_attack = 19, /** Attack detected */ + zrtp_status_notavailable = 20, /** Function is not available in current configuration */ + zrtp_status_count = 21 +} zrtp_status_t; + +/** \} */ + +/** \manonly */ + +#define ZRTP_MIM2_WARNING_STR \ + "Possible Man-In-The-Middle-Attack! Switching to state Error\n"\ + "because a packet arrived that was ZRTP_DHPART2, but contained\n"\ + "a g^y that didn't match the previous ZRTP_COMMIT.\n" + +#define ZRTP_MITM1_WARNING_STR "DH validating failed. (pvi is 1 or p-1), aborted\n" + +#define ZRTP_VERIFIED_INIT_WARNING_STR \ + "Falling back to cleartext because a packet arrived that was\n"\ + "ZRTP_CONFIRM1, but which couldn't be verified - the sender must have a different\n"\ + "shared secret than we have.\n" + +#define ZRTP_VERIFIED_RESP_WARNING_STR \ + "Falling back to cleartext because a packet arrived that was ZRTP_CONFIRM2,\n"\ + " but which couldn't be verified - the sender must have a different shared secret than we have.\n" + +#define ZRTP_EQUAL_ZID_WARNING_STR \ + "Received a ZRTP_HELLO packet with the same ZRTP ID that we have.\n"\ + " This is likely due to a bug in the software. Ignoring the ZRTP_HELLO\n"\ + " packet, therefore this call cannot be encrypted.\n" + +#define ZRTP_UNSUPPORTED_COMP_WARNING_STR \ + " Received ZRTP_HELLO packet with an algorithms field which had a\n"\ + " list of hashes that didn't include any of our supported hashes. Ignoring\n"\ + " the ZRTP_HELLO packet, therefore this call cannot be encrypted.\n" + +#define ZRTP_NOT_UNIQUE_NONCE_WARNING_STR \ + " Received COMMIT with hash value already used in another stream within this ZRTP session\n" + +#define ZRTP_RELAYED_SAS_FROM_NONMITM_STR \ +" Received SAS Relaying message from endpoint which haven't introduced as MiTM.\n" + +/** \endmanonly */ + +#endif /* __ZRTP_ERROR_H__ */ diff --git a/include/zrtp_iface.h b/include/zrtp_iface.h new file mode 100644 index 0000000000..e8de27fb3b --- /dev/null +++ b/include/zrtp_iface.h @@ -0,0 +1,692 @@ +/* + * 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 + */ + + + +/** + * \file zrtp_iface.h + * \brief libzrtp product-dependent functions + */ + +#ifndef __ZRTP_IFACE_H__ +#define __ZRTP_IFACE_H__ + +#include "zrtp_config.h" +#include "zrtp_base.h" +#include "zrtp_string.h" +#include "zrtp_error.h" +#include "zrtp_iface_system.h" + + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/*======================================================================*/ +/* libzrtp interface: Cache */ +/*======================================================================*/ + +/*! + * \defgroup zrtp_iface_cache ZRTP Cache + * \ingroup zrtp_iface + * + * The secret cache implementation should have a two-layer structure: each pair of ZIDs should have + * a relevant pair of secrets (current and previous). In addition to the value of the secret, the + * cache should contain: verification flag, last usage time-stamp and cache TTL value. + * + * The simplest secret cache scheme implementation is: + * \code + * [local_ZID][remote_ZID][curr_cache][prev_cache][verified][used at][cache ttl] + * \endcode + * \warning + * Libzrtp doen't provide synchronization for cache read/write operation. Cache is not thread safe + * by default. Implementor must take care of synchronization inside his implementation. + * + * For more information see corresponding section \ref XXX. Samples can be found at \ref XXX + * (\c zrtp_iface_builtin.h, \c zrtp_iface_cache.c) + * \{ + */ + +/** + * @brief Data types and functions related to shared secrets. + */ +typedef struct zrtp_callback_cache_t +{ + /** + * \brief Cache initialization. + * + * libzrtp calls this function before start using cache routine at zrtp_init(). + * + * \param zrtp - libzrtp global context; + * \sa zrtp_callback_cache_t#on_down() + */ + zrtp_status_t (*on_init)(zrtp_global_t* zrtp); + + /** + * \brief Cache deinitialization. + * + * libzrtp calls this function when zrtp cache is no longer needed at zrtp_down(). + * \sa zrtp_callback_cache_t#on_init() + */ + void (*on_down)(); + + /** + * \brief Add/Update cache value + * + * Interface function for entering the retained secret to the cache. This function should + * guarantee permanent storage in the cache. The implementation algorithm is the following: + * - if the entry associated with a given pair of ZIDs does not exist, the value should be + * stored in cache. + * - if the entry already exists, the current secret value becomes stored as the previous one. + * The new value becomes stored as the current one. Besides rss->value a timestamp + * (rss->lastused_at) and cache TTL(rss->ttl) should be updated. + * + * \param one_zid - ZID of one side; + * \param another_zid - ZID of the other side; + * \param rss - a structure storing the value of the secret that needs to be saved. + * \return + * - zrtp_status_ok if operation is successful; + * - some error code from \ref zrtp_status_t in case of error. + * \sa zrtp_callback_cache_t#on_get + */ + zrtp_status_t (*on_put)( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + zrtp_shared_secret_t *rss); + + /** + * \brief Return secret cache associated with specified pair of ZIDs. + * + * This function should return the secret associated with the specified pair of ZIDs. In + * addition to the secret value, TTL (rss->ttl) and cache timestamp (rss->lastused_at) value + * should be also returned. + * + * \param one_zid - one side's ZID; + * \param another_zid - the other side's ZID; + * \param prev_requested - if this parameter value is 1, the function should return the previous + * secret's value. If this parameter value is 0, the function should return the current + * secret's value; + * \param rss - structure that needs to be filled in. + * \return + * - zrtp_status_ok - if operation is successful; + * - zrtp_status_fail - if the secret cannot be found; + * - some error code from zrtp_status_t if an error occurred. + * \sa zrtp_callback_cache_t#on_put + */ + zrtp_status_t (*on_get)( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + zrtp_shared_secret_t *rss, + int prev_requested); + + /** + * \brief Set/clear cache verification flag + * + * This function should set the secret verification flag associated with a pair of ZIDs. + * \warning + * For internal use only. To change the verification flag from the user space use the + * zrtp_verified_set() function. + * + * \param one_zid - first ZID for cache identification; + * \param another_zid - second ZID for cache identification; + * \param verified - verification flag (value can be 0 or 1). + * \return + * - zrtp_status_ok if flag is successfully modified; + * - zrtp_status_fail if the secret cannot be found; + * - some other error code from \ref zrtp_status_t if another error occurred. + */ + zrtp_status_t (*on_set_verified)( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + uint32_t verified); + + /** + * \brief Return cache verification flag + * + * This function return the secret verification flag associated with a pair of ZIDs. + * + * \param one_zid - first ZID for cache identification; + * \param another_zid - second ZID for cache identification; + * \param verified - verification flag to be filled in + * \return + * - zrtp_status_ok if flag is successfully returned; + * - zrtp_status_fail if the secret cannot be found; + * - some other error code from \ref zrtp_status_t if another error occurred. + */ + zrtp_status_t (*on_get_verified)( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + uint32_t* verified); + + /** + * \brief Should set Secure Since cache aparemeter to current date and time + * + * This function is optional and may be ommited. + * + * \param one_zid - first ZID for cache identification; + * \param another_zid - second ZID for cache identification; + * \return + * - zrtp_status_ok if the oprtation finished sucessfully. + * - some other error code from \ref zrtp_status_t if another error occurred. + */ + zrtp_status_t (*on_reset_since)( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid); + + /** + * \brief Add/Update cache value for MiTM endpoint + * + * This function is analogy to zrtp_callback_cache_t#on_put but for MiTM endpoint. + * \todo Add more detail description + * \sa zrtp_callback_cache_t#on_put zrtp_callback_cache_t#on_get_mitm + */ + zrtp_status_t (*on_put_mitm)( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + zrtp_shared_secret_t *rss); + + /** + * \brief Return secret cache for MiTM endpoint + * + * This function is analogy to zrtp_callback_cache_t#on_get but for MiTM endpoint. + * \todo Add more detail description + * \sa zrtp_callback_cache_t#on_get zrtp_callback_cache_t#on_put_mitm + */ + zrtp_status_t (*on_get_mitm)( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + zrtp_shared_secret_t *rss); + + /** + * \brief Return Preshared calls counter + * + * This function should return the preshared calls counter associated with a pair of ZIDs. + * + * \param one_zid - first ZID for cache identification; + * \param another_zid - second ZID for cache identification; + * \param counter - preshared calls counter to be filled in + * \return + * - zrtp_status_ok if counter is successfully returned; + * - zrtp_status_fail if the secret cannot be found; + * - some other error code from \ref zrtp_status_t if another error occurred. + */ + zrtp_status_t (*on_presh_counter_get)( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + uint32_t* counter); + + /** + * \brief Increase/reset Preshared streams counter made between two endpoints (ZIDs) + * + * This function should set the preshared calls counter associated with a pair of ZIDs. + * Function is optional and should be implemented if your prodict uses Preshared keys exchange. + * + * \param one_zid - first ZID for; + * \param another_zid - second ZID; + * \param counter - Preshared calls counter. + * \return + * - zrtp_status_ok if the counter is successfully modified; + * - zrtp_status_fail if the secret cannot be found; + * - some other error code from \ref zrtp_status_t if another error occurred. + */ + zrtp_status_t (*on_presh_counter_set)( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + uint32_t counter); +} zrtp_callback_cache_t; + + +/** \} */ + +/*======================================================================*/ +/* libzrtp interface: Scheduler */ +/*======================================================================*/ + +/** + * \defgroup zrtp_iface_scheduler ZRTP Delay Calls + * \ingroup zrtp_iface + * + * Algorithm used in the scheduled call module is described in detail in section \ref XXX of the + * developer's guide documentation. Technical details of this function's implementation follows. + * + * For more information see corresponding section \ref XXX. Samples can be found at \ref XXX + * (\c zrtp_iface_builtin.h, \c zrtp_iface_scheduler.c) + * \{ + */ + +/** \brief ZRTP Delays Calls signature. */ +typedef void (*zrtp_call_callback_t)(zrtp_stream_t*, zrtp_retry_task_t*); + +/** + * @brief Delay Call wrapper + */ +struct zrtp_retry_task_t +{ + /** \brief Task action callback */ + zrtp_call_callback_t callback; + + /** \brief Timeout before call in milliseconds */ + zrtp_time_t timeout; + + /** + * \brief User data pointer. + * + * Pointer to the user data. This pointer can be used for fast access to some additional data + * attached to this task by the user application. + */ + void* usr_data; + + + // TODO: hide these elements + /** + * \brief Task activity flag. + * + * Libzrtp unsets this flag on task canceling. It prevents the scheduler engine from re-adding + * an already canceled task. Callback handlers skip passive tasks. + * \note + * For internal use only. Don't' modify this field in implementation. + */ + uint8_t _is_enabled; + + /** + * \brief Number of task retries. + * + * Every handler that attempts the task increases it by one. When the limit is reached the + * scheduler should stop retries and performs a specified action - generally raises an error. + * \note + * For internal use only. Don't' modify this field in implementation. + */ + uint32_t _retrys; + + /** + * \brief Task Busy flag. + * + * Built-in cache implementation uses this flag to protect task from being removed during the + * callback. + * + * Default cache implementation "locks" this flag before call zrtp_retry_task#callback + * and "unlocks" when the call is performed. zrtp_callback_scheduler_t#on_wait_call_later exits + * when there are no callbacks in progress - no tasks with \c _is_busy enabled. + */ + uint8_t _is_busy; +}; + +/** + * @brief Delay Calls callbacks + */ +typedef struct zrtp_callback_scheduler_t +{ + /** + * \brief Delay Calls initialization. + * + * libzrtp calls this function before start using scheduler routine at zrtp_init(). + * + * \param zrtp - libzrtp global context; + * \sa zrtp_callback_scheduler_t#on_down() + */ + zrtp_status_t (*on_init)(zrtp_global_t* zrtp); + + /** + * \brief Delay Calls deinitialization. + * + * libzrtp calls this function when zrtp scheduler is no longer needed at zrtp_down(). + * \sa zrtp_callback_scheduler_t#on_init() + */ + void (*on_down)(); + + /** + * \brief Interface for performing delay call + * + * This function should add delay call request (\c task) to the processing queue. When the + * zrtp_retry_task_t#timeout is expired, scheduler should call zrtp_retry_task_t#callback and + * remove tasks from the processing queue. + * + * \param stream - stream context for processing the callback function; + * \param task - task structure that should be processed. + * \sa zrtp_callback_scheduler_t#on_cancel_call_later + */ + void (*on_call_later)(zrtp_stream_t *stream, zrtp_retry_task_t* task); + + /** + * \brief Interface for canceling a delay calls + * + * This function cancels delay call if it still in the processing queue. The algorithm is the + * following: + * - If there is a specified task for a specified stream, this task should be deleted. + * - If the \c task parameter is equal to NULL - ALL tasks for the specified stream must be + * terminated and removed from the queue. + * + * \param ctx - stream context for the operation; + * \param task - delayed call wrapper structure. + * \sa zrtp_callback_scheduler_t#on_call_later + */ + void (*on_cancel_call_later)(zrtp_stream_t* ctx, zrtp_retry_task_t* task); + + /** + * \brief Interface for waiting for scheduling tasks is finished + * + * This function is called by libzrtp when the state-mamchine is in a position to destroy ZRTP + * session and all incapsulated streams. Allocated for the stream memory may be cleared and + * released. If after this operation, scheduler perform time-out call it will bring system to + * crash. + * + * The scheduler implementation must guarantee that any delay call for the \c stream will not be + * performed after on_wait_call_later(). + * + * \param stream - stream context for the operation; + * \sa zrtp_callback_scheduler_t#on_call_later. + */ + void (*on_wait_call_later)(zrtp_stream_t* stream); +} zrtp_callback_scheduler_t; + +/** \} */ + +/*======================================================================*/ +/* libzrtp interface: Protocol */ +/*======================================================================*/ + +/** + * \defgroup zrtp_iface_proto ZRTP Protocol Feedback + * \ingroup zrtp_iface + * + * This section defines ZRTP protcol events. Detail description of ZRTP state-machine is defined in + * \ref XXX. + * \{ + */ + +/** + * \brief ZRTP Protocol events + * + * For additional information see \ref XXX + */ +typedef enum zrtp_protocol_event_t +{ + /** \brief Just a stub for error detection. */ + ZRTP_EVENT_UNSUPPORTED = 0, + + /** \brief Switching to CLEAR state */ + ZRTP_EVENT_IS_CLEAR, + + /** \brief Switching to INITIATING_SECURE state */ + ZRTP_EVENT_IS_INITIATINGSECURE, + + /** \brief Switching to PENDING_SECURE state */ + ZRTP_EVENT_IS_PENDINGSECURE, + + /** \brief Switching to PENDING_CLEAR state */ + ZRTP_EVENT_IS_PENDINGCLEAR, + + /** + * \brief Switching to NO_ZRTP state. + * + * Hello packet undelivered - no ZRTP endpoint and other end + */ + ZRTP_EVENT_NO_ZRTP, + + /** + * \brief First N Hello packet undelivered - probably, no ZRTP endpoint and other end + * + * Libzrtp raises this event after few Hello have been send without receiving response from the + * remote endpoint. User application may use this event to stop Securing ritual if connection + * lag is important. + * + * Developer should take into account that delays in Hello receiving may be conditioned by + * interruptions in media channel + * + * \warning Don't handle this event unless necessary + */ + ZRTP_EVENT_NO_ZRTP_QUICK, + + /** + * \brief MiTM Enrollment with MiTM endpoint + * + * Informs the Client-side endpoint of receiving a registration invitation from the MiTM. + * Libzrtp raises this event after switching to the Secure state (ZRTP_EVENT_IS_SECURE). The + * user may accept the invitation using a zrtp_register_with_trusted_mitm() call. + */ + ZRTP_EVENT_IS_CLIENT_ENROLLMENT, + + /** + * \brief New user has registered to the MitM + * + * Informs MitM of the registration of a new user. Libzrtp raises this event when a user calls + * the special registration number and has switched to the secure state. + */ + ZRTP_EVENT_NEW_USER_ENROLLED, + + /** + * \brief New user has already registered with the MiTM + * + * Notifies the MiTM of an attempt to register from a user that is already registered. In this + * case a new MiTM secret will not be generated and the user may be informed by voice prompt. + * Libzrtp raises this event from the SECURE state. + */ + ZRTP_EVENT_USER_ALREADY_ENROLLED, + + /** + * \brief User has cancelled registration + * + * Libzrtp may raise this event during regular calls when it discovers that the user has removed + * its MiTM secret. This event informs the MiTM that the SAS can no longer be transferred to + * this user. + */ + ZRTP_EVENT_USER_UNENROLLED, + + /** + * \brief SAS value and/or rendering scheme was updated + * + * LibZRTP raises this event when the SAS value is transferred from the trusted MiTM. The value + * is rendered automatically according to the rendering scheme specified by the trusted MiTM. + * (it may be different than that of the previous one). + * + * On receiving this event, the Client application should replace the old SAS with the new one + * and ask the user to verify it. This event is called from the Secure state only. + */ + ZRTP_EVENT_LOCAL_SAS_UPDATED, + + /** + * \brief SAS transfer was accepted by the remote side + * + * Libzrtp raises this event to inform the Server-side about accepting the change of SAS value + * and/or rendering scheme by the remote client. This event is called from the Secure state + * only. + */ + ZRTP_EVENT_REMOTE_SAS_UPDATED, + + /** + * \brief Swishing to SECURE state + * + * Duplicates zrtp_callback_event_t#on_zrtp_secure for more thin adjustments. + */ + ZRTP_EVENT_IS_SECURE, + + /** + * \brief Swishing to SECURE state is finished. + * + * Equal to ZRTP_EVENT_IS_SECURE but called when the Securing process is completely finished: + * new RS secret is generate, cache flags updated and etc. Can be used in extended application + * for more thin adjustments. + */ + ZRTP_EVENT_IS_SECURE_DONE, + + /** + * \brief Indicates DRM restriction. Stream can't go Secure. + * + * Libzrtp generate this event if DRM rules don't allow to switch to Secure mode: + * - A passive endpoint never sends a Commit message. Semi-active endpoint does not send a + * Commit to a passive endpoint + * - A passive phone, if acting as a SIP initiator r ejects all commit packets from everyone. + * - A passive phone rejects all commit messages from a PBX. + */ + ZRTP_EVENT_IS_PASSIVE_RESTRICTION, + + ZRTP_EVENT_COUNT + +} zrtp_protocol_event_t; + +/** + * \brief ZRTP Protocol Errors and Warnings + * + * For additional information see \ref XXX + */ +typedef enum zrtp_security_event_t +{ + /** + * \brief Switching to ERROR state + * + * The exact error code can be found at zrtp_stream_info_t#last_error. Use zrtp_log_error2str() + * to get error description in text mode. + */ + ZRTP_EVENT_PROTOCOL_ERROR = ZRTP_EVENT_COUNT, + + /** + * \brief Hello Hash is different from that received in signaling. + * + * In accordance with sec. 8.1 of the ZRTP RFC, libzrtp provides the ability to prevent DOS + * attacks. libzrtp can detect an attack in which the hash of the remote Hello was received + * through signaling and added to the ZRTP context (zrtp_signaling_hash_set()). + * + * When the hash of the incoming Hello doesn't match the hash from signaling, the + * ZRTP_EVENT_WRONG_SIGNALING_HASH event is raised and the connection MAY be terminated + * manually. + */ + ZRTP_EVENT_WRONG_SIGNALING_HASH, + + /** + * \brief Hmac of the received packet is different from the hmac value earlier received. + * + * If the Hello hash is sent through protected signaling, libzrtp provides the ability to + * prevent protocol packets from modification and even eliminates comparing the SAS. To do this, + * libzrtp compares the message Hmac with the Hmac received in the previous message. + * + * If the Hmacs don't match, the ZRTP_EVENT_WRONG_MESSAGE_HMAC event is raised and the + * connection MAY be terminated manually. + */ + ZRTP_EVENT_WRONG_MESSAGE_HMAC, + + /** + * \brief Retain secret was found in the cache but it doesn't match with the remote one + * + * The library rises this event when non-expired secret have been found in the cache but + * value of the secret doesn't match with the remote side secret. Such situation may happen + * in case of MiTM attack or when remote side lost it's cache. + * + * Recommended behavior: the application should notify user about the situation and ask him to + * verify the SAS. If SAS is different - it indicates the attack. + */ + ZRTP_EVENT_MITM_WARNING +} zrtp_security_event_t; + +/** + * \brief Callbacks definitions + * + * This section lists callback functions informing the user about the protocol status. These + * callbacks must be defined in the user application. + */ +typedef struct zrtp_callback_event_t +{ + /** + * \brief ZRTP Protocol events notification. + * + * Informs about switching between the protocol states and other events. Provides more flexible + * control over the protocol then on_zrtp_secure and on_zrtp_not_secure. + * + * \param event - type of event; + * \param stream - ZRTP stream context. + */ + void (*on_zrtp_protocol_event)(zrtp_stream_t *stream, zrtp_protocol_event_t event); + + /** + * \brief ZRTP Security events notification + * + * Informs about ZRTP security events: MiTM attacks, cache desynchronization and + * others. + * \warning MUST be handled in the target application to provide high security level. + * + * \param event - type of event; + * \param stream - ZRTP stream context. + */ + void (*on_zrtp_security_event)(zrtp_stream_t *stream, zrtp_security_event_t event); + + /** + * \brief Indicates switching to SECURE state. + * + * Pair of events: \c on_zrtp_secure and \c on_zrtp_not_secure represent simplified event + * handling mechanism comparing to \c on_zrtp_protocol_event. libzrtp calls this event when the + * call is SECURE and media is encrypted. + * + * SAS Verification is required on this event. + * + * \param stream - ZRTP stream context. + */ + void (*on_zrtp_secure)(zrtp_stream_t *stream); + + /** + * \brief Indicates switching to NOT SECURE state. + * + * This event duplicates some protocol and security events to simplify libzrtp usage. It may be + * used in applications which don't require detail information about ZRTP protocol. + * + * If Error appeared - the exact error code can be found at zrtp_stream_info_t#last_error. Use + * zrtp_log_error2str() to get error description in text mode. + * + * \param stream - ZRTP stream context. + */ + void (*on_zrtp_not_secure)(zrtp_stream_t *stream); +} zrtp_callback_event_t; + +/** \} */ + +/*======================================================================*/ +/* libzrtp interface: Misc */ +/*======================================================================*/ + +/** + * \defgroup zrtp_iface_misc Miscellaneous functions + * \ingroup zrtp_iface + * \{ + */ + +/** + * \brief Miscellaneous Functions + */ +typedef struct zrtp_callback_misc_t +{ + /** + * \brief RTP packet sending function + * + * This function pushes an outgoing ZRTP packet to the network. Correct building of IP and UPD + * headers is the developer's responsibility. + * + * \param stream - ZRTP stream context; + * \param packet - buffer storing the ZRTP packet to send; + * \param length - size of the ZRTP packet. + * \return + * - number of bytes sent if successful; + * - -1 if error occurred. + */ + int (*on_send_packet)(const zrtp_stream_t* stream, char* packet, unsigned int length); +} zrtp_callback_misc_t; + +/** \} */ + +/** + * \brief ZRTP feedback interface and application dependent routine + * \ingroup zrtp_iface + */ +typedef struct zrtp_callback_t +{ + /** \brief ZRTP Protocol Feedback */ + zrtp_callback_event_t event_cb; + /** \brief ZRTP Delay Calls routine */ + zrtp_callback_scheduler_t sched_cb; + /** \brief ZRTP Cache */ + zrtp_callback_cache_t cache_cb; + /** \brief Miscellaneous functions */ + zrtp_callback_misc_t misc_cb; +} zrtp_callback_t; + + +#if defined(__cplusplus) +} +#endif + +#endif /*__ZRTP_IFACE_H__*/ diff --git a/include/zrtp_iface_cache.h b/include/zrtp_iface_cache.h new file mode 100644 index 0000000000..c401ba9f7f --- /dev/null +++ b/include/zrtp_iface_cache.h @@ -0,0 +1,164 @@ +/* + * 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 + */ + +#ifndef __ZRTP_IFACE_CACHE_H__ +#define __ZRTP_IFACE_CACHE_H__ + +#include "zrtp_config.h" +#include "zrtp_base.h" +#include "zrtp_string.h" +#include "zrtp_error.h" +#include "zrtp_iface.h" + +#if defined(ZRTP_USE_BUILTIN_CACHE) && (ZRTP_USE_BUILTIN_CACHE == 1) + +#if defined(__cplusplus) +extern "C" +{ +#endif + +#define ZRTP_DEF_CACHE_VERSION_STR "libZRTP cache version=" +#define ZRTP_DEF_CACHE_VERSION_VAL "1.0" + +/** + * @brief Cache element identifier type + * Elements of this type link cache data with a pair of ZIDs. + * (constructed as: [ZID1][ZID2], where ZID1 - ZID with greater binary value) + * This type is used to identify cache elements in the built-in implementation. + */ +typedef uint8_t zrtp_cache_id_t[24]; + +#define ZRTP_MITMCACHE_ELEM_LENGTH (sizeof(zrtp_cache_id_t) + sizeof(zrtp_string64_t)) +#define ZRTP_CACHE_ELEM_LENGTH (sizeof(zrtp_cache_elem_t) - sizeof(mlist_t)) +#define ZFONE_CACHE_NAME_LENGTH 256 + +/** + * @brief Secret cache element structure + * This structure is used to store cache data in the built-in implementation + * of the caching system. + */ +typedef struct zrtp_cache_elem +{ + zrtp_cache_id_t id; /** Cache element identifier */ + zrtp_string64_t curr_cache; /** Current cache value */ + zrtp_string64_t prev_cache; /** Prev cache value */ + uint32_t verified; /** Verified flag for the cache value */ + uint32_t lastused_at; /** Last usage time-stamp in seconds */ + uint32_t ttl; /** Cache TTL since lastused_at in seconds */ + uint32_t secure_since; /** Secure since date in seconds. Utility field. Doen't required by libzrtp. */ + char name[ZFONE_CACHE_NAME_LENGTH]; /** name of the user associated with this cache entry */ + uint32_t name_length; /** cache name lengths */ + uint32_t presh_counter; /** number of Preshared streams made since last DH echange */ + mlist_t _mlist; +} zrtp_cache_elem_t; + + +zrtp_status_t zrtp_def_cache_init(zrtp_global_t* zrtp); + +void zrtp_def_cache_down(); + +zrtp_status_t zrtp_def_cache_set_verified( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + uint32_t verified); + +zrtp_status_t zrtp_def_cache_get_verified( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + uint32_t* verified); + + +zrtp_status_t zrtp_def_cache_put( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + zrtp_shared_secret_t *rss); + +zrtp_status_t zrtp_def_cache_put_mitm( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + zrtp_shared_secret_t *rss); + +zrtp_status_t zrtp_def_cache_get( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + zrtp_shared_secret_t *rss, + int prev_requested); + +zrtp_status_t zrtp_def_cache_get_mitm( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + zrtp_shared_secret_t *rss); + +zrtp_status_t zrtp_def_cache_set_presh_counter( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + uint32_t counter); + +zrtp_status_t zrtp_def_cache_get_presh_counter( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + uint32_t* counter); + +/** + * @brief Cache iterator + * zrtp_def_cache_foreach() calls this function for every cache entry. + * @param elem - cache element; + * @param is_mitm - is 1 when callback was called for MiTM for each. + * @param del - callback may return 1 to this to remove cache entry from the list. + * @param data - pointer to some user data from zrtp_def_cache_foreach(); + * @return + * - 0 - if element was requested for reading only and wasn't changed; + * - 1 - if element was modified and cache should be updated. + */ +typedef int (*zrtp_cache_callback_t)(zrtp_cache_elem_t* elem, int is_mitm, void* data, int* del); + +/** + * @brief Iterate over all cache entries. + * Can be used for searching and modifying cache entries. Protected by mutex. + * Can be called in parallel with other cache operations when protocol is + * running. + * @param global - libzrtp global context; + * @param is_mitm - if value of this flag is 1 - fore_each will be applied for MiTM secrets; + * @param callback - function to be called for every cache entry; + * @param data - this pointer will be passed to every \c callback call. + */ +void zrtp_def_cache_foreach( zrtp_global_t *global, + int is_mitm, + zrtp_cache_callback_t callback, + void *data); + +/** + * @brief Store shared secrets cache to the persistent storage + * May be used in server solutions for periodically flushing the cache to prevent data loss. + * + * @return + * - zrtp_status_ok - if operation complited successfully; + * - zrtp_status_wrong_state - if a call is performed from a routine which + * doesn't use the default cache. + */ +zrtp_status_t zrtp_def_cache_store(zrtp_global_t *global); + +zrtp_status_t zrtp_def_cache_reset_since( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid); + +zrtp_status_t zrtp_def_cache_get_since( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + uint32_t* since); + +zrtp_status_t zrtp_def_cache_get_name( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + zrtp_stringn_t* name); + +zrtp_status_t zrtp_def_cache_put_name( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + const zrtp_stringn_t* name); + +zrtp_cache_elem_t* zrtp_def_cache_get2(const zrtp_cache_id_t id, int is_mitm); + + +#if defined(__cplusplus) +} +#endif + +#endif /* ZRTP_USE_BUILTIN_CACHE */ + +#endif /*__ZRTP_IFACE_CACHE_H__*/ + diff --git a/include/zrtp_iface_scheduler.h b/include/zrtp_iface_scheduler.h new file mode 100644 index 0000000000..f2ca0181dc --- /dev/null +++ b/include/zrtp_iface_scheduler.h @@ -0,0 +1,89 @@ +/* + * 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 + */ + + +#ifndef __ZRTP_IFACE_SCHEDULER_H__ +#define __ZRTP_IFACE_SCHEDULER_H__ + +#include "zrtp_config.h" +#include "zrtp_base.h" +#include "zrtp_string.h" +#include "zrtp_error.h" +#include "zrtp_iface.h" + +#if defined(ZRTP_USE_BUILTIN_SCEHDULER) && (ZRTP_USE_BUILTIN_SCEHDULER == 1) + +#if defined(__cplusplus) +extern "C" +{ +#endif + + +/** + * In order to use default secheduler libzrtp one should define tow extra interfaces: + * sleep and threads riutine. + */ + +/** + * \brief Suspend thread execution for an interval measured in miliseconds + * \param msec - number of miliseconds + * \return: 0 if successful and -1 in case of errors. + */ + +#if ZRTP_PLATFORM != ZP_WIN32_KERNEL + +#if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WINCE) +#include + typedef LPTHREAD_START_ROUTINE zrtp_thread_routine_t; +#elif (ZRTP_PLATFORM == ZP_LINUX) || (ZRTP_PLATFORM == ZP_DARWIN) || (ZRTP_PLATFORM == ZP_BSD) + typedef void *(*zrtp_thread_routine_t)(void*); +#elif (ZRTP_PLATFORM == ZP_SYMBIAN) + typedef int(*zrtp_thread_routine_t)(void*); +#endif + +/** + * \brief Function is used to create a new thread, within a process. + * + * Thread should be created with default attributes. Upon its creation, the thread executes + * \c start_routine, with \c arg as its sole argument. + * \param start_routine - thread start routine. + * \param arg - start routine arguments. + * \return 0 if successful and -1 in case of errors. + */ + + +extern int zrtp_thread_create(zrtp_thread_routine_t start_routine, void *arg); +extern int zrtp_sleep(unsigned int msec); + +#endif + +void zrtp_def_scheduler_down(); + +zrtp_status_t zrtp_def_scheduler_init(zrtp_global_t* zrtp); + +void zrtp_def_scheduler_call_later(zrtp_stream_t *ctx, zrtp_retry_task_t* ztask); + +void zrtp_def_scheduler_cancel_call_later(zrtp_stream_t* ctx, zrtp_retry_task_t* ztask); + +void zrtp_def_scheduler_wait_call_later(zrtp_stream_t* ctx); + + +zrtp_status_t zrtp_sem_init(zrtp_sem_t** sem, uint32_t value, uint32_t limit); +zrtp_status_t zrtp_sem_destroy(zrtp_sem_t* sem); +zrtp_status_t zrtp_sem_wait(zrtp_sem_t* sem); +zrtp_status_t zrtp_sem_trtwait(zrtp_sem_t* sem); +zrtp_status_t zrtp_sem_post(zrtp_sem_t* sem); + +#if defined(__cplusplus) +} +#endif + +#endif /* ZRTP_USE_BUILTIN_SCEHDULER */ + +#endif /*__ZRTP_IFACE_SCHEDULER_H__*/ diff --git a/include/zrtp_iface_system.h b/include/zrtp_iface_system.h new file mode 100644 index 0000000000..6a69bd5b8b --- /dev/null +++ b/include/zrtp_iface_system.h @@ -0,0 +1,183 @@ +/* + * 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 + */ + + +/** + * \file zrtp_iface_system.h + * \brief libzrtp platform-dependent routine + */ + +#ifndef __ZRTP_IFACE_SYSTEM_H__ +#define __ZRTP_IFACE_SYSTEM_H__ + +#include "zrtp_config.h" +#include "zrtp_types.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + + +/*============================================================================*/ +/* System wide functions */ +/*============================================================================*/ + +/** + * \defgroup zrtp_iface Library Interfaces Overview + * + * This section describes the requirements for the implementation of each interface function. + * Descriptions are divided into groups by function + */ + +/** + * \defgroup zrtp_iface_base Basic platform-dependent routine + * \ingroup zrtp_iface + * \{ + */ + +/** + * \brief Time in miliseconds + * + * libzrtp uses a unix-like time calculation scheme: time since 1/1/1970. + */ +typedef uint64_t zrtp_time_t; + + +/** + * \brief Allocates memory of a defined size + * + * Allocates \c size bytes and returns a pointer to the allocated memory Allocated memory is not + * cleared. + * + * \param size - number of bytes for allocation + * \return + * - pointer to the allocated memory if successful. + * - NULL if the memory allocation failed. + */ +extern void* zrtp_sys_alloc(unsigned int size); + +/** + * \brief release memory + * + * Release the memory space pointed to by \c obj, which was returned by a previous zrtp_sys_alloc() + * call. If \c obj is NULL, no operation is performed. + * + * \param obj - pointer to the released memory + */ +extern void zrtp_sys_free(void* obj); + +/** + * \brief Memory copying function. + * + * This function copies \c length bytes from memory area \c src to memory area \c dest. The memory + * areas should not overlap. + * + * \param dest - pointer to the destination buffer + * \param src - pointer to the source buffer; + * \param length - number of bytes to be copied. + * \return + * - pointer to the destination buffer (dest) + */ +extern void* zrtp_memcpy(void* dest, const void* src, unsigned int length); + +/** + * \brief Write a byte to a byte string + * + * The zrtp_memset() function writes \c n bytes of value \c c (converted to an unsigned char) to the + * string \c s. + * \return + * - first argument + */ +extern void *zrtp_memset(void *s, int c, unsigned int n); + +/** + * \brief Returns current date and time + * + * This function should return current unix-like date and time: number of microseconds since + * 1.1.1970. + */ +extern zrtp_time_t zrtp_time_now(); + +/** \} */ + +/*============================================================================*/ +/* Mutex related interfaces */ +/*============================================================================*/ + +/** + * \defgroup zrtp_iface_mutex Synchronization related functions + * \ingroup zrtp_iface + * \{ + */ + +/** + * \brief Initializing the mutex structure + * + * This function allocates and initializes the mutex referenced by \c mutex with default attributes. + * Upon successful initialization, the state of the mutex becomes initialized and unlocked. This + * function should create a NON RECURSIVE mutex. (Attempting to relock the mutex causes deadlock) + * + * \param mutex - out parameter, mutex structure for allocation and initialization + * \return: + * - zrtp_status_ok if initialization successful; + * - zrtp_status_fail if an error occurred. + * \sa zrtp_mutex_destroy() + */ +extern zrtp_status_t zrtp_mutex_init(zrtp_mutex_t** mutex); + +/** + * \brief Deinitializing the mutex structure + * + * This function destroys the mutex object previously allocated by zrtp_mutex_init(). + * + * \param mutex - mutex structure for deinitialization. + * \return: + * - zrtp_status_ok if deinitialization successful; + * - zrtp_status_fail if an error occurred. + * \sa zrtp_mutex_init() + */ + extern zrtp_status_t zrtp_mutex_destroy(zrtp_mutex_t* mutex); + +/** + * \brief Mutex locking + * + * This function locks the mutex object referenced by \c mutex. If the mutex is already locked, the + * thread that called it is blocked until the mutex becomes available. This operation returns the + * mutex object referenced by the mutex in the locked state with the calling thread as its owner. + * + * \param mutex - mutex for locking; + * \return: + * - zrtp_status_ok if successful; + * - zrtp_status_fail if an error occurred. + */ +extern zrtp_status_t zrtp_mutex_lock(zrtp_mutex_t* mutex); + +/** + * \brief Mutex releasing + * + * This function releases the mutex object referenced by mutex. The way a mutex is released depends + * on the mutex's type attribute. If there are threads blocked on the mutex object referenced by + * mutex when zrtp_mutex_unlock() is called and the mutex becomes available, the scheduling policy + * determines which thread acquires the mutex. + * + * \param mutex - mutex to release + * \return: + * - zrtp_status_ok if successful; + * - zrtp_status_fail if an error occurred. + */ +extern zrtp_status_t zrtp_mutex_unlock(zrtp_mutex_t* mutex); + +/*! \} */ + +#if defined(__cplusplus) +} +#endif + +#endif /* __ZRTP_IFACE_SYSTEM_H__ */ diff --git a/include/zrtp_legal.h b/include/zrtp_legal.h new file mode 100644 index 0000000000..03c94729fd --- /dev/null +++ b/include/zrtp_legal.h @@ -0,0 +1,25 @@ +/* + * 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 + */ + +#ifndef __ZRTP_LEGAL_H__ +#define __ZRTP_LEGAL_H__ + + +/* + * We want the copyright string accessable to the unix strings command in + * the linked binary, and don't want the linker to remove it if it's not + * referenced, thus the volatile qualifier. + * + * ANSI C standard, section 3.5.3: "An object that has volatile-qualified + * type may be modified in ways unknown to the implementation or have + * other unknown side effects." + */ +extern volatile const char zrtpCopyright[]; + +#endif /*__ZRTP_LEGAL_H__ */ diff --git a/include/zrtp_list.h b/include/zrtp_list.h new file mode 100644 index 0000000000..e6ee0988c8 --- /dev/null +++ b/include/zrtp_list.h @@ -0,0 +1,66 @@ +/* + * 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 + */ + + +#ifndef __ZRTP_LIST_H__ +#define __ZRTP_LIST_H__ + +#include "zrtp_config.h" + +typedef struct mlist mlist_t; +struct mlist +{ + mlist_t *next; + mlist_t *prev; +}; + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* + * \warning + * We cast pointer to integer. There is bad thing for 64 bit platforms but + * calculated offset couldn't be bigger then 2x32 and it will be casted + * to integer correctly. + */ +#define mlist_list_offset(type, list_name) ((size_t)&(((type*)0)->list_name)) + +#define mlist_get_struct(type, list_name, list_ptr) \ + ((type*)(((char*)(list_ptr)) - mlist_list_offset(type,list_name))) + +#define mlist_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +#define mlist_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +void init_mlist(mlist_t* head); + +void mlist_add(mlist_t* head, mlist_t* node); +void mlist_add_tail(mlist_t *head, mlist_t *node); + +void mlist_insert(mlist_t *prev, mlist_t *node); + +void mlist_del(mlist_t *node); +void mlist_del_tail(mlist_t *node); + +mlist_t* mlist_get(mlist_t *head); +mlist_t* mlist_get_tail(mlist_t *head); + +int mlist_isempty(mlist_t *head); + +#if defined(__cplusplus) +} +#endif + + +#endif /*__ZRTP_LIST_H__ */ diff --git a/include/zrtp_log.h b/include/zrtp_log.h new file mode 100644 index 0000000000..75193ac1d5 --- /dev/null +++ b/include/zrtp_log.h @@ -0,0 +1,161 @@ +/* + * 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 + */ + +#ifndef __ZRTP_LOG_H__ +#define __ZRTP_LOG_H__ + +#include "zrtp_config.h" +#include "zrtp_types.h" +#include "zrtp_base.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZRTP_LOG_SENDER_MAX_LEN 12 +#define ZRTP_LOG_BUFFER_SIZE 512 + + +/*! + * \defgroup iface_log Functions for debug and information logging + * \ingroup interfaces + * \{ + */ + +/** + * @brief Write log message. + * This is the main macro used to write text to the logging backend. + * @param level The logging verbosity level. Lower number indicates higher + * importance, with level zero indicates fatal error. Only + * numeral argument is permitted (e.g. not variable). + * @param arg Enclosed 'printf' like arguments, with the first + * argument is the sender, the second argument is format + * string and the following arguments are variable number of + * arguments suitable for the format string. + * + * Sample: + * @code + * ZRTP_LOG(2, (__UNITE__, "Some log message with id %d", id)); + * @endcode + */ + +#define ZRTP_LOG(level,arg) do { \ +zrtp_log_wrapper_##level(arg); \ +} while (0) + +#define ZRTP_LOGC(level,arg) do { \ +zrtp_log_wrapperc_##level(arg); \ +} while (0) + + +/** + * @brief Signature for function to be registered to the logging subsystem to + * write the actual log message to some output device. + * + * @param level Log level. + * @param data Log message, which will be NULL terminated. + * @param len Message length. (prefix + text) + * @param offset Log message prefix length + */ +typedef void zrtp_log_engine(int level, char *data, int len, int offset); + + +#if ZRTP_LOG_MAX_LEVEL >= 1 + +/** + * @brief Changes default log writer function. + * This function may be used to implement log writer in a way native for target + * OS or product. By default libzrtp uses console output. + * @param engine - log writer. + */ +void zrtp_log_set_log_engine(zrtp_log_engine *engine); + +/** + * @brief Changes Log-Level in run-time mode + * Libzrtp uses 3 log levels: + * - 1 - system related errors; + * - 2 - security, ZRTP protocol related errors and warnings; + * - 3 - debug logging. + * By default, libzrtp uses debug logging - level 3. + * @param level - log level. + */ +void zrtp_log_set_level(uint32_t level); + +/* \} */ + +#else /* If logger is enabled */ + +# define zrtp_log_set_log_engine(engine) +# define zrtp_log_set_level(level) + +#endif /* If logger is enabled */ + + +#if ZRTP_LOG_MAX_LEVEL >= 1 +# define zrtp_log_wrapper_1(arg) zrtp_log_1 arg + void zrtp_log_1(const char *src, const char *format, ...); +# define zrtp_log_wrapperc_1(arg) zrtp_logc_1 arg + void zrtp_logc_1(const char *format, ...); +#else +# define zrtp_log_wrapper_1(arg) +# define zrtp_log_wrapperc_1(arg) +#endif + +#if ZRTP_LOG_MAX_LEVEL >= 2 +# define zrtp_log_wrapper_2(arg) zrtp_log_2 arg + void zrtp_log_2(const char *src, const char *format, ...); +# define zrtp_log_wrapperc_2(arg) zrtp_logc_2 arg + void zrtp_logc_2(const char *format, ...); +#else +#define zrtp_log_wrapper_2(arg) +#define zrtp_log_wrapperc_2(arg) +#endif + +#if ZRTP_LOG_MAX_LEVEL >= 3 +# define zrtp_log_wrapper_3(arg) zrtp_log_3 arg + void zrtp_log_3(const char *src, const char *format, ...); +# define zrtp_log_wrapperc_3(arg) zrtp_logc_3 arg + void zrtp_logc_3(const char *format, ...); + +#else +# define zrtp_log_wrapper_3(arg) +# define zrtp_log_wrapperc_3(arg) +#endif + +const char* zrtp_log_error2str(zrtp_protocol_error_t error); +const char* zrtp_log_status2str(zrtp_status_t error); + +/** Returns symbolical name of ZRTP protocol state for the current stream. */ +const char* zrtp_log_state2str(zrtp_state_t state); + +/** Returns symbolical name of ZXRTP protocol packet by it's code. */ +const char* zrtp_log_pkt2str(zrtp_msg_type_t type); + +/** Returns symbolical name of the PK Exchange mode for the current stream. */ +const char* zrtp_log_mode2str(zrtp_stream_mode_t mode); + +/** Returns symbolical name of the protocol and security events. */ +const char* zrtp_log_event2str(uint8_t event); + + +/** Print out ZRTP environment configuration setting to log level 3. */ +void zrtp_print_env_settings(); + +/** Print out ZRTP stream info strxucture. (use ZRTP log-level 3). */ +void zrtp_log_print_streaminfo(zrtp_stream_info_t* info); + +/** Print out ZRTP session info structure. (use ZRTP log-level 3). */ +void zrtp_log_print_sessioninfo(zrtp_session_info_t* info); + +#ifdef __cplusplus +} +#endif + + +#endif /* __ZRTP_LOG_H__ */ diff --git a/include/zrtp_pbx.h b/include/zrtp_pbx.h new file mode 100644 index 0000000000..94ce80cce1 --- /dev/null +++ b/include/zrtp_pbx.h @@ -0,0 +1,139 @@ +/* + * 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 + */ + + +/** + * \file zrtp_pbx.h + * \brief Defines basic Functions to work with MiTM endpoints + */ + +#ifndef __ZRTP_PBX_H__ +#define __ZRTP_PBX_H__ + +#include "zrtp_config.h" +#include "zrtp_types.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/** + * \defgroup zrtp_api_mitm PBX related functions and data types + * \ingroup zrtp_api + * + * In this section the basic functions for using the library in MiTM mode + * environment. Asterisk PBX, for example. + * \{ + */ + +/** + * \brief Start ZRTP enrollment ritual on Server side + * + * This is the equivalent of zrtp_stream_start() but for MiTM endpoints. By calling + * zrtp_stream_registration_start() libzrtp prepares to engage in the enrollment ritual: send + * special flag in Confirm packet and prepare for generating the MiTM secret. + * \return + * - zrtp_status_ok - if operation started successfully; + * - one of zrtp_status_t errorrs in other case. + * \sa zrtp_callback_event_t#on_zrtp_protocol_event + * \sa zrtp_event_t (PBX related definitions) + */ +zrtp_status_t zrtp_stream_registration_start(zrtp_stream_t* stream, uint32_t ssrc); + +/** + * \brief Continue ZRTP enrollment ritual (from CLEAR state) on Server side. + * + * This is equivalent to zrtp_stream_secure() but with enrollment ritual. Use this function instead + * of zrtp_stream_registration_start() in case when "autosecure" option is disabled for some reason. + * \return + * - zrtp_status_ok - if operation started successfully; + * - one of zrtp_status_t errorrs in other case. + */ +zrtp_status_t zrtp_stream_registration_secure(zrtp_stream_t* stream); + +/** + * \brief Confirms enrollment ritual on Client side + * + * Invocation of this function by event zrtp_protocol_event_t#ZRTP_EVENT_IS_CLIENT_ENROLLMENT + * confirms enrollment process; libzrtp generates special secret which will be used to "Sign" all + * further calls with the trusted MiTM. + * \return + * - zrtp_status_ok - in case when enrollment was completed successfully; + * - zrtp_status_fail - in case of error: wrong protocol state or system error. + */ +zrtp_status_t zrtp_register_with_trusted_mitm(zrtp_stream_t* stream); + +/** + * \brief Automatically handle ZRTP call in PBX environment + * + * This function may be called to handle ZRTP call between two ZRTP endpoints through PBX. As + * described in ID sec 8.3., there are several problems with ZRTP in PBX environment. + * zrtp_resolve_mitm_call() implements several steps to resolve such problems: + * - detect enrolled and non enrolled endpoint. If both sides are enrolled - one side for the SAS + * transfer will be chousen automatically; + * - start SAS transfer with the enrolled endpoint; + * - update flags and SAS rendering scheme if necessary. + * In other words: After switching to SECURE state, this is the one function which ZRTP MiTM + * endpoint should call to handle ZRTP call correctly. If you want to have more flexability in MiTM + * mode - resolve ambiguity manually using functions listed below. + * \param stream1 - one party of ZRTP call (must be in secure state already); + * \param stream2 - other party of ZRTP call (must be in secure state already). + * \return + * - zrtp_status_ok - if operation started successfully; + * - one of zrtp_status_t errors in other case. + * \ref XXX_DRAFT, XXX_GUIDE + */ +zrtp_status_t zrtp_resolve_mitm_call(zrtp_stream_t* stream1, zrtp_stream_t* stream2); + +/** + * \brief Updates remote-side SAS value and rendering scheme + * + * zrtp_update_remote_sas() initiates process of "SAS transferring" between trusted MiTM and user. + * It allows to change as SAS rendering scheme as a SAS value and related flags as well. It the MiTM + * needs to update just one of the parameters - the other one should be set to NULL. libzrtp informs + * about status of the SAS updating through zrtp_protocol_event_t::ZRTP_EVENT_REMOTE_SAS_UPDATED. + * Call this function in SECURE state only. + * \param stream - zrtp endpoint stream to update; + * \param transf_sas_scheme - chosen SAS rendering scheme; + * \param transf_sas_value - relaying SAS value (full sas hash); + * \param transf_ac_flag - relaying "allowclear" flag; + * \param transf_d_flag - relaying "disclose" flag. + * \return + * - zrtp_status_ok - if operation started successfully; + * - one of zrtp_status_t errors in other case. + */ +zrtp_status_t zrtp_update_remote_options( zrtp_stream_t* stream, + zrtp_sas_id_t transf_sas_scheme, + zrtp_string32_t* transf_sas_value, + uint8_t transf_ac_flag, + uint8_t transf_d_flag ); + +/** + * \brief Check if user at the end of the stream \c stream is enrolled + * \param stream - stream for examining. + * \return: 1 if user is enrolled and 0 in other case + */ +uint8_t zrtp_is_user_enrolled(zrtp_stream_t* stream); + +/** + * \brief Choose single enrolled stream from two enrolled + * + * This function may be used to resolve ambiguity with call transferring between two enrolled users. + * \return stream which shuld be used for SAS transferring + */ +zrtp_stream_t* zrtp_choose_one_enrolled(zrtp_stream_t* stream1, zrtp_stream_t* stream2); + +/* \} */ + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/include/zrtp_protocol.h b/include/zrtp_protocol.h new file mode 100644 index 0000000000..7e8986ff55 --- /dev/null +++ b/include/zrtp_protocol.h @@ -0,0 +1,491 @@ +/* + * 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 + */ + +#ifndef __ZRTP_PROTOCOL_H__ +#define __ZRTP_PROTOCOL_H__ + +#include "zrtp_config.h" +#include "zrtp_types.h" +#include "zrtp_error.h" + + +/*! + * \defgroup dev_protocol Protocol related data types and definitions + * \ingroup zrtp_dev + * \{ + */ + +/*! ZRTP Protocol version, retransmitted in HELLO packets */ +#define ZRTP_PROTOCOL_VERSION "1.10" +#define ZRTP_PROTOCOL_VERSION_VALUE 110 + +#define ZRTP_ZFONE_PROTOCOL_VERSION "0.10" +#define ZRTP_ZFONE_PROTOCOL_VERSION_VALUE 10 + +/* + * Protocol constants and definitions. All these values are defined by the ZRTP + * specification "ZRTP Internet Draft". + * Don't change them! + */ +#define ZRTP_S384 "S384" +#define ZRTP_S256 "S256" +#define ZRTP_S160 "S160" +#define ZRTP_AES1 "AES1" +#define ZRTP_AES3 "AES3" +#define ZRTP_HS32 "HS32" +#define ZRTP_HS80 "HS80" +#define ZRTP_DH2K "DH2k" +#define ZRTP_DH3K "DH3k" +#define ZRTP_EC256P "EC25" +#define ZRTP_EC384P "EC38" +#define ZRTP_EC521P "EC52" +#define ZRTP_MULT "Mult" +#define ZRTP_PRESHARED "Prsh" +#define ZRTP_B32 "B32 " +#define ZRTP_B256 "B256" + +#define ZRTP_ROLE_INITIATOR "Initiator" +#define ZRTP_ROLE_RESPONDER "Responder" +#define ZRTP_INITIATOR_HMAKKEY_STR "Initiator HMAC key" +#define ZRTP_RESPONDER_HMAKKEY_STR "Responder HMAC key" +#define ZRTP_GOCLEAR_STR "GoClear" +#define ZRTP_INITIATOR_KEY_STR "Initiator SRTP master key" +#define ZRTP_INITIATOR_SALT_STR "Initiator SRTP master salt" +#define ZRTP_RESPONDER_KEY_STR "Responder SRTP master key" +#define ZRTP_RESPONDER_SALT_STR "Responder SRTP master salt" +#define ZRTP_SKEY_STR "ZRTP Session Key" +#define ZRTP_SAS_STR "SAS" +#define ZRTP_RS_STR "retained secret" +#define ZRTP_INITIATOR_ZRTPKEY_STR "Initiator ZRTP key" +#define ZRTP_RESPONDER_ZRTPKEY_STR "Responder ZRTP key" +#define ZRTP_CLEAR_HMAC_STR "GoClear" +#define ZRTP_KDF_STR "ZRTP-HMAC-KDF" +#define ZRTP_SESS_STR "ZRTP Session Key" +#define ZRTP_MULTI_STR "ZRTP MSK" +#define ZRTP_PRESH_STR "ZRTP PSK" +#define ZRTP_TRUSTMITMKEY_STR "Trusted MiTM key" +#define ZRTP_COMMIT_HV_KEY_STR "Prsh" + +#define ZRTP_CACHE_DEFAULT_TTL (30*24*60*60) + +/** ZRTP Message magic Cookie */ +#define ZRTP_PACKETS_MAGIC 0x5a525450L +/** Defines ZRTP extension type for RTP protocol */ +#define ZRTP_MESSAGE_MAGIC 0x505a + + +/** + * @brief Retransmission timer T1 in milliseconds + * T1 is used for the retransmission of Hello messages. The HELLO timeout is + * doubled each time a resend occurs. The gain (max timeout value) is limited + * by @ref ZRTP_T1_CAPPING. After reaching \c ZRTP_T1_CAPPING, the state machine + * keeps resending HELLO packets until the resend count is less than \ref + * ZRTP_T1_MAX_COUNT + * @sa ZRTP_T1_MAX_COUNT ZRTP_T1_CAPPING + */ + +#define ZRTP_T1 50 + +/*! + * \brief Max resends count value for T1 timer + * This is the threshold value for HELLO replays. See \ref ZRTP_T1 ZRTP_T1 for + * details. If the resend count exceeds the value of ZRTP_T1_MAX_COUNT then + * the state machine calls _zrtp_machine_enter_initiatingerror() with error code \ref + * zrtp_protocol_error_t#zrtp_error_timeout and ZRTP session establishment is + * failed. + */ +#define ZRTP_T1_MAX_COUNT 20 + +/*! + * \brief Max resends count value for T1 timer for cases when local side have + * received remote Hello. Libzrtp uses this extended number of retries when there + * is an evidence, that remote side supports ZRTP protocol (remote Hello received). + * This approach allows to eliminate problem when ZRTP state-machine switches to + * NO_ZRTP state while remote side is computing his initial DH value. (especially + * important for slow devices) + */ +#define ZRTP_T1_MAX_COUNT_EXT 60 + +/*! Hello retries counter for ZRTP_EVENT_NO_ZRTP_QUICK event */ +#define ZRTP_NO_ZRTP_FAST_COUNT 5 + +/*! + * \brief Max T1 timeout + * ZRTP_T1_MAX_COUNT is the threshold for the growth of the timeout value of + * HELLO resends. See \ref ZRTP_T1 for details. + */ +#define ZRTP_T1_CAPPING 200 + +/*! + * \brief ZRTP stream initiation period in milliseconds + * If for some reason the initiation of a secure ZRTP stream can't be performed + * at a given time (there are no retained secrets for the session, or the + * concurrent stream is being processed in "DH" mode) the next attempt will be + * done in ZRTP_PROCESS_T1 milliseconds. If at the end of ZRTP_PROCESS_T1_MAX_COUNT + * attempts the necessary conditions haven't been reached, the task is canceled. + * The mechanism of delayed execution is the same as the mechanism of delayed + * packet sending. \sa ZRTP_PROCESS_T1_MAX_COUNT + */ +#define ZRTP_PROCESS_T1 50 + +/*! + * \brief Max recall count value + * This is the threshold value for ZRTP stream initiation tries. See \ref + * ZRTP_PROCESS_T1 for details. +*/ +#define ZRTP_PROCESS_T1_MAX_COUNT 20000 + +/*! + * \brief Retransmission timer T2 in milliseconds + * T2 is used for the retransmission of all ZRTP messages except HELLO. The + * timeout value is doubled after every retransmission. The gain (max timeout's + * value) is limited by \ref ZRTP_T2_CAPPING. \ref ZRTP_T2_MAX_COUNT is the limit + * for packets resent as for \ref ZRTP_T1. + */ +#define ZRTP_T2 150 + +/*! + * \brief Max retransmissions for non-HELLO packets + * ZRTP_T2_MAX_COUNT limits number of resends for the non-HELLO/GOCLEAR packets. + * When exceeded, call_is_on_error() is called and the error code is set to + * \ref zrtp_protocol_error_t#zrtp_error_timeout + */ +#define ZRTP_T2_MAX_COUNT 10 + + +/*! + * \brief Max timeout value for protocol packets (except HELLO and GOCLEAR) + * The resend timeout value grows until it reaches ZRTP_T2_CAPPING. After that + * the state machine keeps resending until the resend count hits the limit of + * \ref ZRTP_T2_MAX_COUNT + */ +#define ZRTP_T2_CAPPING 1200 + +/*! + * \brief Retransmission timer for GoClear resending in milliseconds. + * To prevent pinholes from closing or NAT bindings from expiring, the GoClear + * message should be resent every N seconds while waiting for confirmation from + * the user. GoClear replays are endless. + */ +#define ZRTP_T3 300 + +/*! + * \brief Set of timeouts for Error packet replays. + * The meaning of these fields are the same as in the T1 group but for + * Error/ErrorAck packets. The values of these options are not strongly + * defined by the draft. We use empirical values. + */ +#define ZRTP_ET 150 +#define ZRTP_ETI_MAX_COUNT 10 +#define ZRTP_ETR_MAX_COUNT 3 + +/* ZRTP Retries schedule for slow CSD channel */ +#define ZRTP_CSD_T4PROC 2000 + +#define ZRTP_CSD_T1 400 + ZRTP_CSD_T4PROC +#define ZRTP_CSD_T2 900 + ZRTP_CSD_T4PROC +#define ZRTP_CSD_T3 900 + ZRTP_CSD_T4PROC +#define ZRTP_CSD_T4 200 + ZRTP_CSD_T4PROC +#define ZRTP_CSD_ET 200 + ZRTP_CSD_T4PROC + + +/*! Defines the max component number which can be used in a HELLO agreement */ +#define ZRTP_MAX_COMP_COUNT 7 + + +/* + * Some definitions of protocol structure sizes. To simplify sizeof() constructions + */ +#define ZRTP_VERSION_SIZE 4 +#define ZRTP_ZID_SIZE 12 +#define ZRTP_CLIENTID_SIZE 16 +#define ZRTP_COMP_TYPE_SIZE 4 +#define ZRTP_RS_SIZE 32 +#define ZRTP_RSID_SIZE 8 +#define ZRTP_PACKET_TYPE_SIZE 8 +#define RTP_V2_HDR_SIZE 12 +#define RTP_HDR_SIZE RTP_V2_HDR_SIZE +#define RTCP_HDR_SIZE 8 +#define ZRTP_HV_SIZE 32 +#define ZRTP_HV_NONCE_SIZE 16 +#define ZRTP_HV_KEY_SIZE 8 +#define ZRTP_HMAC_SIZE 8 +#define ZRTP_CFBIV_SIZE 16 +#define ZRTP_MITM_SAS_SIZE 4 +#define ZRTP_MESSAGE_HASH_SIZE 32 +#define ZRTP_HASH_SIZE 32 + +/* Without header and HMAC: + + + + */ +#define ZRTP_HELLO_STATIC_SIZE (ZRTP_VERSION_SIZE + ZRTP_CLIENTID_SIZE + 32 + ZRTP_ZID_SIZE + 4) + +/* Without header and HMAC: + */ +#define ZRTP_DH_STATIC_SIZE (32 + 4*8) + +/* Without header and HMAC: + + */ +#define ZRTP_COMMIT_STATIC_SIZE (32 + ZRTP_ZID_SIZE + 4*5) + +/* + + + CRC32 */ +#define ZRTP_MIN_PACKET_LENGTH (RTP_HDR_SIZE + 4 + 8 + 4) + + +#if ( ZRTP_PLATFORM != ZP_SYMBIAN ) + #pragma pack(push,1) +#endif + + + +/** Base ZRTP messages header */ +typedef struct zrtp_msg_hdr +{ + /** ZRTP magic cookie */ + uint16_t magic; + + /** ZRTP message length in 4-byte words */ + uint16_t length; + + /** ZRTP message type */ + zrtp_uchar8_t type; +} zrtp_msg_hdr_t; + +/*! + * \brief ZRTP HELLO packet data + * Contains fields needed to construct/store a ZRTP HELLO packet + */ +typedef struct zrtp_packet_Hello +{ + zrtp_msg_hdr_t hdr; + /** ZRTP protocol version */ + zrtp_uchar4_t version; + + /** ZRTP client ID */ + zrtp_uchar16_t cliend_id; + + /*!< Hash to prevent DOS attacks */ + zrtp_uchar32_t hash; + + /** Endpoint unique ID */ + zrtp_uchar12_t zid; +#if ZRTP_BYTE_ORDER == ZBO_LITTLE_ENDIAN + uint8_t padding2:4; + + /** Passive flag */ + uint8_t pasive:1; + + /** M flag */ + uint8_t mitmflag:1; + + /** Signature support flag */ + uint8_t sigflag:1; + uint8_t padding1:1; + + /** Hash scheme count */ + uint8_t hc:4; + uint8_t padding3:4; + + /** Cipher count */ + uint8_t ac:4; + + /** Hash scheme count */ + uint8_t cc:4; + + /** SAS scheme count */ + uint8_t sc:4; + + /** PK Type count */ + uint8_t kc:4; +#elif ZRTP_BYTE_ORDER == ZBO_BIG_ENDIAN + uint8_t padding1:1; + uint8_t sigflag:1; + uint8_t mitmflag:1; + uint8_t pasive:1; + uint8_t padding2:4; + uint8_t padding3:4; + uint8_t hc:4; + uint8_t cc:4; + uint8_t ac:4; + uint8_t kc:4; + uint8_t sc:4; +#endif + + zrtp_uchar4_t comp[ZRTP_MAX_COMP_COUNT*5]; + zrtp_uchar8_t hmac; +} zrtp_packet_Hello_t; + + +/** + * @brief ZRTP COMMIT packet data + * Contains information to build/store a ZRTP commit packet. + */ +typedef struct zrtp_packet_Commit +{ + zrtp_msg_hdr_t hdr; + + /** Hash to prevent DOS attacks */ + zrtp_uchar32_t hash; + + /** ZRTP endpoint unique ID */ + zrtp_uchar12_t zid; + + /** hash calculations schemes selected by ZRTP endpoint */ + zrtp_uchar4_t hash_type; + + /** cipher types selected by ZRTP endpoint */ + zrtp_uchar4_t cipher_type; + + /** SRTP auth tag lengths selected by ZRTP endpoint */ + zrtp_uchar4_t auth_tag_length; + + /** session key exchange schemes selected by endpoints */ + zrtp_uchar4_t public_key_type; + + /** SAS calculation schemes selected by endpoint*/ + zrtp_uchar4_t sas_type; + /** hvi. See "ZRTP Internet Draft" */ + zrtp_uchar32_t hv; + zrtp_uchar8_t hmac; +} zrtp_packet_Commit_t; + + +/** + * @brief ZRTP DH1/2 packets data + * Contains fields needed to constructing/storing ZRTP DH1/2 packet. + */ +typedef struct zrtp_packet_DHPart +{ + zrtp_msg_hdr_t hdr; + + /** Hash to prevent DOS attacks */ + zrtp_uchar32_t hash; + + /** hash of retained shared secret 1 */ + zrtp_uchar8_t rs1ID; + + /** hash of retained shared secret 2 */ + zrtp_uchar8_t rs2ID; + + /** hash of user-defined secret */ + zrtp_uchar8_t auxsID; + + /** hash of PBX secret */ + zrtp_uchar8_t pbxsID; + + /** pvi/pvr or nonce field depends on stream mode */ + zrtp_uchar1024_t pv; + zrtp_uchar8_t hmac; +} zrtp_packet_DHPart_t; + + +/** + * @brief ZRTP Confirm1/Confirm2 packets data + */ +typedef struct zrtp_packet_Confirm +{ + zrtp_msg_hdr_t hdr; + + /** HMAC of preceding parameters */ + zrtp_uchar8_t hmac; + + /** The CFB Initialization Vector is a 128 bit random nonce */ + zrtp_uchar16_t iv; + + /** Hash to prevent DOS attacks */ + zrtp_uchar32_t hash; + + /** Unused (Set to zero and ignored) */ + uint8_t pad[2]; + + /** Length of optionas signature field */ + uint8_t sig_length; + + /** boolean flags for allowclear, SAS verified and disclose */ + uint8_t flags; + + /** how long (seconds) to cache shared secret */ + uint32_t expired_interval; +} zrtp_packet_Confirm_t; + + +/** + * @brief ZRTP Confirm1/Confirm2 packets data + */ +typedef struct zrtp_packet_SASRelay +{ + zrtp_msg_hdr_t hdr; + + /** HMAC of preceding parameters */ + zrtp_uchar8_t hmac; + + /** The CFB Initialization Vector is a 128 bit random nonce */ + zrtp_uchar16_t iv; + + /** Unused (Set to zero and ignored) */ + uint8_t pad[2]; + + /** Length of optionas signature field */ + uint8_t sig_length; + + /** boolean flags for allowclear, SAS verified and disclose */ + uint8_t flags; + + /** Rendering scheme of relayed sasvalue (for trusted MitMs) */ + zrtp_uchar4_t sas_scheme; + + /** Trusted MITM relayed sashash */ + uint8_t sashash[32]; +} zrtp_packet_SASRelay_t; + + +/** + * @brief GoClear packet structure according to ZRTP specification + */ +typedef struct zrtp_packet_GoClear +{ + zrtp_msg_hdr_t hdr; + + /** Clear HMAC to protect SRTP session from accidental termination */ + zrtp_uchar8_t clear_hmac; +} zrtp_packet_GoClear_t; + + +/** + * @brief Error packet structure in accordance with ZRTP specification + */ +typedef struct zrtp_packet_Error +{ + zrtp_msg_hdr_t hdr; + + /** ZRTP error code defined by draft and \ref zrtp_protocol_error_t */ + uint32_t code; +} zrtp_packet_Error_t; + +/** ZFone Ping Message. Similar to ZRTP protocol packet format */ +typedef struct +{ + zrtp_msg_hdr_t hdr; + zrtp_uchar4_t version; /** Zfone discovery protocol version */ + zrtp_uchar8_t endpointhash; /** Zfone endpoint unique identifier */ +} zrtp_packet_zfoneping_t; + +/** ZFone Ping MessageAck. Similar to ZRTP protocol packet format */ +typedef struct +{ + zrtp_msg_hdr_t hdr; + zrtp_uchar4_t version; /** Zfone discovery protocol version */ + zrtp_uchar8_t endpointhash; /** Zfone endpoint unique identifier */ + zrtp_uchar8_t peerendpointhash; /** EndpointHash copied from Ping message */ + uint32_t peerssrc; +} zrtp_packet_zfonepingack_t; + +/*! \} */ + +#if ( ZRTP_PLATFORM != ZP_SYMBIAN ) + #pragma pack(pop) +#endif + +#endif /*__ZRTP_PROTOCOL_H__*/ diff --git a/include/zrtp_srtp.h b/include/zrtp_srtp.h new file mode 100644 index 0000000000..16e84b9f29 --- /dev/null +++ b/include/zrtp_srtp.h @@ -0,0 +1,240 @@ +/* + * 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. + * + * Vitaly Rozhkov + */ + +#ifndef __ZRTP_SRTP_H__ +#define __ZRTP_SRTP_H__ + +#include "zrtp_config.h" +#include "zrtp_error.h" +#include "zrtp_types.h" +#include "zrtp_crypto.h" + + +/* in host order, so outside the #if */ +#define ZRTP_RTCP_E_BIT 0x80000000 +/* for byte-access */ +#define ZRTP_RTCP_E_BYTE_BIT 0x80 +#define ZRTP_RTCP_INDEX_MASK 0x7fffffff + + +/*! + * \defgroup srtp SRTP encryption interface + * \ingroup zrtp_dev + * \{ + */ + +/* Special types and definitions for the embedded implementation */ +#if (!defined(ZRTP_USE_EXTERN_SRTP) || (ZRTP_USE_EXTERN_SRTP == 0)) +#include "zrtp_srtp_builtin.h" +/*! + * \brief Structure describing an SRTP session. + * An instance of this structure is created by calling zrtp_srtp_create() + * and destroyed by calling zrtp_srtp_destroy(). It is used for + * protecting and unprotecting included streams. + */ +struct zrtp_srtp_ctx_t +{ + zrtp_srtp_stream_ctx_t *outgoing_srtp; /*!< pointer to outgoing SRTP stream context */ + zrtp_srtp_stream_ctx_t *incoming_srtp; /*!< pointer to incoming SRTP stream context */ +}; + +/*! + * \brief Global context of an internal SRTP implementation. + * It is created by calling zrtp_srtp_init() and destroyed by calling zrtp_srtp_down(). + * This context is used for holding replay protection mechanism data. + */ +typedef struct +{ + zrtp_rp_ctx_t *rp_ctx; /*!< pointer to replay protection context. */ +} zrtp_srtp_global_t; + +#else +typedef void zrtp_srtp_global_t; +#endif /* BUILDIN SRTP */ + +/*! + * \brief Structure describing SRTP/SRTCP stream parameters. + */ +typedef struct +{ + /*!< Cipher used to encrypt packets */ + zrtp_cipher_t *cipher; + /*! + * \brief Cipher key length in bytes (not including salt length). + * Used for cipher key derivation on stream initialization + * by calling \ref zrtp_srtp_create(). + */ + uint32_t cipher_key_len; + + /*!< Hash used for packets authentication */ + zrtp_hash_t *hash; + + /*! + * \brief Key length in bytes for HMAC generation. + * Used for auth key derivation on stream initialization by calling \ref + * zrtp_srtp_create() and for filling the key buffer with zeros on + * stream deinitialization by calling \ref zrtp_srtp_destroy(). + */ + uint32_t auth_key_len; + + /*!< Structure describing SRTP authentication scheme */ + zrtp_auth_tag_length_t *auth_tag_len; +} zrtp_srtp_policy_t; + + +/*! + * \brief Structure describing SRTP stream parameters. + * Variables of this type should be mapped into the SRTP stream context when + * a new stream is created. + */ +typedef struct +{ + zrtp_srtp_policy_t rtp_policy; /*!< crypto policy for RTP stream */ + zrtp_srtp_policy_t rtcp_policy; /*!< crypto policy for RTCP stream */ + + zrtp_cipher_t *dk_cipher; /*!< cipher for the key derivation mechanism */ + + /*!< Master key for key derivation. (holds the key value only, without the salt) */ + zrtp_string64_t key; + /*!< Master salt for key derivation. (salt should be 14 bytes length) */ + zrtp_string64_t salt; + + uint16_t ssrc; +} zrtp_srtp_profile_t; + + +/*! + * \brief Initialize SRTP engine and allocate global SRTP context. + * Contains global data for all sessions and streams. For correct memory + * management, the global SRTP context should be released by calling \ref + * zrtp_srtp_destroy(). A pointer to the allocated SRTP global should be saved + * at zrtp->srtp_global. + * \warning this function \b must be called before any operation with the SRTP + * engine. + * \param zrtp - pointer to libzrtp global context + * \return + * - zrtp_status_ok if success + * - zrtp_status_fail if error. + */ +zrtp_status_t zrtp_srtp_init(zrtp_global_t *zrtp); + +/*! + * \brief Free all allocated resources that were allocated by initialization + * This function \b must be called at the end of SRTP engine use. + * A pointer to deallocated SRTP global context (zrtp->srtp_global) + * should be cleared ( set to NULL). + * \param zrtp - pointer to libzrtp global context; + * \return + * - zrtp_status_ok - if SRTP engine has been deinitialized successfully; + * - one of \ref zrtp_status_t errors - if deinitialization failed. + */ +zrtp_status_t zrtp_srtp_down( zrtp_global_t *zrtp); + +/*! + * \brief Creates SRTP context based on given incoming and outgoing profiles. + * \param srtp_global - pointer to SRTP engine global context; + * \param inc_profile - profile for incoming stream configuration; + * \param out_profile - profile for outgoing stream configuration. + * \return + * - pointer to allocated and initialized SRTP session; + * - NULL if error. + */ +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 ); + +/*! + * \brief Destroys SRTP context that was allocated by \ref zrtp_srtp_create() + * \param srtp_global - pointer to SRTP engine global context; + * \param srtp_ctx - pointer to SRTP context. + * \return + * - zrtp_status_ok - if SRTP context has been destroyed successfully; + * - one of \ref zrtp_status_t errors if error. + */ +zrtp_status_t zrtp_srtp_destroy( zrtp_srtp_global_t *srtp_global, + zrtp_srtp_ctx_t * srtp_ctx ); + + +/*! + * \brief Function applies SRTP protection to the RTP packet. + * If zrtp_status_ok is returned, then packet points to the resulting SRTP + * packet; otherwise, no assumptions should be made about the value of either + * data elements. + * \note This function assumes that it can write the authentication tag + * directly into the packet buffer, right after the the RTP payload. 32-bit + * boundary alignment of the packet is assumed as well. + * \param srtp_global - global SRTP context; + * \param srtp_ctx - SRTP context to use in processing the packet; + * \param packet - pointer to the packet to be protected. + * \return + * - zrtp_status_ok - if packet has been protected successfully; + * - one of \ref zrtp_status_t errors - if protection failed. + */ +zrtp_status_t zrtp_srtp_protect( zrtp_srtp_global_t *srtp_global, + zrtp_srtp_ctx_t *srtp_ctx, + zrtp_rtp_info_t *packet ); + +/*! + * \brief Decrypts SRTP packet. + * If zrtp_status_ok is returned, then packet points to the resulting plain RTP + * packet; otherwise, no assumptions should be made about the value of either + * data elements. + * \warning This function assumes that the SRTP packet is aligned on + * a 32-bit boundary. + * \param srtp_global - global SRTP context; + * \param srtp_ctx - SRTP context to use in processing the packet; + * \param packet - pointer to the packet to be unprotected. + * \return + * - zrtp_status_ok - if packet has been unprotected successfully + * - one of \ref zrtp_status_t errors - if decryption failed + */ +zrtp_status_t zrtp_srtp_unprotect( zrtp_srtp_global_t *srtp_global, + zrtp_srtp_ctx_t *srtp_ctx, + zrtp_rtp_info_t *packet ); + +/*! + * \brief Function applies SRTCP protection to the RTCP packet. + * If zrtp_status_ok is returned, then packet points to the result in SRTCP + * packet; otherwise, no assumptions should be made about the value of either + * data elements. + * \note This function assumes that it can write the authentication tag + * directly into the packet buffer, right after the the RTP payload. 32-bit + * boundary alignment of the packet is also assumed. + * \param srtp_global - global SRTP context; + * \param srtp_ctx - SRTP context to use in processing the packet; + * \param packet - pointer to the packet to be protected. + * \return + * - zrtp_status_ok - if packet has been protected successfully; + * - one of \ref zrtp_status_t errors - if protection failed. + */ +zrtp_status_t zrtp_srtp_protect_rtcp( zrtp_srtp_global_t *srtp_global, + zrtp_srtp_ctx_t *srtp_ctx, + zrtp_rtp_info_t *packet ); + +/*! + * \brief Decrypts SRTCP packet. + * If zrtp_status_ok is returned, then packet points to the resulting RTCP + * packet; otherwise, no assumptions should be made about the value of either + * data elements. + * \warning This function assumes that the SRTP packet is aligned on + * a 32-bit boundary. + * \param srtp_global - global SRTP context; + * \param srtp_ctx - SRTP context to use in processing the packet; + * \param packet - pointer to the packet to be unprotected. + * \return + * - zrtp_status_ok - if packet has been unprotected successfully; + * - one of \ref zrtp_status_t errors - if decryption failed. +*/ +zrtp_status_t zrtp_srtp_unprotect_rtcp( zrtp_srtp_global_t *srtp_global, + zrtp_srtp_ctx_t *srtp_ctx, + zrtp_rtp_info_t *packet ); + +/* \} */ + +#endif /*__ZRTP_SRTP_H__ */ diff --git a/include/zrtp_srtp_builtin.h b/include/zrtp_srtp_builtin.h new file mode 100644 index 0000000000..0e92d4af88 --- /dev/null +++ b/include/zrtp_srtp_builtin.h @@ -0,0 +1,149 @@ +/* + * 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 + * Vitaly Rozhkov + */ + +#ifndef __ZRTP_SRTP_BUILTIN_H__ +#define __ZRTP_SRTP_BUILTIN_H__ + +#include "zrtp_config.h" +#include "zrtp_error.h" +#include "zrtp_types.h" +#include "zrtp_crypto.h" + +/*! + * \defgroup dev_srtp Built in SRTP realization + * \ingroup zrtp_dev + * \{ + */ + +/*! + * \brief Sliding window width in bits. + * This window is used by the replay protection mechanism. As stated in the + * RFC3711, '3.3.2., the replay protection sliding window width MUST be at least + * 64, but MAY be set to a higher value. + */ +#if (ZRTP_PLATFORM == ZP_SYMBIAN) +# define ZRTP_SRTP_WINDOW_WIDTH 16 +#else +# define ZRTP_SRTP_WINDOW_WIDTH 128 +#endif + +#if ZRTP_SRTP_WINDOW_WIDTH % 8 +/*! + * \brief Sliding window width in bytes if padding is needed. + * This is used for allocating a window as a uint8_t array. + */ +#define ZRTP_SRTP_WINDOW_WIDTH_BYTES ZRTP_SRTP_WINDOW_WIDTH/8+1 +#else +/*! + * \brief Sliding window width in bytes if padding isn't needed. + * This is used for allocating a window as a uint8_t array. + */ +#define ZRTP_SRTP_WINDOW_WIDTH_BYTES ZRTP_SRTP_WINDOW_WIDTH/8 +#endif + +#define RP_INCOMING_DIRECTION 1 +#define RP_OUTGOING_DIRECTION 2 + + +/*! \brief Structure describing replay protection engine data */ +typedef struct +{ + uint32_t seq; /*!< sequence number of packet on the top of sliding window */ + uint8_t window[ZRTP_SRTP_WINDOW_WIDTH_BYTES]; /*!< sliding window buffer */ +} zrtp_srtp_rp_t; + + +/*! \brief Structure describing cipher wrapper */ +typedef struct +{ + /*!< cipher that will be used for packet encryption */ + zrtp_cipher_t *cipher; + + /*!< pointer to cipher's context */ + void *ctx; +} zrtp_srtp_cipher_t; + + +/*! \brief Structure describing authentication wrapper */ +typedef struct +{ + zrtp_hash_t *hash; /*!< hash component for authentication tag generation */ + uint8_t *key; /*!< key buffer for HMAC generation */ + uint32_t key_len; /*!< key length in bytes. Used for zeroes filling of buffer with key */ + zrtp_auth_tag_length_t *tag_len; /*!< SRTP authentication scheme component */ +} zrtp_srtp_auth_t; + + +/*! \brief Structure for SRTP stream context description. */ +typedef struct +{ + /*!< wrapper for cipher component and holding its auxiliary data. Used for RTP encryption */ + zrtp_srtp_cipher_t rtp_cipher; + /*!< wrapper for hash component and holding its auxiliary data. Used for RTP authentication */ + zrtp_srtp_auth_t rtp_auth; + + /*!< wrapper for cipher component and holding its auxiliary data. Used for RTCP encryption */ + zrtp_srtp_cipher_t rtcp_cipher; + /*!< wrapper for hash component and holding its auxiliary data. Used for RTCP authentication */ + zrtp_srtp_auth_t rtcp_auth; +} zrtp_srtp_stream_ctx_t; + + +/*! + * \brief Enumeration of labels used in key derivation for various purposes. + * See RFC3711, "4.3. Key Derivation" for more details + */ +typedef enum +{ + label_rtp_encryption = 0x00, /*!< for RTP cipher's key derivation */ + label_rtp_msg_auth = 0x01, /*!< for RTP packets authentication mechanism's key derivation */ + label_rtp_salt = 0x02, /*!< for RTP cipher's salt derivation */ + + label_rtcp_encryption = 0x03, /*!< used for RTCP cipher's key derivation */ + label_rtcp_msg_auth = 0x04, /*!< for RTCP packets authentication mechanism key derivation */ + label_rtcp_salt = 0x05 /*!< for RTCP cipher's salt derivation */ +} zrtp_srtp_prf_label; + +typedef zrtp_srtp_cipher_t zrtp_dk_ctx; + + +/*! + * \brief Structure describing a protection node. + * Each node keeps data for protecting RTP and RTCP packets against replays + * within streams with a given SSRC. There are two replay protection nodes for + * each SSRC value in the two lists. One is used for incoming packets and + * the other for outgoing packets. +*/ +typedef struct +{ + zrtp_srtp_rp_t rtp_rp; /*!< RTP replay protection data */ + zrtp_srtp_rp_t rtcp_rp; /*!< RTCP replay protection data */ + uint32_t ssrc; /*!< RTP media SSRC for nodes searching in the linked list */ + zrtp_srtp_ctx_t *srtp_ctx; /*!< SRTP context related with current node*/ + mlist_t mlist; +} zrtp_rp_node_t; + + +/*! +* \brief Structure describing replay protection context. +* This structure holds two linked list's heads and two mutexes for +* synchronization access to appropriate lists. +*/ +typedef struct +{ + zrtp_rp_node_t inc_head; /*!< head of replay protection nodes list for incoming packets */ + zrtp_mutex_t* inc_sync; /*!< mutex for incoming list access synchronization */ + zrtp_rp_node_t out_head; /*!< head of replay protection nodes list for outgoing packets */ + zrtp_mutex_t* out_sync; /*!< mutex for outgoing list access synchronization */ +} zrtp_rp_ctx_t; + +/* \} */ + +#endif /* __ZRTP_SRTP_BUILTIN_H__ */ diff --git a/include/zrtp_string.h b/include/zrtp_string.h new file mode 100644 index 0000000000..2c48ca694b --- /dev/null +++ b/include/zrtp_string.h @@ -0,0 +1,284 @@ +/* + * 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 + */ + +#ifndef __ZRTP_STRING_H__ +#define __ZRTP_STRING_H__ + +#include "zrtp_config.h" +#include "zrtp_types.h" + +/** + * \file zrtp_strings.h + * \brief libzrtp safe strings + */ + +/*============================================================================*/ +/* Libzrtp Strings */ +/*============================================================================*/ + +#define ZRTP_STRING8 12 +#define ZRTP_STRING16 20 +#define ZRTP_STRING32 36 +#define ZRTP_STRING64 68 +#define ZRTP_STRING128 132 +#define ZRTP_STRING256 260 +#define ZRTP_STRING1024 1028 + + +#if ( ZRTP_PLATFORM != ZP_SYMBIAN ) +#pragma pack(push, 1) +#endif + +typedef struct zrtp_stringn +{ + uint16_t length; + uint16_t max_length; + char buffer[0]; +} zrtp_stringn_t; + +typedef struct zrtp_string8 +{ + uint16_t length; + uint16_t max_length; + char buffer[ZRTP_STRING8]; +} zrtp_string8_t; + + +typedef struct zrtp_string16 +{ + uint16_t length; + uint16_t max_length; + char buffer[ZRTP_STRING16]; +} zrtp_string16_t; + +typedef struct zrtp_string32 +{ + uint16_t length; + uint16_t max_length; + char buffer[ZRTP_STRING32]; +} zrtp_string32_t; + +typedef struct zrtp_string64 +{ + uint16_t length; + uint16_t max_length; + char buffer[ZRTP_STRING64]; +} zrtp_string64_t; + +typedef struct zrtp_string128 +{ + uint16_t length; + uint16_t max_length; + char buffer[ZRTP_STRING128]; +} zrtp_string128_t; + +typedef struct zrtp_string256 +{ + uint16_t length; + uint16_t max_length; + char buffer[ZRTP_STRING256]; +} zrtp_string256_t; + +typedef struct zrtp_string1024 +{ + uint16_t length; + uint16_t max_length; + char buffer[ZRTP_STRING1024]; +} zrtp_string1024_t; + +#if ( ZRTP_PLATFORM != ZP_SYMBIAN ) +#pragma pack(pop) +#endif + + +/** + * \defgroup zrtp_strings Libzrtp Safe Strings + * + * Using standard C-like strings is potentially dangerous in any program. All standard functions for + * working with c-strings rely on zero-termination, since c-strings don't contain a representation + * of their length. This can cause many mistakes. Moreover, it is impossible to use these strings + * for storing binary data. + * + * To solve these problems libzrtp uses zstrings instead of normal c-strings. A zstring is just a + * wrapped c-string that stores its own length. Use the following data types, macros and utility + * functions for working with zstrings in your applications. + * + * zstrings are easy to use, and at the same time light-weight and flexible. + * We use two groups of zstring types: + * \li zrtp_stringn_t - base type for all operations with zstrings; + * \li zrtp_stringXX_t group - storage types. + * + * One can use any zrtp_stringXX_t type (big enough to store necessary data) esired and operate with + * it using global zstring functions. To cast zrtp_stringXX_t to zrtp_stringn_t, the \ref ZSTR_GV + * and \ref ZSTR_GVP macros can be used. + * + * The main principle of running zstrings is storing its current data size. So to avoid mistakes and + * mess it is advised to use preestablished initialization macros. The description of each follows. + * \{ + */ + + +/** + * \brief Casts zrtp_stringXX_t to a pointer to zrtp_stringn_t. + * + * This macro prevents static casts caused by using zstring functions. Prevents mistakes and makes + * zstrings safer to use. + * \sa ZSTR_GVP + */ +#define ZSTR_GV(pstr) \ +(zrtp_stringn_t*)((char*)pstr.buffer - sizeof(pstr.max_length) - sizeof(pstr.length)) + +/** + * \brief Casts zrtp_stringXX_t* to a pointer to zrtp_stringn_t. + * + * This macro prevents static casts from using zstring functions. + * \sa ZSTR_GV + */ +#define ZSTR_GVP(pstr) \ +(zrtp_stringn_t*)((char*)pstr->buffer - sizeof(pstr->max_length) - sizeof(pstr->length)) + +/** + * \brief Macro for empty zstring initialization + * \warning Use this macro on every zrtp_string structure allocation. + * usage: \code zrtp_string_t zstr = ZSTR_INIT_EMPTY(zstr); \endcode + */ +#define ZSTR_INIT_EMPTY(a) { 0, sizeof(a.buffer) - 1, { 0 }} + +/** + * \brief Macro for zstring initialization from a constant C-string + * usage: \code zrtp_string_t zstr = ZSTR_INIT_WITH_CONST_CSTRING("zstring use example"); \endcode + */ +#define ZSTR_INIT_WITH_CONST_CSTRING(s) {sizeof(s) - 1, 0, s} + +/** + * \brief Macro for zstring clearing + * + * Use this macro for initializing already created zstrings + * usage: \code ZSTR_SET_EMPTY(zstr); \endcode + */ +#define ZSTR_SET_EMPTY(a)\ +{ a.length = 0; a.max_length = sizeof(a.buffer) - 1; a.buffer[0] = 0; } + + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/** + * \brief compare two zstrings + * + * Function compares the two strings left and right. + * \param left - one string for comparing; + * \param right - the other string for comparing. + * \return + * - -1 if left string less than right; + * - 0 if left string is equal to right; + * - 1 if left string greater than right. + */ +int zrtp_zstrcmp(const zrtp_stringn_t *left, const zrtp_stringn_t *right); + +/** + * \brief Copy a zstring + * + * The zrtp_zstrcpy function copies the string pointed by src to the structure pointed to by dst. + * \param src source string; + * \param dst destination string. + */ +void zrtp_zstrcpy(zrtp_stringn_t *dst, const zrtp_stringn_t *src); + +/** + * \brief Copy first N bytes of zstring + * + * The zrtp_zstrncpy function copies the first N bytes from the string pointed to by src to the + * structure pointed by dst. + * \param src - source string; + * \param dst - destination string; + * \param size - nuber of bytes to copy. + */ +void zrtp_zstrncpy(zrtp_stringn_t *dst, const zrtp_stringn_t *src, uint16_t size); + +/** + * @brief Copy a c-string into a z-string + * \param dst - destination zsyring + * \param src - source c-string to be copied. + */ +void zrtp_zstrcpyc(zrtp_stringn_t *dst, const char *src); + + +/** + * \brief Copy first N bytes of a c-string into a z-string + * \param dst - destination zsyring + * \param src - source c-string to be copied. + * \param size - number of bytes to be copied from \c src to \c dst + */ +void zrtp_zstrncpyc(zrtp_stringn_t *dst, const char *src, uint16_t size); + +/** + * \brief Concatenate two strings + * + * The zrtp_zstrcat function appends the src string to the dst string. If dst string doesn't have + * enough space it will be truncated. + * \param src source string; + * \param dst destination string. + */ +void zrtp_zstrcat(zrtp_stringn_t *dst, const zrtp_stringn_t *src); + +/** + * \brief Clear a zstring + * \param zstr - string for clearing; + */ +void zrtp_wipe_zstring(zrtp_stringn_t *zstr); + +/** + * \brief Compare two binary strings + * + * This function is used to prevent errors caused by other, non byte-to-byte comparison + * implementations. The secret sorting function is sensitive to such things. + * + * \param s1 - first string for comparison + * \param s2 - second string for comparison + * \param n - number of bytes to be compared + * \return - an integer less than, equal to, or greater than zero, if the first n bytes of s1 + * is found, respectively, to be less than, to match, or to be greater than the first n bytes of s2. + */ +int zrtp_memcmp(const void* s1, const void* s2, uint32_t n); + +/** + * \brief Converts binary data to the hex string representation + * + * \param bin - pointer to the binary buffer for converting; + * \param bin_size - binary data size; + * \param buff - destination buffer; + * \param buff_size - destination buffer size. + * \return + * - pointer to the buff with converted data; + * - "Buffer too small" in case of error. + */ +const char* hex2str(const char* bin, int bin_size, char* buff, int buff_size); + +/** + * \brief Converts hex string to the binary representation + * + * \param buff - source buffer for converting; + * \param buff_size - source buffer size; + * \param bin - pointer to the destination binary buffer; + * \param bin_size - binary data size; + * \return + * - pointer to the buff with converted data, or NULL in case of error. + */ +char *str2hex(const char* buff, int buff_size, char* bin, int bin_size); + +#if defined(__cplusplus) +} +#endif + +/** \} */ + +#endif /* __ZRTP_STRING_H__ */ diff --git a/include/zrtp_types.h b/include/zrtp_types.h new file mode 100644 index 0000000000..abbba0dce4 --- /dev/null +++ b/include/zrtp_types.h @@ -0,0 +1,1008 @@ +/* + * 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 + */ + + +#ifndef __ZRTP_TYPES_H__ +#define __ZRTP_TYPES_H__ + +#include "zrtp_config.h" +#include "bn.h" +#include "zrtp_base.h" +#include "zrtp_iface.h" +#include "zrtp_list.h" +#include "zrtp_legal.h" +#include "zrtp_string.h" +#include "zrtp_protocol.h" + + +/** + * \brief Defines ZRTP state-machine states + * \ingroup zrtp_types + * + * The conditions for switching from one state to another, and libzrtp behavior in every state is + * described in detail in \ref XXX and depicted in diagram XXX and XXX. + * + * The current stream state is stored in the zrtp_stream_info_t#state variable and available for + * reading at any time. + */ +typedef enum zrtp_state_t +{ + ZRTP_STATE_NONE = 0, + ZRTP_STATE_ACTIVE, /** Just right stream attaching, before protocol start */ + ZRTP_STATE_START, /** Protocol initiated, Discovery haven't started yet */ + ZRTP_STATE_WAIT_HELLOACK, /** Hello sending, waiting for HelloAck */ + ZRTP_STATE_WAIT_HELLO, /** HelloAck received, Waiting for peer Hello */ + ZRTP_STATE_CLEAR, /** CLEAR state */ + ZRTP_STATE_START_INITIATINGSECURE, /** Starting Initiator state-machine */ + ZRTP_STATE_INITIATINGSECURE, /** Commit retries, waiting for DH1 */ + ZRTP_STATE_WAIT_CONFIRM1, /** DH2 retries, waiting for Confirm1 */ + ZRTP_STATE_WAIT_CONFIRMACK, /** Confirm2 retries, waiting for ConfirmAck */ + ZRTP_STATE_PENDINGSECURE, /** Responder state-machine, waiting for DH2 */ + ZRTP_STATE_WAIT_CONFIRM2, /** Waiting for Confirm2 to finalize ZRTP exchange */ + ZRTP_STATE_SECURE, /** SECURE state, call is encrypted */ + ZRTP_STATE_SASRELAYING, /** SAS transferring to the remote peer (for MiTM only) */ + ZRTP_STATE_INITIATINGCLEAR, /** Switching to CLEAR initated by the local endpoint */ + ZRTP_STATE_PENDINGCLEAR, /** CLEAR request have been received */ + ZRTP_STATE_INITIATINGERROR, /** Protocol ERROR detected on local side */ + ZRTP_STATE_PENDINGERROR, /** Protocol ERROR received from the remote peer */ + ZRTP_STATE_ERROR, /** Protcol ERROR state. Check zrtp_stream_info#last_error*/ +#if (defined(ZRTP_BUILD_FOR_CSD) && (ZRTP_BUILD_FOR_CSD == 1)) + ZRTP_STATE_DRIVEN_INITIATOR, + ZRTP_STATE_DRIVEN_RESPONDER, + ZRTP_STATE_DRIVEN_PENDING, +#endif + ZRTP_STATE_NO_ZRTP, /** Discovery phase failed. Remote peer doesn't support ZRTP */ + ZRTP_STATE_COUNT +} zrtp_state_t; + +/** + * \brief Enumeration for ZRTP stream mode definition + * \ingroup zrtp_types + */ +typedef enum zrtp_stream_mode_t +{ + ZRTP_STREAM_MODE_UNKN = 0, /** Unused stream - unknown mode */ + ZRTP_STREAM_MODE_CLEAR = 1, /** Just after stream attaching - mode is undefined */ + ZRTP_STREAM_MODE_DH = 2, /** FULL DH ZRTP stream mode */ + ZRTP_STREAM_MODE_PRESHARED = 3, /** Preshared ZRTP stream mode */ + ZRTP_STREAM_MODE_MULT = 4, /** Multistream ZRTP stream mode */ + ZRTP_STREAM_MODE_COUNT = 5 +} zrtp_stream_mode_t; + +/** + * \brief ZRTP session profile + * \ingroup zrtp_types + * \ingroup zrtp_main_init + * + * ZRTP Sessions are configured with a profile scheme. Each profile is defined by a structure of the + * given type. zrtp_profile_t contains a set of preferences for crypto components and other + * protocol parameters. + * + * The Crypto component choosing mechanism is as follows: both sides communicated their supported + * components during the "discovery phase". After that the initiator chooses the optimal + * intersection of components. + * + * For components identification the numerical values of the following types are used: + * zrtp_hash_id_t, zrtp_cipher_id_t, zrtp_atl_id_t, and zrtp_sas_id_t. The profile field responsible + * for components of a particular type setting is an integer-valued array where component + * identifiers should be placed in order of priority. 0-element is of the first priority. The list + * should end with ZRTP_COMP_UNKN=0. + * + * The values in the profile may be filled either by libzrtp zrtp_profile_defaults() or by the user + * manually. + * + * The profile is applied to the stream context on allocation by zrtp_session_init(). + * + * \sa XXX + */ +struct zrtp_profile_t +{ + /** + * \brief Allowclear mode flag + * + * This option means that the ZRTP peer allows SRTP termination. If allowclear is disabled, the + * ZRTP peer must stay in protected mode until the moment the ZRTP stream is shut down. When not + * in "allowclear" mode, libzrtp will reject all incoming GoClear packages and will not generate + * its own. + * + * Setting the value equal to 1 turns "allowclear" on, and 0 turns "allowclear" off. If + * "allowclear" is disabled zrtp_stream_clear() returns zrtp_status_fail. + */ + uint8_t allowclear; + + /** + * \brief ZRTP "autosecure" mode flag + * + * In "autosecure" mode, a protected connection will be initiated automatically just after + * stream start-up. If the option "autosecure" is switched off, then a secure connection can be + *initialized only by calling zrtp_stream_secure(). + */ + uint8_t autosecure; + + /** + * \brief Disclose bit. + * + * This field MUST be set by user application if it's going to disclose stream keys. + */ + uint8_t disclose_bit; + + /** + * \brief Enabled Discovery Optimization + * + * ZRTP protocol specification allows to speed-up the discovery process by sending Commit + * instead of HelloAck. This is the default behavior for most of ZRTP endpoints. It allows to + * eliminate one unnecessary exchange. + * + * At other hand, this optimization may cose some problems on slow devices: using this option, + * the endpoint starts to compute DH value right after receiving remote Hello. It may take + * seginificent amount of time on slow device (of is the device is busy on other calculations). + * As all libzrtp messages are processed in single thread, while local endpoint computing DH + * it be unable to response on remote Hello-s and remote side may switch to NO_ZRTP state. + * + * Not use this option is you running libzrtp on slow device or your software supports HQ video + * conferences. Enabled by default. + */ + uint8_t discovery_optimization; + + /** + * \brief Cache time-to-live + * + * The time interval libzrtp should retain secrets. This parameter sets the secret's time to + * live in seconds. This option is global for all connections processed by the library. It is + * used together with zrtp_session_info_t#cache_ttl. + * + * ZRTP_CACHE_DEFAULT_TTL value is used by default. + */ + uint32_t cache_ttl; + + /** \brief SAS calculation scheme preferences */ + uint8_t sas_schemes[ZRTP_MAX_COMP_COUNT+1]; + + /** \brief Cipher type preferences */ + uint8_t cipher_types[ZRTP_MAX_COMP_COUNT+1]; + + /** \brief Public key exchange scheme preferences */ + uint8_t pk_schemes[ZRTP_MAX_COMP_COUNT+1]; + + /** \brief Auth tag length preferences */ + uint8_t auth_tag_lens[ZRTP_MAX_COMP_COUNT+1]; + + /** + * \brief Hash calculation scheme preferences + * \note ZRTP_HASH_SHA256 is only one hash algorithm supported by current version of libzrtp. + */ + uint8_t hash_schemes[ZRTP_MAX_COMP_COUNT+1]; +}; + +/** + * \brief Shared secret structure + * \ingroup zrtp_iface_cache + * + * This structure stores ZRTP shared secret values used in the protocol. + */ +struct zrtp_shared_secret_t +{ + /** \brief ZRTP secret value */ + zrtp_string64_t value; + + /** + * \brief last usage time-stamp in seconds. + * + * Library updates this value on generation of the new value based on previous one. + */ + uint32_t lastused_at; + + /** + * \brief TTL value in seconds. + * + * Available for reading after the Hello exchange. Updated on switching to Secure state. + */ + uint32_t ttl; + + /** + * \brief Loaded secret flag. + * + * When the flag is set (= 1), the secret has been loaded from the cache. Otherwise the secret + * has been generated. + * \warning For internal use only. Don't modify this flag in the application. + */ + uint8_t _cachedflag; +}; + +/** + * \brief Lists MitM roles on PBX call transferring + * + * Enumeration type for the ZRTP modes based on the role of the MitM. + */ +typedef enum zrtp_mitm_mode_t +{ + /** MitM is not supported or not activated. */ + ZRTP_MITM_MODE_UNKN = 0, + + /** + * \brief Client-side mode called to the PBX in ZRTP trusted MiTM mode. + * + * Libzrtp activates this state on receiving an Hello, indicating that remote side is trusted + * MiTM. + */ + ZRTP_MITM_MODE_CLIENT, + + /** + * \brief Server-side mode to transfer SAS to the registrant. + * + * Libzrtp switches to this state on starting zrtp_update_remote_options(). + */ + ZRTP_MITM_MODE_RECONFIRM_SERVER, + /** + * \brief Client-side mode accepted SAS transfer from the trusted MiTM. + * + * Libzrtp activates this state on receiving an SASRELAY from a trusted MiTM endpoint. + */ + ZRTP_MITM_MODE_RECONFIRM_CLIENT, + /** + * \brief Server-side mode to accept the user's registration requests. + * + * Libzrtp switches to this state on starting a registration stream by + * zrtp_stream_registration_start() or zrtp_stream_registration_secure(). + */ + ZRTP_MITM_MODE_REG_SERVER, + /** + * \brief User-side mode to confirm the registration ritual. + * + * The library enables this state when a remote party invites it to the registration ritual + * by a special flag in the Confirm packet. + */ + ZRTP_MITM_MODE_REG_CLIENT +} zrtp_mitm_mode_t; + + +/** \manonly */ + + +/*======================================================================*/ +/* Internal ZRTP libzrtp datatypes */ +/*======================================================================*/ + +/** + * @defgroup types_dev libzrtp types for developers + * The data types used in inside libzrte. This section is for libzrtp developers + * @ingroup zrtp_dev + * \{ + */ + + +/** + * @brief Enumeration for ZRTP protocol packets type definition + * @warning! Don't change order of these definition without synchronizing with + * print* functions (see zrtp_log.h) + */ +typedef enum +{ + ZRTP_UNPARSED = -1, /** Unparsed packet */ + ZRTP_NONE = 0, /** Not ZRTP packet */ + ZRTP_HELLO = 1, /** ZRTP protocol HELLO packet */ + ZRTP_HELLOACK = 2, /** ZRTP protocol HELLOACK packet */ + ZRTP_COMMIT = 3, /** ZRTP protocol COMMIT packet */ + ZRTP_DHPART1 = 4, /** ZRTP protocol DHPART1 packet */ + ZRTP_DHPART2 = 5, /** ZRTP protocol DHPART2 packet */ + ZRTP_CONFIRM1 = 6, /** ZRTP protocol CONFIRM1 packet */ + ZRTP_CONFIRM2 = 7, /** ZRTP protocol CONFIRM2 packet */ + ZRTP_CONFIRM2ACK = 8, /** ZRTP protocol CONFIRM2ACK packet */ + ZRTP_GOCLEAR = 9, /** ZRTP protocol GOCLEAR packet */ + ZRTP_GOCLEARACK = 10, /** ZRTP protocol GOCLEARACK packet */ + ZRTP_ERROR = 11, /** ZRTP protocol ERROR packet */ + ZRTP_ERRORACK = 12, /** ZRTP protocol ERRORACK packet */ + ZRTP_PROCESS = 13, /** This is not a packet type but type of task for scheduler */ + ZRTP_SASRELAY = 14, /** ZRTP protocol SASRELAY packet */ + ZRTP_RELAYACK = 15, /** ZRTP protocol RELAYACK packet */ + ZRTP_ZFONEPING = 16, /** Zfone3 Ping packet */ + ZRTP_ZFONEPINGACK = 17, /** Zfone3 PingAck packet */ + ZRTP_MSG_TYPE_COUNT = 18 +} zrtp_msg_type_t; + + +/** + * @brief enumeration for protocol state-machine roles + * Protocol role fully defines it's behavior. ZRTP peer chooses a role according + * to specification. For details see internal developers documentation + */ +typedef enum zrtp_statemachine_type_t +{ + ZRTP_STATEMACHINE_NONE = 0, /** Unknown type. Used as error value */ + ZRTP_STATEMACHINE_INITIATOR = 1, /** Defines initiator's protocol logic */ + ZRTP_STATEMACHINE_RESPONDER = 2 /** Defines responder's protocol logic */ +} zrtp_statemachine_type_t; + +#define ZRTP_BIT_RS1 0x02 +#define ZRTP_BIT_RS2 0x04 +#define ZRTP_BIT_AUX 0x10 +#define ZRTP_BIT_PBX 0x20 + +/** + * @brief Library global context + * Compilers and linkers on some operating systems don't support the declaration + * of global variables in c files. Storing a context allows us to solve this + * problem in a way that unifies component use. The context is created by calling + * zrtp_init(), and is destroyed with zrtp_down(). It contains data necessary + * for crypto-component algorithms, including hash schemes, cipher types, SAS + * schemes etc. Context data can be divided into three groups: + * - ID of client ZRTP peer; + * - RNG related fields (hash context for entropy computing); + * - DH scheme related fields(internal data used for DH exchange); + * - headers of the lists of every crypto-component type used for component + * management. + * All of this data, except for "RNG related fields", is for internal use only + * and set automatically. All that is needed is to link every created session + * to global context. + * @sa zrtp_init() zrtp_down() zrtp_session_init() + */ +struct zrtp_global_t +{ + /** ZRTP license mode. */ + uint32_t lic_mode; + + /** Local ZRTP client ID. */ + zrtp_string16_t client_id; + + /** Flags defines that the local endpoint acts as ZRTP MiTM. */ + uint8_t is_mitm; + + /** Hash context for entropy accumulation for the RNG unit. */ + MD_CTX rand_ctx; + + /** RNG unit initialization flag. */ + uint8_t rand_initialized; + + zrtp_string128_t def_cache_path; + + /** This object is used to protect the shared RNG hash zrtp#rand_ctx */ + zrtp_mutex_t* rng_protector; + + /** This section provides static data for DH3K and DH4K components */ + struct BigNum one; + struct BigNum G; + struct BigNum P_2048; + struct BigNum P_2048_1; + struct BigNum P_3072; + struct BigNum P_3072_1; + uint8_t P_2048_data[256]; + uint8_t P_3072_data[384]; + + /** Head of hash components list */ + mlist_t hash_head; + + /** Head of ciphers list */ + mlist_t cipher_head; + + /** Head of ATL components list */ + mlist_t atl_head; + + /** Head of public key exchange schemes list */ + mlist_t pktype_head; + + /** SAS schemes list */ + mlist_t sas_head; + + /** Storage for some SRTP global data */ + void* srtp_global; + + /** Head of ZRTP sessions list */ + mlist_t sessions_head; + + /** Global sessions count used to create ZRTP session IDs. For debug purposes mostly. */ + uint32_t sessions_count; + + /** Global streams count used to create ZRTP session IDs. For debug purposes mostly. */ + uint32_t streams_count; + + /** This object is used to synchronize sessions list operations */ + zrtp_mutex_t* sessions_protector; + + /** Set of feedback callbacks used by libzrtp to interact witrh the user-space.*/ + zrtp_callback_t cb; +}; + + +/** + * @brief RTP packet structure used in libzrtp + * Used for conveniently working with RTP/ZRTP packets. A binary RTP/ZRTP + * packet is converted into a zrtp_rtp_info_t structure before processing by + * _zrtp_packet_preparse() + */ +typedef struct zrtp_rtp_info_t +{ + /** Packet length in bytes */ + uint32_t *length; + + /** Pointer to the RTP/ZRTP packet body */ + char *packet; + + /** Pointer to ZRTP Message part (skip ZRTP transport header part) */ + void *message; + + /** ZRTP packet type (ZRTP_NONE in case of non command packet) */ + zrtp_msg_type_t type; + + /** Straightened RTP/ZRTP sequence number in host mode */ + uint32_t seq; + + /** RTP SSRC/ZRTP in network mode */ + uint32_t ssrc; +} zrtp_rtp_info_t; + + +/** + * @brief Retained secrets container + * Contains the session's shared secret values and related flags restored from + * the cache. Every subsequent stream within a session uses these values + * through @ref zrtp_proto_secret_t pointers. By definition, different ZRTP + * streams can't change secret values. Secret flags are protected against race + * conditions by the mutex \c _protector. For internal use only. + */ +typedef struct zrtp_secrets_t +{ + /** First retained secret RS1. */ + zrtp_shared_secret_t *rs1; + + /** Second retained secret RS1. */ + zrtp_shared_secret_t *rs2; + + /** User-defined secret. */ + zrtp_shared_secret_t *auxs; + + /** PBX Secret for trusted MiTMs. */ + zrtp_shared_secret_t *pbxs; + + /** Bit-map to summarize shared secrets "Cached" flags. */ + uint32_t cached; + uint32_t cached_curr; + + /** Bit-map to summarize shared secrets "Matches" flags. */ + uint32_t matches; + uint32_t matches_curr; + + /** Bit-map to summarize shared secrets "Wrongs" flags. */ + uint32_t wrongs; + uint32_t wrongs_curr; + + /** This flag equals one iff the secrets have been uploaded from the cache. */ + uint8_t is_ready; +} zrtp_secrets_t; + + +/** + * @brief Protocol shared secret + * Wrapper around the session shared secrets \ref zrtp_shared_secret. Used + * for ID storing and secret sorting according to ZRTP ID sec. 5.4.4. + */ +typedef struct zrtp_proto_secret_t +{ + /** Local-side secret ID */ + zrtp_string8_t id; + + /** Remote-side secret ID */ + zrtp_string8_t peer_id; + + /** Pointer to the binary value and set of related flags */ + zrtp_shared_secret_t *secret; +} zrtp_proto_secret_t; + + +/** + * @brief ZRTP messages cache + * This structure contains ZRTP messages prepared for sending or received from + * the other side. This scheme allows speed-ups the resending of packets and + * computing message hashes, and makes resending thread-safe. Besides packets, + * tasks retries are stored as well. + */ +typedef struct zrtp_stream_mescache_t +{ + zrtp_packet_Hello_t peer_hello; + zrtp_packet_Hello_t hello; + zrtp_packet_GoClear_t goclear; + zrtp_packet_Commit_t peer_commit; + zrtp_packet_Commit_t commit; + zrtp_packet_DHPart_t peer_dhpart; + zrtp_packet_DHPart_t dhpart; + zrtp_packet_Confirm_t confirm; + zrtp_string32_t h0; + zrtp_packet_Confirm_t peer_confirm; + zrtp_packet_Error_t error; + zrtp_packet_SASRelay_t sasrelay; + + zrtp_retry_task_t hello_task; + zrtp_retry_task_t goclear_task; + zrtp_retry_task_t dh_task; + zrtp_retry_task_t commit_task; + zrtp_retry_task_t dhpart_task; + zrtp_retry_task_t confirm_task; + zrtp_retry_task_t error_task; + zrtp_retry_task_t errorack_task; + zrtp_retry_task_t sasrelay_task; + + zrtp_string16_t signaling_hash; +} zrtp_stream_mescache_t; + + +/** + * @brief Crypto context for Diffie-Hellman calculations + * Used only by DH streams to store Diffie-Hellman calculations. Allocated on + * protocol initialization and released on switching to SECURE mode. + */ +typedef struct zrtp_dh_crypto_context_t +{ + /** DH secret value */ + struct BigNum sv; + + /** DH public value */ + struct BigNum pv; + + /** DH public value precalculated for remote side */ + struct BigNum peer_pv; + + /** DH shared secret. DHSS = hash(DHResult) */ + zrtp_string64_t dhss; + + unsigned int initialized_with; +} zrtp_dh_crypto_context_t; + + +/*! + * \brief Crypto context for ECDSA calculations + * Used to store ECDSA keys and calculations. Allocated on + * protocol initialization and released on switching to SECURE mode. + */ +typedef struct zrtp_dsa_crypto_context_t +{ + struct BigNum sv; /*!< DSA secret value */ + struct BigNum pv; /*!< DSA public value */ + struct BigNum peer_pv;/*!< DSA public value for some remote side */ +} zrtp_dsa_crypto_context_t; + + +/** + * @brief Protocol crypto context + * Used as temporary storage for ZRTP crypto data during protocol running. + * Unlike \ref zrtp_stream_crypto_t this context is needed only during key + * negotiation and destroyed on switching to SECURE state. + */ +typedef struct zrtp_proto_crypto_t +{ + /** ZRTP */ + zrtp_string128_t kdf_context; + + /** ZRTP stream key */ + zrtp_string64_t s0; + + /** Local hvi value for the hash commitment: hvi or nonce for Multistream. */ + zrtp_string64_t hv; + + /** Remove hvi value for the hash commitment: hvi or nonce for Multistream. */ + zrtp_string64_t peer_hv; + + /** Total messages hash. See ZRTP ID 5.4.4/5.5.4 */ + zrtp_string64_t mes_hash; + + /** RS1 */ + zrtp_proto_secret_t rs1; + + /** RS2 */ + zrtp_proto_secret_t rs2; + + /** User-Defined secret */ + zrtp_proto_secret_t auxs; + + /** PBX secret */ + zrtp_proto_secret_t pbxs; +} zrtp_proto_crypto_t; + +/*! + * \brief ZRTP protocol structure + * Protocol structure is responsible for ZRTP protocol logic (CLEAR-SECURE + * switching) and RTP media encrypting/decrypting. The protocol is created + * right after the discovery phase and destroyed on stream closing. + */ +struct zrtp_protocol_t +{ + /** Protocol mode: responder or initiator. */ + zrtp_statemachine_type_t type; + + /** Context for storing protocol crypto data. */ + zrtp_proto_crypto_t* cc; + + /** SRTP crypto engine */ + zrtp_srtp_ctx_t* _srtp; + + /** Back-pointer to ZRTP stream context. */ + zrtp_stream_t *context; +}; + +/** + * @brief Stream-persistent crypto options. + * Unlike \ref zrtp_proto_crypto_t these data are kept after switching to Secure + * state or stopping the protocol; used to sign/verify Confirm and GoClear packets. + */ +typedef struct zrtp_stream_crypto_t +{ + /** Local side hmackey value. */ + zrtp_string64_t hmackey; + + /** Remote side hmackey value. */ + zrtp_string64_t peer_hmackey; + + /** Local side ZRTP key for Confirms protection. */ + zrtp_string64_t zrtp_key; + + /** Remote side ZRTP key for Confirms verification. */ + zrtp_string64_t peer_zrtp_key; +} zrtp_stream_crypto_t; + + +/** + * @brief stream media context. Contains all RTP media-related information. + */ +typedef struct zrtp_media_context_t +{ + /** The highest ZRTP message sequence number received. */ + uint32_t high_in_zrtp_seq; + + /** The last ZRTP message sequence number sent. */ + uint32_t high_out_zrtp_seq; + + /** The highest RTP media sequence number received; used by SRTP. */ + uint32_t high_in_media_seq; + + /** The highest RTP media sequence number sent; used by SRTP. */ + uint32_t high_out_media_seq; + + /** SSRC of the RTP media stream associated with the current ZRTP stream. */ + uint32_t ssrc; +} zrtp_media_context_t; + +/*! + * \brief ZRTP stream context + * \warning Fields with prefix "_" are for internal use only. + */ +struct zrtp_stream_t +{ + /*! Stream unique identifier for debug purposes */ + zrtp_id_t id; + + /*! + * \brief Stream mode + * This field defines libzrtp behavior related to specified contexts. See + * "ZRTP Internet Draft" + * and \ref usage for additional information about stream types and their + * processing logic. + */ + zrtp_stream_mode_t mode; + + /*! + * \brief Defines ZRTP role in trusted MitM scheme. + * The value of this mode determines the behavior of the ZRTP machine + * according to it's role in the MitM scheme. Initially the mode is + * ZRTP_MITM_MODE_UNKN and then changes on protocol running. + */ + zrtp_mitm_mode_t mitm_mode; + + /*! + * \brief Previous ZRTP protocol states + * Used in analysis to determine the reason for a switch from one state to + * another. Enabled by _zrtp_change_state(. + */ + zrtp_state_t prev_state; + + /*!< Reflects current state of ZRTP protocol */ + zrtp_state_t state; + + /** + * @brief Persistent stream crypto options. + * Stores persistent crypto data needed after Confirmation. This data can be + * cleared only when the stream is destroyed. + */ + zrtp_stream_crypto_t cc; + + /** DH crypto context used in PK calculations */ + zrtp_dh_crypto_context_t dh_cc; + + /*! + * \brief Pointer to the ZRTP protocol implementation + * The protocol structure stores all crypto data during the securing + * procedure. After switching to SECURE state the protocol clears all + * crypto sources and performs traffic encryption/decryption. + */ + zrtp_protocol_t *protocol; + + /*! + * Hash pre-image of the remote party Hello retrieved from Signaling. When + * user calls zrtp_signaling_hash_set() libzrtp stores hash value in this + * variable and checks all incoming Hellos to prevent DOS attacks. + */ + zrtp_string128_t signaling_hash; + + /*!< Holder for RTP/ZRTP media stream options. */ + zrtp_media_context_t media_ctx; + + /*!< ZRTP messages and task retries cache */ + zrtp_stream_mescache_t messages; + + /*! + * Current value of "allowclear" option exchanged during ZRTP negotiation. + * Available for reading in SECURE state. + */ + uint8_t allowclear; + + /*! + * This flag shows when remote side is "pasice" (has license mode PASSIVE) + * Available for reading in CLEAR state. + */ + uint8_t peer_passive; + + /*! + * \brief actual lifetime of stream secrets + * This variable contains the interval for retaining secrets within an + * established stream. In accordance with "ZRTP Internet Draft" + * this value is calculated as the minimal of local and remote TTLs after + * confirmation. Value is given in seconds and can be read in the SECURE + * state. It may be used in displaying session parameters. + */ + uint32_t cache_ttl; + + /*! + * \brief Peer disclose bit Indicates the ability of the remote side to + * disclose its session key. Specifies that the remote side allows call + * monitoring. If this flag is set, the end user must be informed. It can + * be read in the SECURE state. + */ + uint8_t peer_disclose_bit; + + /*! + * \brief Last protocol error code + * If there is a mistake in running the protocol, zrtp_event_callback() + * will be called and the required error code will be set to this field. + * An error code is the numeric representation of ZRTP errors defined in + * the draft. All error codes are defined by \ref zrtp_protocol_error_t. + */ + zrtp_protocol_error_t last_error; + + /** + * Duplicates MiTM flag from peer Hello message + */ + uint8_t peer_mitm_flag; + + /*! + * \brief Pointer to the concurrent DH stream + * If Commit messages are sent by both ZRTP endpoints at the same time, but + * are received in different media streams, "tie-breaking" rules apply - the + * Commit message with the lowest hvi value is discarded and the other side + * becomes the initiator. The media stream in which the Commit was sent will + * proceed through the ZRTP exchange while the media stream with the discarded + * Commit must wait for the completion of the other ZRTP exchange. A pointer + * to that "waiting" stream is stored in \c _concurrent. When the running + * stream is switched to "Initiating Secure" the concurrent stream is resumed. + */ + zrtp_stream_t *concurrent; + + /** Back-pointer to the ZRTP global data */ + zrtp_global_t *zrtp; + + /** Pointer to paren t-session context. Used for back capability */ + zrtp_session_t *session; + + /*!< Public key exchange component used within current stream */ + zrtp_pk_scheme_t *pubkeyscheme; + + /*! + * Pointer to the user data. This pointer can be used for fast access to + * some additional data attached to this ZRTP stream by the user application + */ + void *usr_data; + + /*! + * \brief Stream data protector + * A mutex is used to avoid race conditions during asynchronous calls + * (zrtp_stream_secure(), zrtp_stream_clear() etc.) in parallel to the main + * processing loop zrtp_process_rtp/srtp(). + */ + zrtp_mutex_t* stream_protector; +}; + + +/*! + * \brief ZRTP session context + * Describes the state of the ZRTP session. Stores data necessary and sufficient + * for processing ZRTP sessions. Encapsulates ZRTP streams and all crypto-data. + */ +struct zrtp_session_t +{ + /*! Session unique identifier for debug purposes */ + zrtp_id_t id; + + /*! + * \brief Local-side ZID + * The unique 12-characters string that identifies the local ZRTP endpoint. + * It must be generated by the user application on installation and used + * permanently for every ZRTP session. This ID allows remote peers to + * recognize this ZRTP endpoint. + */ + zrtp_string16_t zid; + + /*! + * \brief Remote-side ZID + * Extracted from the Hello packet of the very first ZRTP stream. Uniquely + * identifies the remote ZRTP peer. Used in combination with the local zid + * to restore secrets and other data from the previous call. Available for + * reading after the discovering phase. + */ + zrtp_string16_t peer_zid; + + /*!< ZRTP profile, defined crypto options and behavior for every stream within cirrent session */ + zrtp_profile_t profile; + + /** Define endpoint Signaling role. Different from ZRTP Initiator/Responder role */ + uint8_t is_initiator; + + /*! + * \brief Set of retained secrets and flags for the current ZRTP session. + * libzrtp uploads secrets and flags from the cache on the very first + * stream within every ZRTP session. + */ + zrtp_secrets_t secrets; + + /*!< ZRTP session key used to extand ZRTP session without additional DH exchange */ + zrtp_string64_t zrtpsess; + + /** First SAS base32/256 string */ + zrtp_string16_t sas1; + + /** Second SAS 256 string */ + zrtp_string16_t sas2; + + /** Binary SAS digest (ZRTP_SAS_DIGEST_LENGTH bytes) */ + zrtp_string32_t sasbin; + + /*!< Back-pointer to the ZRTP global data */ + zrtp_global_t *zrtp; + + /*!< Back-pointer to user data associated with this session context. */ + void *usr_data; + + /** Hash component used within current session */ + zrtp_hash_t *hash; + + /** Cipher component used within current session */ + zrtp_cipher_t *blockcipher; + + /** SRTP authentication component used within current session */ + zrtp_auth_tag_length_t *authtaglength; + + /** SAS scheme component used within current session */ + zrtp_sas_scheme_t *sasscheme; + + /** List of ZRTP streams attached to the session. */ + zrtp_stream_t streams[ZRTP_MAX_STREAMS_PER_SESSION]; + + /** This object is used to synchronize all stream list operations */ + zrtp_mutex_t* streams_protector; + + /** Prevents race conditions if streams start simultaneously. */ + zrtp_mutex_t* init_protector; + + /** + * This flag indicates that possible MiTM attach was detected during the protocol exchange. + */ + uint8_t mitm_alert_detected; + + mlist_t _mlist; +}; + +/*! \} */ + + +/*===========================================================================*/ +/* Data types and definitions for SRTP */ +/*===========================================================================*/ + +#if ZRTP_BYTE_ORDER == ZBO_LITTLE_ENDIAN + +/** + * RTP header structure + * @ingroup dev_srtp + */ +typedef struct +{ + uint16_t cc:4; /** CSRC count */ + uint16_t x:1; /** header extension flag */ + uint16_t p:1; /** padding flag */ + uint16_t version:2; /** protocol version */ + uint16_t pt:7; /** payload type */ + uint16_t m:1; /** marker bit */ + uint16_t seq; /** sequence number */ + uint32_t ts; /** timestamp */ + uint32_t ssrc; /** synchronization source */ +} zrtp_rtp_hdr_t; + +/** + * RTCP header structure + * @ingroup dev_srtp + */ +typedef struct +{ + unsigned char rc:5; /** reception report count */ + unsigned char p:1; /** padding flag */ + unsigned char version:2; /** protocol version */ + unsigned char pt:8; /** payload type */ + uint16_t len; /** length */ + uint32_t ssrc; /** synchronization source */ +} zrtp_rtcp_hdr_t; + +typedef struct +{ + unsigned int index:31; /** srtcp packet index in network order! */ + unsigned int e:1; /** encrypted? 1=yes */ + /** optional mikey/etc go here */ + /** and then the variable-length auth tag */ +} zrtp_rtcp_trailer_t; + +#else + +/** + * RTP header structure + * @ingroup dev_srtp + */ +typedef struct +{ + uint16_t version:2; /** protocol version */ + uint16_t p:1; /** padding flag */ + uint16_t x:1; /** header extension flag */ + uint16_t cc:4; /** CSRC count */ + uint16_t m:1; /** marker bit */ + uint16_t pt:7; /** payload type */ + uint16_t seq; /** sequence number */ + uint32_t ts; /** timestamp */ + uint32_t ssrc; /** synchronization source */ +} zrtp_rtp_hdr_t; + +/** + * RTCP header structure + * @ingroup dev_srtp + */ +typedef struct +{ + unsigned char version:2; /** protocol version */ + unsigned char p:1; /** padding flag */ + unsigned char rc:5; /** reception report count */ + unsigned char pt:8; /** payload type */ + uint16_t len; /** length */ + uint32_t ssrc; /** synchronization source */ +} zrtp_rtcp_hdr_t; + +typedef struct +{ + unsigned int e:1; /** encrypted? 1=yes */ + unsigned int index:31; /** srtcp packet index */ +} zrtp_rtcp_trailer_t; + +#endif + +/** + * RTP header extension structure + * @ingroup dev_srtp + */ +typedef struct +{ + uint16_t profile_specific; /** profile-specific info */ + uint16_t length; /** number of 32-bit words in extension */ +} zrtp_rtp_hdr_xtnd_t; + + +/** \endmanonly */ + +#endif /* __ZRTP_TYPES_H__ */ diff --git a/include/zrtp_version.h b/include/zrtp_version.h new file mode 100644 index 0000000000..8ddb68b193 --- /dev/null +++ b/include/zrtp_version.h @@ -0,0 +1,19 @@ +/* + * 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 + */ + +#ifndef __ZRTP_VERSION_H__ +#define __ZRTP_VERSION_H__ + +#define LIBZRTP_VERSION_MAJOR 1 + +#define LIBZRTP_VERSION_MINOR 0 +#define LIBZRTP_VERSION_BUILD 591 +#define LIBZRTP_VERSION_STR "v1.00 590" + +#endif /*__ZRTP_VERSION_H__*/ diff --git a/projects/gnu/AUTHORS b/projects/gnu/AUTHORS new file mode 100644 index 0000000000..5d67c092cd --- /dev/null +++ b/projects/gnu/AUTHORS @@ -0,0 +1,30 @@ +libzrtp betta +Copyright (c) 2005-2008 Philip Zimmermann. All rights reserved. +Contact Phil at: www.philzimmermann.com +Visit the Zfone Project Home Page http://zfoneproject.com/ +Report bugs via the Zfone Bugs Page http://zfoneproject.com/bugs.html + +Created by Phil Zimmermann. + +Developers: + Viktor Krikun + Nikolay Popok + Vitaly Rozhkov + Andrey Rozinko + Bryce Wilcox-O'Hearn + +Thanks to: + Alan Johnston + Jon Callas + Hal Finney + Colin Plumb + Sagar Pai + Werner Dittmann + L. Amber Wilcox-O'Hearn + Ariel Boston + Donovan Preston + +Software development services provided by Svitla Systems and http://www.soft-industry.com/en. + +Portions of this software are available under open source licenses from other authors. +Notably, Brian Gladman's AES implementation, and David McGrew's libSRTP package. diff --git a/projects/gnu/COPYING b/projects/gnu/COPYING new file mode 100644 index 0000000000..ac0efbec90 --- /dev/null +++ b/projects/gnu/COPYING @@ -0,0 +1,7 @@ +/* + * 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. + */ + \ No newline at end of file diff --git a/projects/gnu/ChangeLog b/projects/gnu/ChangeLog new file mode 100644 index 0000000000..709dcbe6f8 --- /dev/null +++ b/projects/gnu/ChangeLog @@ -0,0 +1 @@ +Change Log is available at [https://developers.zfoneproject.com/libzrtp/wiki/LibzrtpChangeLog] \ No newline at end of file diff --git a/projects/gnu/INSTALL b/projects/gnu/INSTALL new file mode 100644 index 0000000000..16a3c821ff --- /dev/null +++ b/projects/gnu/INSTALL @@ -0,0 +1,255 @@ +/* + * 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 + */ + +Basic Installation +================================================================================ + + To start playing with Zfone and libzrtp you should install few developers +packages on your machine: gcc and g++ compilers, automake and autoconf tools. + + To install library as a Zfone component for Linux the following flags +should be used: BUILD_DEBUG_LOG, BUILD_WITH_CFUNC, BUILD_DEFAULT_CACHE, +BUILD_DEFAULT_TIMER and WITH_ZFONE. + The following instructions are for experienced users and developers only. +If you just want to install Zfone use the command as follows: +./configure CFLAGS="-O0 -g3 -W -Wall -DBUILD_DEBUG_LOG -DBUILD_WITH_CFUNC +-DBUILD_DEFAULT_CACHE -DBUILD_DEFAULT_TIMER -DWITH_ZFONE" + +Library distribution contains installation and configuration files, project files +for several Operation Systems. To install Library on Unix-like systems the +autotools tool set is used. To install on Windows - Microsoft Visual Studio. +Except standard for your system compile flags the following are available for +your system: +-# -DBUILD_DEBUG_LOG - enables debug and logging information + This flag is recommended to be used at design stages for testing. Logs make + debug process much easier and are to be included into bugreport. +-# -DBUILD_WITH_CFUNC - assign to the library to gather standard for this + platform system interface functions realizations. This option simplifies the + library use and make code more compact. You can have a look at realizations + in src/zrtp-iface.c. file. And if they suit you use this flag. +-# -DBUILD_EMPTY_CACHE this flag assigns to the library to use empty stubs + instead of operations with cache. This checkbox may be used in test + applications or in systems where cache secrets storing is impossible. Be + careful with this flag! Use it if it is really necessary. +-# -DBUILD_EMPTY_TIMER this flag assigns to the library to use empty stubs + instead of delayed tasks processing. This checkbox may be used in test + applications or in systems with the reliable communication channel (the + package loss is impossible). Be careful with this flag! Use it if it is + really necessary. + +Except library itself, the set of utilities for the all components workability +check on the basis of a certain platform is provided. libzrtp test creates +several parallel ZRTP sessions, initiates transfer to the protected mode, +displays statistics, after which the application is stopped. If application test +was completed successfully the library is configured correctly, all components +work correctly. Note! Installation of test application is carried out with +-DBUILD_EMPTY_CACHE -DBUILD_EMPTY_TIMER flags. After fulfilling tests reinstall +library without use of these flags. + +Further instructions must be followed in order to build and set up the library in +any Unix-like operation system (Linux, FreeBSD, MacOS): + -# Download source codes from zfoneproject.com + -# Decompress the archive libzrtp-0.3.X.tzr.gz : tar -zxf ./libzrtp-0.3.X.tzr.gz + and open cd libzrtp-0.3.X directory + -# Configure the library: ./configure (use necessary compollation flags) + -# Build the library: make + -# If you get the errors during, please send a full log of configuration + and building process to zfone-bugs@philzimmermann.com. Please specify + the operation system, hardware platform, compiler version and other + environmental parameters. Any proposals will be taken into account when + developing new versions. + -# After te library successful building, run setup (installation): ./make install + -# to build test unites run ./configure with CFLAGS="-DBUILD_DEBUG_LOG + -DBUILD_WITH_CFUNC -DBUILD_EMPTY_CACHE -DBUILD_EMPTY_TIMER and parameter + --enable-test. After successful configuration start test: "make check". + This command will build and run all test (bnlib test, srtp tests and + libzrtp tests) Don't forget to rebuild library without -DBUILD_EMPTY_CACHE + -DBUILD_EMPTY_TIMER. + +For library configuration and installation on Windows platform the followinf +files should be used: + -# For installation with the Microsoft Visual Studio v6 use: + - libzrtp.dsw + - libzrtp.dsp + - test\libzrtp_test.dsp + -# For installation with the Microsoft Visual Studio v7 use: + - libzrtp.sln + - libzrtp.vcproj + - test\libzrtp_test.vcproj + -# If you want to build libzrtp in Windows kernel mode you mast use MAKEFILE.WIN32 + +For 32-bit machines bnlib contains assemble file lbn80386.asm. The assembler is +needed to install it. The compiler ml is in the stracture of VS7, if you use VS6 +you can use Microsoft Macro Assembler (http://www.masm32.com/masmdl.htm). To +compile this file you have define in properties: Commands: \ml /c /Cx +/coff /Fo $(TargetDir)\$(InputName).obj $(InputPath) Outputs: $(TargetDir)\$(InputName).obj + where is a complete path to the compiler. + +Possible problems and methods of the solution: + -# Some environment problems with automatic definition of architecture + and byte-order are possible at library building. We recommend before building + of libZRTP on a new program or hardware platform uncomment the test-unite at + the end of the file \c zrtp_syste.h. If there is a mistakes in definition of + architecture or byte-order use zrtp_system.h manual configuration following + the comments. + +Please take into account the fact that libzrtp developers are not responsible for +external modules of the library. In other words, the functionality of the library +was tested under majority of widespread Linux and Windows systems, but warnings +can still occur during these modules compilation. + +If you have faced with some problems during configuration or installing of the +library - send a report to the Support Service. If you installed library on the +platform not described here, please contact the Support Service. We are +interested very much to get know the results of testing on new platforms. We +will carefully examine all proposals and will do our best to realize them in new +library versions. + + +Compilers and Options +================= + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +================= + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/include', `/usr/local/lib', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +will cause the specified gcc to be used as the C compiler (unless it is +overridden in the site shell script). + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. diff --git a/projects/gnu/Makefile.am b/projects/gnu/Makefile.am new file mode 100644 index 0000000000..48b8c578a5 --- /dev/null +++ b/projects/gnu/Makefile.am @@ -0,0 +1,57 @@ +# +# Copyright (c) 2006-2007 Philip R. Zimmermann. All rights reserved. +# Contact: http://philzimmermann.com +# +# Viktor Krikun +# + +TEST_DIR=$(top_srcdir)/../../test +TOP_SRCDIR=$(top_srcdir)/../../include +THIRD_DIR=$(top_srcdir)/../../third_party + +libzrtp_includedir=$(includedir)/libzrtp + +libzrtp_include_HEADERS = \ + $(TOP_SRCDIR)/zrtp.h \ + $(TOP_SRCDIR)/zrtp_base.h \ + $(TOP_SRCDIR)/zrtp_config.h \ + $(TOP_SRCDIR)/zrtp_config_user.h \ + $(TOP_SRCDIR)/zrtp_config_unix.h \ + $(TOP_SRCDIR)/zrtp_crypto.h \ + $(TOP_SRCDIR)/zrtp_engine.h \ + $(TOP_SRCDIR)/zrtp_error.h \ + $(TOP_SRCDIR)/zrtp_iface.h \ + $(TOP_SRCDIR)/zrtp_iface_scheduler.h \ + $(TOP_SRCDIR)/zrtp_iface_cache.h \ + $(TOP_SRCDIR)/zrtp_iface_system.h \ + $(TOP_SRCDIR)/zrtp_legal.h \ + $(TOP_SRCDIR)/zrtp_list.h \ + $(TOP_SRCDIR)/zrtp_log.h \ + $(TOP_SRCDIR)/zrtp_pbx.h \ + $(TOP_SRCDIR)/zrtp_protocol.h \ + $(TOP_SRCDIR)/zrtp_srtp.h \ + $(TOP_SRCDIR)/zrtp_srtp_builtin.h \ + $(TOP_SRCDIR)/zrtp_string.h \ + $(TOP_SRCDIR)/zrtp_types.h \ + $(TOP_SRCDIR)/zrtp_version.h \ + \ + $(THIRD_DIR)/bnlib/bn.h \ + \ + $(THIRD_DIR)/bgaes/aes.h \ + $(THIRD_DIR)/bgaes/aesopt.h \ + $(THIRD_DIR)/bgaes/aestab.h \ + $(THIRD_DIR)/bgaes/bg2zrtp.h \ + $(THIRD_DIR)/bgaes/brg_types.h \ + $(THIRD_DIR)/bgaes/sha1.h \ + $(THIRD_DIR)/bgaes/sha2.h + +if ZRTP_BUILD_ENTERPRISE +libzrtp_include_HEADERS += $(TOP_SRCDIR)/zrtp_ec.h +endif + +SUBDIRS = ../../third_party/bnlib +SUBDIRS += build + +uninstall: + rm -rf $(prefix)/include/libzrtp + rm -f $(prefix)/lib/libzrtp.a diff --git a/projects/gnu/NEWS b/projects/gnu/NEWS new file mode 100644 index 0000000000..e69de29bb2 diff --git a/projects/gnu/README b/projects/gnu/README new file mode 100644 index 0000000000..e69de29bb2 diff --git a/projects/gnu/autoreconf.sh b/projects/gnu/autoreconf.sh new file mode 100755 index 0000000000..fb8e583f63 --- /dev/null +++ b/projects/gnu/autoreconf.sh @@ -0,0 +1,5 @@ +#!/bin/bash +aclocal -I ./config/ +autoheader +autoconf +automake diff --git a/projects/gnu/build/Makefile.am b/projects/gnu/build/Makefile.am new file mode 100644 index 0000000000..8d6e0a0a45 --- /dev/null +++ b/projects/gnu/build/Makefile.am @@ -0,0 +1,56 @@ +# +# Copyright (c) 2006-2009 Philip R. Zimmermann. All rights reserved. +# Contact: http://philzimmermann.com +# +# Viktor Krikun +# + +TOP_SRCDIR=$(top_srcdir)/../.. +INCLUDES = -I$(TOP_SRCDIR)/include \ + -I$(TOP_SRCDIR)/. \ + -I$(TOP_SRCDIR)/third_party/bgaes \ + -I$(TOP_SRCDIR)/third_party/bnlib + +lib_LIBRARIES = libzrtp.a + +libzrtp_a_LIBADD = $(TOP_SRCDIR)/third_party/bnlib/libbn.a + +libzrtp_a_SOURCES = $(TOP_SRCDIR)/src/zrtp.c \ + $(TOP_SRCDIR)/src/zrtp_crc.c \ + $(TOP_SRCDIR)/src/zrtp_crypto_aes.c \ + $(TOP_SRCDIR)/src/zrtp_crypto_atl.c \ + $(TOP_SRCDIR)/src/zrtp_crypto_hash.c \ + $(TOP_SRCDIR)/src/zrtp_crypto_pk.c \ + $(TOP_SRCDIR)/src/zrtp_crypto_sas.c \ + $(TOP_SRCDIR)/src/zrtp_datatypes.c \ + $(TOP_SRCDIR)/src/zrtp_engine.c \ + $(TOP_SRCDIR)/src/zrtp_iface_scheduler.c \ + $(TOP_SRCDIR)/src/zrtp_iface_sys.c \ + $(TOP_SRCDIR)/src/zrtp_initiator.c \ + $(TOP_SRCDIR)/src/zrtp_legal.c \ + $(TOP_SRCDIR)/src/zrtp_list.c \ + $(TOP_SRCDIR)/src/zrtp_log.c \ + $(TOP_SRCDIR)/src/zrtp_pbx.c \ + $(TOP_SRCDIR)/src/zrtp_protocol.c \ + $(TOP_SRCDIR)/src/zrtp_responder.c \ + $(TOP_SRCDIR)/src/zrtp_rng.c \ + $(TOP_SRCDIR)/src/zrtp_srtp_builtin.c \ + $(TOP_SRCDIR)/src/zrtp_string.c \ + $(TOP_SRCDIR)/src/zrtp_utils.c \ + $(TOP_SRCDIR)/src/zrtp_utils_proto.c \ + \ + $(TOP_SRCDIR)/third_party/bgaes/aes_modes.c \ + $(TOP_SRCDIR)/third_party/bgaes/aescrypt.c \ + $(TOP_SRCDIR)/third_party/bgaes/aeskey.c \ + $(TOP_SRCDIR)/third_party/bgaes/aestab.c \ + $(TOP_SRCDIR)/third_party/bgaes/sha1.c \ + $(TOP_SRCDIR)/third_party/bgaes/sha2.c\ + \ + $(TOP_SRCDIR)/src/zrtp_iface_cache.c \ + $(TOP_SRCDIR)/src/zrtp_engine_driven.c +if ZRTP_BUILD_ENTERPRISE +libzrtp_a_SOURCES +=$(TOP_SRCDIR)/src/zrtp_crypto_ec.c \ + $(TOP_SRCDIR)/src/zrtp_crypto_ecdh.c +endif + +SUBDIRS = test diff --git a/projects/gnu/build/test/Makefile.am b/projects/gnu/build/test/Makefile.am new file mode 100644 index 0000000000..5c1f3886a0 --- /dev/null +++ b/projects/gnu/build/test/Makefile.am @@ -0,0 +1,43 @@ + +# Copyright (c) 2006-2009 Philip R. Zimmermann. All rights reserved. +# Contact: http://philzimmermann.com +# +# Viktor Krikun +# + + + +TOP_SRCDIR=$(top_srcdir)/../.. +INCLUDES = -I$(TOP_SRCDIR)/include \ + -I$(TOP_SRCDIR)/include/enterprise \ + -I$(TOP_SRCDIR)/. \ + -I$(TOP_SRCDIR)/third_party/bgaes \ + -I$(TOP_SRCDIR)/third_party/bnlib + + +check_PROGRAMS = libzrtp_test + +libzrtp_test_SOURCES = $(TOP_SRCDIR)/test/pc/zrtp_test_core.c \ + $(TOP_SRCDIR)/test/pc/zrtp_test_crypto.c \ + $(TOP_SRCDIR)/test/pc/zrtp_test_queue.c \ + $(TOP_SRCDIR)/test/pc/zrtp_test_ui.c + +libzrtp_test_LDADD = ../libzrtp.a \ + $(TOP_SRCDIR)/third_party/bnlib/libbn.a -lpthread + +SUBDIRS = . + +check: + @echo "" + @echo "*========================================================================*" + @echo "* starting libZRTP tests *" + @echo "*========================================================================*" + @echo "" + @./libzrtp_test + + @echo "" + @echo "*========================================================================*" + @echo "* In case you have a test FAILED send the generated log file *" + @echo "* with your comment to . *" + @echo "*========================================================================*" + @echo "" diff --git a/projects/gnu/cfg b/projects/gnu/cfg new file mode 100755 index 0000000000..8f19122fb7 --- /dev/null +++ b/projects/gnu/cfg @@ -0,0 +1,2 @@ +#!/bin/bash +./configure --enable-enterprise \ No newline at end of file diff --git a/projects/gnu/configure.in b/projects/gnu/configure.in new file mode 100644 index 0000000000..4e53494d69 --- /dev/null +++ b/projects/gnu/configure.in @@ -0,0 +1,96 @@ +# +# 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 Krikun +# + +AC_INIT() + +AC_CONFIG_AUX_DIR(config) +AC_CONFIG_HEADER(config/config.h) + +# Checks for target OS +AC_CANONICAL_TARGET + +case $target_os in + aix*) ;; + *mingw* | *cygw* | *win32* | *w32* ) + echo "------- START libzrtp configuration for Windows platform ------------" + ;; + *darwin*) + echo "------- START libzrtp configuration for Darwin platform ------------" + ;; + *freebsd2* | *freebsd* | *netbsd* | *openbsd* | *osf[12]*) + echo "------- START libzrtp configuration for BSD platform ------------" + AC_DEFINE(PLATFORM,ZP_BSD,BSD platform) + ;; + hpux* | irix* | linuxaout* | linux* | osf* | solaris2* | sunos4*) + echo "------- START libzrtp configuration for Linux platform ------------" + ;; +esac + + +AM_INIT_AUTOMAKE([libzrtp], [0.91]) +AX_PREFIX_CONFIG_H(../../include/zrtp_config_unix.h,ZRTP,config/config.h) + +CFLAGS="$CFLAGS -Wno-unused-parameter -fno-strict-aliasing -fPIC -DZRTP_AUTOMAKE=1" + +# Configuring external libraries +echo "========================= configuring bnlib ==============================" +cd ./../../third_party/bnlib +./configure CFLAGS="$CFLAGS" +cd ../../projects/gnu +echo "================================ done ===================================" + +# Checks for programs. +AC_PROG_CC +AC_PROG_CXX +AC_PROG_RANLIB + +# Apply configure options +AC_ARG_ENABLE(enterprise, [ --enable-enterprise enable building of enterprise components).], enable_enterprise=$enableval,enable_enterprise="no") +AM_CONDITIONAL(ZRTP_BUILD_ENTERPRISE, [test "x$enable_enterprise" = "xyes"]) + +# Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS([linux/version.h endian.h]) +AC_CHECK_HEADERS([errno.h]) +AC_CHECK_HEADERS([asm/types.h]) +AC_CHECK_HEADERS([stdlib.h stdint.h stdarg.h]) +AC_CHECK_HEADERS([string.h strings.h]) +AC_CHECK_HEADERS([stdio.h unistd.h]) +AC_CHECK_HEADERS([inttypes.h sys/inttypes.h sys/types.h machine/types.h]) +AC_CHECK_HEADERS([pthread.h semaphore.h sys/time.h fcntl.h]) + +AC_CHECK_TYPES([int8_t,uint8_t,int16_t,uint16_t,int32_t,uint32_t,uint64_t,int64_t]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST + +# Checks for library functions. +AC_FUNC_MALLOC +AC_CHECK_FUNCS([memset memcpy malloc free]) +AC_CHECK_FUNCS([usleep]) +AC_CHECK_FUNCS([fopen fread]) +AC_CHECK_FUNCS([pthread_mutex_lock pthread_mutex_unlock pthread_mutex_init pthread_mutex_destroy]) +AC_CHECK_FUNCS([pthread_attr_init pthread_attr_setdetachstate pthread_create]) +AC_CHECK_FUNCS([sem_wait sem_trywait sem_post sem_unlink sem_destroy sem_open sem_init]) + +AC_CHECK_LIB([pthread], [main], [LIB_PTHREAD="-lpthread"], [echo " Couldn't find library pthread";]) + +# Other +AC_DEFINE(PRAGMA_PACK_PUSH,[#pragma pack(push, 1)],[Define pragma pack(push) for your platform]) +AC_DEFINE(PRAGMA_PACK_POP,[#pragma pack(pop)],[Define pragma pack(pop) for your platform]) +AC_DEFINE(INLINE,[static inline],[Define inline construction for your platform]) + +if test "x$enable_enterprise" = "xyes" ; then + AC_DEFINE(ENABLE_EC,1,Enterprise) + CFLAGS="$CFLAGS -DZRTP_ENABLE_EC=1" +fi + +AC_SUBST(ENABLE_EC) + +# Genearte Makefiles +AC_OUTPUT([Makefile build/Makefile build/test/Makefile]) diff --git a/projects/gnu/create_docs.sh b/projects/gnu/create_docs.sh new file mode 100755 index 0000000000..1999a1b14a --- /dev/null +++ b/projects/gnu/create_docs.sh @@ -0,0 +1,11 @@ +cd ../../doc +rm -f docs.tar.gz +rm -rf libzrtp-doc +echo "=================> start doxygen." +doxygen > /dev/null 2>&1 +mkdir libzrtp-doc +cp -Rf ./out/html/* ./libzrtp-doc +tar -zcvf ./libzrtp-doc.tar.gz ./libzrtp-doc >> /dev/null +rm -rf libzrtp-doc +mv libzrtp-doc.tar.gz ../projects/gnu +cd ../projects/gnu diff --git a/projects/gnu/create_pack.pl b/projects/gnu/create_pack.pl new file mode 100755 index 0000000000..e43b63ece3 --- /dev/null +++ b/projects/gnu/create_pack.pl @@ -0,0 +1,421 @@ +#!/usr/bin/perl + +use Getopt::Std; + +getopts("l:ehs", \%args); + +if ($args{h}) +{ + print "Usage: create_pack.pl [OPTION]...\n\n"; + print " -l file write down list of files\n"; + print " -e enterprise version\n"; + print " -s dont add version suffix to package name\n"; + print " -h this help\n\n"; + exit 1; +} + +#to create list of files: +if ($args{l}) +{ + create_files_list($args{l}); + exit 1; +} + +$enterprise = 0; +if ($args{e}) +{ + $enterprise = 1; +} + +if ($args{s}) +{ + $packdir="libzrtp"; +} +else +{ + $LIBZRTP_VERSION=`cat ../../include/zrtp_version.h | grep 'LIBZRTP_VERSION_STR' | awk '{print \$3, \$4}' | sed 's/"v\\(.*\\) \\(.*\\)"/\\1.\\2/'`; + chomp($LIBZRTP_VERSION); + $packdir="libzrtp-$LIBZRTP_VERSION"; +} + +if (-d $packdir) +{ + `rm -rf $packdir` +} + +mkdir $packdir; +create_array(); + +foreach $file(@array) +{ + if (!$enterprise && + (($file =~ m/\/enterprise/i) || + ($file =~ m/_ec.*(proj|sln)/i) || + ($file =~ m/_EC.*(WIN)/i) || + ($file =~ m/\/xcode/i))) + { + print "$file skipped\n"; + next; + } + + $path = "../../" . $file; + if (!-e $path) + { + print "[ERROR]: file $file doesn't exist!\n"; + `rm -rf $packdir`; + exit -1; + } + if (-d $path) + { + mkdir "$packdir/$file"; + } + else + { +# print "copying $path file\n"; + `cp $path $packdir/$file` + } +} + +if (!$enterprise) +{ + `cp -f ../../projects/win/libzrtp_not_ec.vcproj $packdir/projects/win/libzrtp.vcproj`; + `cp -f ../../projects/win_ce/libzrtp_wince_not_ec.vcproj $packdir/projects/win_ce/libzrtp_wince.vcproj`; + `cp -f ../../projects/win_kernel/MAKEFILE_NOT_EC.WIN64 $packdir/projects/win_kernel/MAKEFILE.WIN64`; + `cp -f ../../projects/win_kernel/MAKEFILE_NOT_EC.WIN32 $packdir/projects/win_kernel/MAKEFILE.WIN32`; + + `rm $packdir/include/zrtp_ec.h`; +# `rm $packdir/include/zrtp_iface_cache.h`; + `rm $packdir/src/zrtp_crypto_ecdsa.c`; + `rm $packdir/src/zrtp_crypto_ec.c`; +# `rm $packdir/src/zrtp_engine_driven.c`; + `rm $packdir/src/zrtp_crypto_ecdh.c`; +# `rm $packdir/src/zrtp_iface_cache.c`; +} + + +`find $packdir -name "._*" -delete`; + +$pack_name = $packdir; +if ($enterprise) +{ + $pack_name = $pack_name . "-ec"; +} + +$system = `uname -a`; +if ($system =~ m/darwin/i) +{ + `rm -rf $pack_name.zip`; + `zip -r $pack_name.zip $packdir`; +} +else +{ + `rm -rf $pack_name.tar.gz`; + `tar -zcvf $pack_name.tar.gz $packdir`; +} +`rm -rf $packdir`; +print "package was created\n"; + +#for item in $array; do +# echo "item:"$'\t'"$item" + +sub create_files_list() +{ + $path = `pwd`; + chop($path); + `cd ../..;find . -not -path *svn* -print | awk '{printf \"\\t\\t\\"%s\\",\\n\", \$1} ' > $path/$_[0];cd $path`; +} + + +sub create_array() +{ + @array = + ( + "./ChangeLog", + "./README", + "./AUTHORS", + "./projects", + "./projects/gnu", + "./projects/gnu/Makefile.am", + "./projects/gnu/Makefile.in", + "./projects/gnu/COPYING", + "./projects/gnu/aclocal.m4", + "./projects/gnu/configure", + "./projects/gnu/README", + "./projects/gnu/AUTHORS", + "./projects/gnu/configure.in", + "./projects/gnu/INSTALL", + "./projects/gnu/autoreconf.sh", + "./projects/gnu/config", + "./projects/gnu/config/config.guess", + "./projects/gnu/config/config.sub", + "./projects/gnu/config/config.h.in", + "./projects/gnu/config/install-sh", + "./projects/gnu/config/missing", + "./projects/gnu/config/prefix_config.m4", + "./projects/gnu/config/depcomp", + "./projects/gnu/NEWS", + "./projects/gnu/Makefile.in", + "./projects/gnu/build", + "./projects/gnu/build/Makefile.am", + "./projects/gnu/build/Makefile.in", + "./projects/gnu/build/test", + "./projects/gnu/build/test/Makefile.am", + "./projects/gnu/build/test/Makefile.in", + "./projects/gnu/ChangeLog", + "./projects/xcode", + "./projects/xcode/libzrtp.xcodeproj", + "./projects/xcode/libzrtp.xcodeproj/project.pbxproj", + "./projects/xcode/libzrtp_test.xcodeproj", + "./projects/xcode/libzrtp_test.xcodeproj/project.pbxproj", + "./projects/win_kernel", + "./projects/win_kernel/MAKEFILE.WIN64", + "./projects/win_kernel/MAKEFILE.WIN32", + "./projects/win", + "./projects/win/libzrtp.vcproj", + "./projects/win/libzrtp.sln", + "./projects/win/libzrtp_test.vcproj", + "./projects/win_ce", + "./projects/win_ce/libzrtp_test_wince.vcproj", + "./projects/win_ce/libzrtp_wince.sln", + "./projects/win_ce/libzrtp_wince.vcproj", + "./projects/symbian", + "./projects/symbian/bld.bat", + "./projects/symbian/bld.inf", + "./projects/symbian/bldgcce.bat", + "./projects/symbian/libzrtp.mmp", + "./projects/symbian/zrtp_iface_symb.cpp", + "./src", + "./src/zrtp.c", + "./src/zrtp_crc.c", + "./src/zrtp_crypto_aes.c", + "./src/zrtp_crypto_atl.c", + "./src/zrtp_crypto_hash.c", + "./src/zrtp_crypto_pk.c", + "./src/zrtp_crypto_sas.c", + "./src/zrtp_datatypes.c", + "./src/zrtp_engine.c", + "./src/zrtp_iface_scheduler.c", + "./src/zrtp_iface_sys.c", + "./src/zrtp_initiator.c", + "./src/zrtp_legal.c", + "./src/zrtp_list.c", + "./src/zrtp_log.c", + "./src/zrtp_pbx.c", + "./src/zrtp_protocol.c", + "./src/zrtp_responder.c", + "./src/zrtp_rng.c", + "./src/zrtp_srtp_builtin.c", + "./src/zrtp_srtp_dm.c", + "./src/zrtp_string.c", + "./src/zrtp_utils.c", + "./src/zrtp_utils_proto.c", + "./src/zrtp_crypto_ecdsa.c", + "./src/zrtp_crypto_ec.c", + "./src/zrtp_engine_driven.c", + "./src/zrtp_crypto_ecdh.c", + "./src/zrtp_iface_cache.c", + "./doc", + "./include", + "./include/zrtp.h", + "./include/zrtp_base.h", + "./include/zrtp_config.h", + "./include/zrtp_config_user.h", + "./include/zrtp_config_win.h", + "./include/zrtp_config_symbian.h", + "./include/zrtp_crypto.h", + "./include/zrtp_engine.h", + "./include/zrtp_error.h", + "./include/zrtp_ec.h", + "./include/zrtp_iface.h", + "./include/zrtp_iface_cache.h", + "./include/zrtp_iface_system.h", + "./include/zrtp_iface_scheduler.h", + "./include/zrtp_legal.h", + "./include/zrtp_list.h", + "./include/zrtp_log.h", + "./include/zrtp_pbx.h", + "./include/zrtp_protocol.h", + "./include/zrtp_srtp.h", + "./include/zrtp_srtp_builtin.h", + "./include/zrtp_string.h", + "./include/zrtp_types.h", + "./include/zrtp_version.h", + "./third_party", + "./third_party/bnlib", + "./third_party/bnlib/lbnmem.c", + "./third_party/bnlib/lbn00.c", + "./third_party/bnlib/bn16.c", + "./third_party/bnlib/bn32.c", + "./third_party/bnlib/bn.c", + "./third_party/bnlib/lbnppc.h", + "./third_party/bnlib/bnsize00.h", + "./third_party/bnlib/lbn32.h", + "./third_party/bnlib/lbn80386.h", + "./third_party/bnlib/lbn68020.h", + "./third_party/bnlib/germtest", + "./third_party/bnlib/jacobi.h", + "./third_party/bnlib/bn00.c", + "./third_party/bnlib/bnconfig.h", + "./third_party/bnlib/lbn8086.h", + "./third_party/bnlib/bntest00.c", + "./third_party/bnlib/germain.c", + "./third_party/bnlib/lbn960jx.h", + "./third_party/bnlib/sizetest.c", + "./third_party/bnlib/config.cache", + "./third_party/bnlib/bn68000.c", + "./third_party/bnlib/lbnalpha.h", + "./third_party/bnlib/cputime.h", + "./third_party/bnlib/legal.c", + "./third_party/bnlib/configure.lineno", + "./third_party/bnlib/configure", + "./third_party/bnlib/bnprint.c", + "./third_party/bnlib/bn8086.c", + "./third_party/bnlib/lbn68020.c", + "./third_party/bnlib/README.bntest", + "./third_party/bnlib/lbn8086.asm", + "./third_party/bnlib/lbn16.c", + "./third_party/bnlib/lbn32.c", + "./third_party/bnlib/legal.h", + "./third_party/bnlib/configure.in", + "./third_party/bnlib/lbn960jx.s", + "./third_party/bnlib/prime.h", + "./third_party/bnlib/bninit16.c", + "./third_party/bnlib/bninit32.c", + "./third_party/bnlib/files", + "./third_party/bnlib/ppcasm.h", + "./third_party/bnlib/lbn.h", + "./third_party/bnlib/README.bn", + "./third_party/bnlib/bnintern.doc", + "./third_party/bnlib/sieve.c", + "./third_party/bnlib/bn16.h", + "./third_party/bnlib/bn32.h", + "./third_party/bnlib/bnprint.h", + "./third_party/bnlib/sieve.h", + "./third_party/bnlib/cfg", + "./third_party/bnlib/lbn68000.h", + "./third_party/bnlib/lbnalpha.s", + "./third_party/bnlib/bntest16.c", + "./third_party/bnlib/bntest32.c", + "./third_party/bnlib/cfg.debug", + "./third_party/bnlib/lbnmem.h", + "./third_party/bnlib/germtest.c", + "./third_party/bnlib/prime.c", + "./third_party/bnlib/lbn68000.c", + "./third_party/bnlib/config.log", + "./third_party/bnlib/germain.h", + "./third_party/bnlib/kludge.h", + "./third_party/bnlib/Makefile.in", + "./third_party/bnlib/test", + "./third_party/bnlib/test/primetest.c", + "./third_party/bnlib/test/rsaglue.h", + "./third_party/bnlib/test/randpool.c", + "./third_party/bnlib/test/keys.c", + "./third_party/bnlib/test/primes.doc", + "./third_party/bnlib/test/rsatest.c", + "./third_party/bnlib/test/posix.h", + "./third_party/bnlib/test/legal.c", + "./third_party/bnlib/test/README.rsatest", + "./third_party/bnlib/test/rsaglue.c", + "./third_party/bnlib/test/kbmsdos.c", + "./third_party/bnlib/test/keygen.c", + "./third_party/bnlib/test/README.dsatest", + "./third_party/bnlib/test/types.h", + "./third_party/bnlib/test/random.c", + "./third_party/bnlib/test/md5.c", + "./third_party/bnlib/test/userio.h", + "./third_party/bnlib/test/md5.h", + "./third_party/bnlib/test/dsatest.c", + "./third_party/bnlib/test/pt.c", + "./third_party/bnlib/test/dhtest.c", + "./third_party/bnlib/test/sha.h", + "./third_party/bnlib/test/keygen.h", + "./third_party/bnlib/test/noise.h", + "./third_party/bnlib/test/first.h", + "./third_party/bnlib/test/README.dhtest", + "./third_party/bnlib/test/randtest.c", + "./third_party/bnlib/test/randpool.h", + "./third_party/bnlib/test/random.h", + "./third_party/bnlib/test/sha.c", + "./third_party/bnlib/test/noise.c", + "./third_party/bnlib/test/kbunix.c", + "./third_party/bnlib/test/kludge.h", + "./third_party/bnlib/test/keys.h", + "./third_party/bnlib/test/usuals.h", + "./third_party/bnlib/test/kb.h", + "./third_party/bnlib/CHANGES", + "./third_party/bnlib/bnconfig.hin", + "./third_party/bnlib/lbn80386.asm", + "./third_party/bnlib/jacobi.c", + "./third_party/bnlib/config.status", + "./third_party/bnlib/lbn16.h", + "./third_party/bnlib/lbn80386.s", + "./third_party/bnlib/lbn68360.s", + "./third_party/bnlib/bignum-ARM", + "./third_party/bnlib/bignum-ARM/lbnmem.c", + "./third_party/bnlib/bignum-ARM/sha256_core.s", + "./third_party/bnlib/bignum-ARM/lbnarm.h", + "./third_party/bnlib/bignum-ARM/config.h", + "./third_party/bnlib/bignum-ARM/cputime.h", + "./third_party/bnlib/bignum-ARM/lbn16.c", + "./third_party/bnlib/bignum-ARM/lbnarm.s", + "./third_party/bnlib/bignum-ARM/README-small-memory", + "./third_party/bnlib/bignum-ARM/sha256_arm.c", + "./third_party/bnlib/bignum-ARM/lbn.h", + "./third_party/bnlib/bignum-ARM/bntest16.c", + "./third_party/bnlib/bignum-ARM/lbnmem.h", + "./third_party/bnlib/bignum-ARM/kludge.h", + "./third_party/bnlib/bignum-ARM/lbn16.h", + "./third_party/bnlib/bn.doc", + "./third_party/bnlib/lbnppc.c", + "./third_party/bnlib/bn.h", + "./third_party/bgaes", + "./third_party/bgaes/sha1.h", + "./third_party/bgaes/sha1.c", + "./third_party/bgaes/brg_types.h", + "./third_party/bgaes/aestab.c", + "./third_party/bgaes/aestab.h", + "./third_party/bgaes/sha2.h", + "./third_party/bgaes/aes_modes.c", + "./third_party/bgaes/aescrypt.c", + "./third_party/bgaes/bg2zrtp.h", + "./third_party/bgaes/aeskey.c", + "./third_party/bgaes/sha2.c", + "./third_party/bgaes/aes.h", + "./third_party/bgaes/aesopt.h", + "./test", + "./test/README", + "./test/pc", + "./test/pc/zrtp_test_core.c", + "./test/pc/zrtp_test_core.h", + "./test/pc/zrtp_test_crypto.c", + "./test/pc/zrtp_test_queue.c", + "./test/pc/zrtp_test_queue.h", + "./test/pc/zrtp_test_ui.c", + "./test/win_ce", + "./test/win_ce/libzrtp_test_GUI.cpp", + "./test/win_ce/libzrtp_test_GUI.h", + "./test/win_ce/libzrtp_test_GUI.ico", + "./test/win_ce/libzrtp_test_GUIppc.rc", + "./test/win_ce/libzrtp_test_GUIppc.rc2", + "./test/win_ce/libzrtp_test_GUIsp.rc", + "./test/win_ce/libzrtp_test_GUIsp.rc2", + "./test/win_ce/ReadMe.txt", + "./test/win_ce/resourceppc.h", + "./test/win_ce/resourcesp.h", + "./test/win_ce/stdafx.cpp", + "./test/win_ce/stdafx.h", + "./doc", + "./doc/img", + "./doc/manuals", + "./doc/manuals/howto.dox", + "./doc/manuals/main.dox", + "./doc/manuals/rng.dox", + "./doc/out", + "./doc/out/html", + "./doc/out/html/zfone.jpg", + "./doc/Doxyfile", + "./doc/doxygen.css", + "./doc/footer.html", + "./doc/header.html" + ) +} diff --git a/projects/symbian/DelayRuner.cpp b/projects/symbian/DelayRuner.cpp new file mode 100644 index 0000000000..c9e6fb7892 --- /dev/null +++ b/projects/symbian/DelayRuner.cpp @@ -0,0 +1,79 @@ +/* + ============================================================================ + Name : CDelayRuner.cpp + Author : R. Drutsky + Version : 1.0 + Copyright : Copyright (c) 2010 Soft Industry + Description : CCDelayRuner implementation + ============================================================================ + */ + +#include "DelayRuner.h" +#include "zrtp_iface_system.h" + +void zrtp_internal_delete_task_from_list(zrtp_stream_t* ctx, zrtp_retry_task_t* ztask); + +CDelayRuner::CDelayRuner() : + CActive(EPriorityLow) // Standard priority + { + } + +CDelayRuner* CDelayRuner::NewLC() + { + CDelayRuner* self = new (ELeave) CDelayRuner(); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +CDelayRuner* CDelayRuner::NewL() + { + CDelayRuner* self = CDelayRuner::NewLC(); + CleanupStack::Pop(); // self; + return self; + } + +void CDelayRuner::ConstructL() + { + User::LeaveIfError(iTimer.CreateLocal()); // Initialize timer + CActiveScheduler::Add(this); // Add to scheduler + } + +CDelayRuner::~CDelayRuner() + { + Cancel(); // Cancel any request, if outstanding + iTimer.Close(); // Destroy the RTimer object + // Delete instance variables if any + } + +void CDelayRuner::DoCancel() + { + iTimer.Cancel(); + } + +void CDelayRuner::StartL(zrtp_stream_t *ctx, zrtp_retry_task_t* ztask) + { + Cancel(); // Cancel any request, just to be sure + //iState = EUninitialized; + iCtx = ctx; + iZTask = ztask; + iTimer.After(iStatus, ztask->timeout * 1000); // Set for later + SetActive(); // Tell scheduler a request is active + } + +void CDelayRuner::RunL() + { + if (iStatus == KErrNone) + { + // Do something useful + iZTask->_is_busy = 1 ; // may be we don't need this + (iZTask->callback)(iCtx,iZTask); + iZTask->_is_busy = 0 ; // may be we don't need this + } + zrtp_internal_delete_task_from_list(iCtx,iZTask); + } + +TInt CDelayRuner::RunError(TInt aError) + { + return aError; + } diff --git a/projects/symbian/DelayRuner.h b/projects/symbian/DelayRuner.h new file mode 100644 index 0000000000..39679c6fc4 --- /dev/null +++ b/projects/symbian/DelayRuner.h @@ -0,0 +1,72 @@ +/* + ============================================================================ + Name : CDelayRuner.h + Author : R. Drutsky + Version : 1.0 + Copyright : Copyright (c) 2010 Soft Industry + Description : CDelayRuner declaration + ============================================================================ + */ + +#ifndef DELAYRUNER_H +#define DELAYRUNER_H + +#include // For CActive, link against: euser.lib +#include // For RTimer, link against: euser.lib + +#include +class CDelayRuner : public CActive + { +public: + // Cancel and destroy + ~CDelayRuner(); + + // Two-phased constructor. + static CDelayRuner* NewL(); + + // Two-phased constructor. + static CDelayRuner* NewLC(); + +public: + // New functions + // Function for making the initial request + void StartL(zrtp_stream_t *ctx, zrtp_retry_task_t* ztask); + +private: + // C++ constructor + CDelayRuner(); + + // Second-phase constructor + void ConstructL(); + +private: + // From CActive + // Handle completion + void RunL(); + + // How to cancel me + void DoCancel(); + + // Override to handle leaves from RunL(). Default implementation causes + // the active scheduler to panic. + TInt RunError(TInt aError); + +private: + enum TCDelayRunerState + { + EUninitialized, // Uninitialized + EInitialized, // Initalized + EError + // Error condition + }; + +private: + TInt iState; // State of the active object + RTimer iTimer; // Provides async timing service + + zrtp_stream_t *iCtx; + zrtp_retry_task_t * iZTask; + + }; + +#endif // CDELAYRUNER_H diff --git a/projects/symbian/bld.bat b/projects/symbian/bld.bat new file mode 100755 index 0000000000..0bbff637c6 --- /dev/null +++ b/projects/symbian/bld.bat @@ -0,0 +1 @@ +bldmake bldfiles \ No newline at end of file diff --git a/projects/symbian/bld.inf b/projects/symbian/bld.inf new file mode 100644 index 0000000000..f477ab57f7 --- /dev/null +++ b/projects/symbian/bld.inf @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2006-2007 Philip R. Zimmermann. All rights reserved. + * Contact: http://philzimmermann.com + * + * Nikolay Popok mailto: + * + */ + +PRJ_MMPFILES +libzrtp.mmp + +PRJ_PLATFORMS +WINSCW GCCE WINC diff --git a/projects/symbian/bldgcce.bat b/projects/symbian/bldgcce.bat new file mode 100755 index 0000000000..cf1e17b541 --- /dev/null +++ b/projects/symbian/bldgcce.bat @@ -0,0 +1,2 @@ +abld build gcce urel +pause \ No newline at end of file diff --git a/projects/symbian/libzrtp.mmp b/projects/symbian/libzrtp.mmp new file mode 100644 index 0000000000..ba6a7a1001 --- /dev/null +++ b/projects/symbian/libzrtp.mmp @@ -0,0 +1,74 @@ +/* + * 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. + */ + +TARGET libzrtp.lib +TARGETTYPE lib +UID 0x0FFFFFF0 + +VENDORID 0 + +//OPTION GCC +Wno-ctor-dtor-privacy +MACRO ZRTP_USE_STACK_MINIM + +USERINCLUDE . + +SOURCEPATH . +SOURCE DelayRuner.cpp +SOURCE zrtp_iface_symb.cpp + +SOURCEPATH ..\..\third_party\bnlib +SOURCE bn.c +SOURCE bn32.c +SOURCE bninit32.c +SOURCE lbn32.c +SOURCE lbnmem.c +SOURCE legal.c + +SOURCEPATH ..\..\src +SOURCE zrtp_crc.c +SOURCE zrtp_crypto_aes.c +SOURCE zrtp_crypto_atl.c +SOURCE zrtp_crypto_hash.c +SOURCE zrtp_crypto_pk.c +SOURCE zrtp_crypto_sas.c +SOURCE zrtp_datatypes.c +SOURCE zrtp_engine.c +SOURCE zrtp_iface_cache.c +SOURCE zrtp_iface_scheduler.c +SOURCE zrtp_iface_sys.c +SOURCE zrtp_initiator.c +SOURCE zrtp_list.c +SOURCE zrtp_log.c +SOURCE zrtp_pbx.c +SOURCE zrtp_protocol.c +SOURCE zrtp_responder.c +SOURCE zrtp_rng.c +SOURCE zrtp_srtp_builtin.c +SOURCE zrtp_string.c +SOURCE zrtp_utils.c +SOURCE zrtp_utils_proto.c +SOURCE zrtp.c + +SOURCEPATH ..\..\third_party\bgaes +SOURCE aes_modes.c +SOURCE aescrypt.c +SOURCE aeskey.c +SOURCE aestab.c +SOURCE sha1.c +SOURCE sha2.c + +SYSTEMINCLUDE ..\..\. +SYSTEMINCLUDE ..\..\include +SYSTEMINCLUDE ..\..\third_party\bnlib +SYSTEMINCLUDE ..\..\third_party\bgaes + +SYSTEMINCLUDE \epoc32\include +SYSTEMINCLUDE \epoc32\include\libc + +LIBRARY euser.lib + +SOURCEPATH ..\..\src +SOURCE zrtp_crypto_ec.c zrtp_crypto_ecdh.c zrtp_crypto_ecdsa.c zrtp_engine_driven.c zrtp_legal.c zrtp_srtp_dm.c diff --git a/projects/symbian/zrtp_iface_symb.cpp b/projects/symbian/zrtp_iface_symb.cpp new file mode 100644 index 0000000000..e722b68418 --- /dev/null +++ b/projects/symbian/zrtp_iface_symb.cpp @@ -0,0 +1,336 @@ +/* + * 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. + */ + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +extern "C" +{ +/** + * @brief Get kernel-generated random number + * @bug seems not work + * @return 32 random bits + */ +uint32_t zrtp_symbian_kernel_random(); + +/** + * @brief Pseudo random number: sum of pid's shifted and xored by number of precceses + * @return + */ +uint32_t zrtp_sum_of_pid_and_number_of_poccesses(); + +/** + * @brief Number of milisecond past from particular date and time + * @return + */ +uint64_t zrtp_get_system_time_crazy(); + +/** + * @brief Current procces PID + * @return PID + */ +unsigned int zrtp_get_pid(); + +/** + * @brief Availible memory + * @return memory availible on heap + */ +uint32_t zrtp_get_availible_heap(); + +} + + + +//----------------------------------------------------------------------------- +zrtp_status_t zrtp_mutex_init(zrtp_mutex_t **mutex) { + RMutex *rmutex = new RMutex(); + //rmutex->CreateLocal(); was before + rmutex->CreateGlobal(KNullDesC); + *mutex = (zrtp_mutex_t*) rmutex; + return zrtp_status_ok; +} + +zrtp_status_t zrtp_mutex_lock(zrtp_mutex_t* mutex) { + RMutex *rmutex = (RMutex *) mutex; + rmutex->Wait(); + return zrtp_status_ok; +} + +zrtp_status_t zrtp_mutex_unlock(zrtp_mutex_t* mutex) { + RMutex *rmutex = (RMutex *) mutex; + rmutex->Signal(); + return zrtp_status_ok; +} + +zrtp_status_t zrtp_mutex_destroy(zrtp_mutex_t* mutex) { + RMutex *rmutex = (RMutex *) mutex; + if (rmutex) { + rmutex->Close(); + delete rmutex; + } + return zrtp_status_ok; +} + +//----------------------------------------------------------------------------- +zrtp_status_t zrtp_sem_init(zrtp_sem_t** sem, uint32_t value, uint32_t limit) { + RSemaphore *rsem = new RSemaphore(); + //rsem->CreateLocal(value); + rsem->CreateGlobal(KNullDesC,value); + *sem = (zrtp_sem_t*) rsem; + return zrtp_status_ok; +} + +zrtp_status_t zrtp_sem_destroy(zrtp_sem_t* sem) { + RSemaphore *rsem = (RSemaphore *) sem; + if (rsem) { + rsem->Close(); + delete rsem; + } + return zrtp_status_ok; +} + +zrtp_status_t zrtp_sem_wait(zrtp_sem_t* sem) { + RSemaphore *rsem = (RSemaphore *) sem; + rsem->Wait(); + return zrtp_status_ok; +} + +zrtp_status_t zrtp_sem_trtwait(zrtp_sem_t* sem) { + RSemaphore *rsem = (RSemaphore *) sem; + rsem->Wait(1000); + return zrtp_status_ok; +} + +zrtp_status_t zrtp_sem_post(zrtp_sem_t* sem) { + RSemaphore *rsem = (RSemaphore *) sem; + rsem->Signal(); + return zrtp_status_ok; +} + +//----------------------------------------------------------------------------- +int zrtp_sleep(unsigned int msec) { + TTimeIntervalMicroSeconds32 i(msec *1000); + User::After(i); + return 0; +} + +int zrtp_thread_create(zrtp_thread_routine_t start_routine, void *arg) { + RThread h; + TBuf<64> thName=_L("zrtp_thread"); + + h.Create(thName, start_routine, KDefaultStackSize*2, NULL, arg) ; + h.Resume(); + h.Close(); + + return NULL; +} +//----------------------------------------------------------------------------- +// For Scheduler +#if (defined(ZRTP_USE_BUILTIN_SCEHDULER) && (ZRTP_USE_BUILTIN_SCEHDULER ==1)) + +#include "DelayRuner.h" +#include "zrtp_error.h" +mlist_t tasks_head_s; +static uint8_t inited = 0 ; +static uint8_t is_running = 0; + +typedef struct { + zrtp_stream_t *ctx; /** ZRTP stream context associated with the task */ + zrtp_retry_task_t *ztask; /** ZRTP stream associated with the task */ + mlist_t _mlist; + CDelayRuner* ao; // Active object +} zrtp_sched_task_s_t; + +zrtp_status_t zrtp_def_scheduler_init(zrtp_global_t* zrtp) +{ + zrtp_status_t status = zrtp_status_ok; + ZRTP_LOG(3,("symbian","Init start")); + if (inited) { + return zrtp_status_ok; + } + + do { + init_mlist(&tasks_head_s); + is_running = 1; + inited = 1; + } while (0); + + ZRTP_LOG(3,("symbian","Init end")); + return status; +} + +void zrtp_def_scheduler_down() +{ + ZRTP_LOG(3,("symbian","Down start")); + mlist_t *node = 0, *tmp = 0; + + if (!inited) { + return; + } + + /* Stop main thread */ + is_running = 0; +// zrtp_sem_post(count); + + /* Then destroy tasks queue and realease all other resources */ + //zrtp_mutex_lock(protector); + + mlist_for_each_safe(node, tmp, &tasks_head_s) { + zrtp_sched_task_s_t* task = mlist_get_struct(zrtp_sched_task_s_t, _mlist, node); + if (task->ao!=NULL) + { + delete task->ao; + } + zrtp_sys_free(task); + } + init_mlist(&tasks_head_s); + +// zrtp_mutex_unlock(protector); + +// zrtp_mutex_destroy(protector); +// zrtp_sem_destroy(count); + + ZRTP_LOG(3,("symbian","Down end")); + inited = 0; +} + + +void zrtp_def_scheduler_call_later(zrtp_stream_t *ctx, zrtp_retry_task_t* ztask) +{ +// ZRTP_LOG(3,("symbian","CallLater start")); + //mlist_t *node=0, *tmp=0; + mlist_t* last = &tasks_head_s; + + //zrtp_mutex_lock(protector); + + if (!ztask->_is_enabled) { + //zrtp_mutex_unlock(protector); + return; + } + + do { + zrtp_sched_task_s_t* new_task = (zrtp_sched_task_s_t*)zrtp_sys_alloc(sizeof(zrtp_sched_task_s_t)); + if (!new_task) { + break; + } + + new_task->ctx = ctx; + new_task->ztask = ztask; + new_task->ao = CDelayRuner::NewL(); + + mlist_insert(last, &new_task->_mlist); + + new_task->ao->StartL(ctx,ztask); + //zrtp_sem_post(count); + } while (0); + + //ZRTP_LOG(3,("symbian","CallLater end")); + //zrtp_mutex_unlock(protector); +} + +void zrtp_def_scheduler_cancel_call_later(zrtp_stream_t* ctx, zrtp_retry_task_t* ztask) +{ + mlist_t *node=0, *tmp=0; + ZRTP_LOG(3,("symbian","CancelcallLater start")); +// zrtp_mutex_lock(protector); + + mlist_for_each_safe(node, tmp, &tasks_head_s) { + zrtp_sched_task_s_t* task = mlist_get_struct(zrtp_sched_task_s_t, _mlist, node); + if ((task->ctx == ctx) && ((task->ztask == ztask) || !ztask)) { + task->ao->Cancel(); + delete task->ao; // Cancel and delete task + mlist_del(&task->_mlist); + zrtp_sys_free(task); + //zrtp_sem_trtwait(count); + if (ztask) { + break; + } + } + } + ZRTP_LOG(3,("symbian","CancelCallLater done")); +// zrtp_mutex_unlock(protector); +} + +void zrtp_internal_delete_task_from_list(zrtp_stream_t* ctx, zrtp_retry_task_t* ztask) + { + mlist_t *node=0, *tmp=0; + ZRTP_LOG(3,("symbian","DelTask begin")); + mlist_for_each_safe(node, tmp, &tasks_head_s) + { + zrtp_sched_task_s_t* task = mlist_get_struct(zrtp_sched_task_s_t, _mlist, node); + if ((task->ctx == ctx) && ((task->ztask == ztask) || !ztask)) + { + delete task->ao; // Cancel and delete task + mlist_del(&task->_mlist); + zrtp_sys_free(task); + ZRTP_LOG(3,("symbian","DelTask Del")); + //zrtp_sem_trtwait(count); + if (ztask) + { + break; + } + } + } + ZRTP_LOG(3,("symbian","DelTask end")); + } + +void zrtp_def_scheduler_wait_call_later(zrtp_stream_t* ctx) +{ +} +#endif // ZRTP_USE_BUILTIN_SCEHDULER +//----------------------------------------------------------------------------- + +unsigned int zrtp_get_pid() + { + return getpid(); + } + +uint64_t zrtp_get_system_time_crazy() + { + TTime time; + + return time.MicroSecondsFrom(TTime(TDateTime (491,EAugust,7,3,37,17,347))).Int64(); + } + +uint32_t zrtp_sum_of_pid_and_number_of_poccesses() + { + TFindProcess fp; + RProcess procces; + TFullName proccesName; + uint_32t idsum=1; + uint_32t proccesCount=0; + fp.Find(KNullDesC); + while (fp.Next(proccesName)==KErrNone) + { + if (procces.Open(proccesName,EOwnerProcess)==KErrNone) + { + idsum+=procces.Id(); + proccesCount++; + procces.Close(); + } + } + idsum = (idsum << 3) xor proccesCount; + return idsum; + } + +uint32_t zrtp_get_availible_heap() + { + return User::Heap().MaxLength(); + } + +uint32_t zrtp_symbian_kernel_random() + { + return Math::Random(); + } diff --git a/projects/win/libzrtp.sln b/projects/win/libzrtp.sln new file mode 100644 index 0000000000..b94a523c24 --- /dev/null +++ b/projects/win/libzrtp.sln @@ -0,0 +1,28 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libzrtp_test", "libzrtp_test.vcproj", "{BA35741B-8C8E-4A39-9CA1-0CE032D6E4ED}" + ProjectSection(ProjectDependencies) = postProject + {C13CC324-E0CA-4492-9A30-310A6BD64FF5} = {C13CC324-E0CA-4492-9A30-310A6BD64FF5} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libzrtp", "libzrtp.vcproj", "{C13CC324-E0CA-4492-9A30-310A6BD64FF5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BA35741B-8C8E-4A39-9CA1-0CE032D6E4ED}.Debug|Win32.ActiveCfg = Debug|Win32 + {BA35741B-8C8E-4A39-9CA1-0CE032D6E4ED}.Debug|Win32.Build.0 = Debug|Win32 + {BA35741B-8C8E-4A39-9CA1-0CE032D6E4ED}.Release|Win32.ActiveCfg = Release|Win32 + {BA35741B-8C8E-4A39-9CA1-0CE032D6E4ED}.Release|Win32.Build.0 = Release|Win32 + {C13CC324-E0CA-4492-9A30-310A6BD64FF5}.Debug|Win32.ActiveCfg = Debug|Win32 + {C13CC324-E0CA-4492-9A30-310A6BD64FF5}.Debug|Win32.Build.0 = Debug|Win32 + {C13CC324-E0CA-4492-9A30-310A6BD64FF5}.Release|Win32.ActiveCfg = Release|Win32 + {C13CC324-E0CA-4492-9A30-310A6BD64FF5}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/projects/win/libzrtp.vcproj b/projects/win/libzrtp.vcproj new file mode 100644 index 0000000000..485bd2f02d --- /dev/null +++ b/projects/win/libzrtp.vcproj @@ -0,0 +1,499 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/win/libzrtp_not_ec.vcproj b/projects/win/libzrtp_not_ec.vcproj new file mode 100644 index 0000000000..63f6c1ca56 --- /dev/null +++ b/projects/win/libzrtp_not_ec.vcproj @@ -0,0 +1,483 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/win/libzrtp_test.vcproj b/projects/win/libzrtp_test.vcproj new file mode 100644 index 0000000000..99ce3f1675 --- /dev/null +++ b/projects/win/libzrtp_test.vcproj @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/win_ce/libzrtp_test_wince.vcproj b/projects/win_ce/libzrtp_test_wince.vcproj new file mode 100644 index 0000000000..4dfc6574c0 --- /dev/null +++ b/projects/win_ce/libzrtp_test_wince.vcproj @@ -0,0 +1,500 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/win_ce/libzrtp_wince.sln b/projects/win_ce/libzrtp_wince.sln new file mode 100644 index 0000000000..a732637635 --- /dev/null +++ b/projects/win_ce/libzrtp_wince.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libzrtp", "libzrtp_wince.vcproj", "{53F84E3B-9903-4046-897B-33FEFFED527A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libzrtp_test", "libzrtp_test_wince.vcproj", "{5C082222-FD44-4295-8055-915936F086BE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Pocket PC 2003 (ARMV4) = Debug|Pocket PC 2003 (ARMV4) + Debug|Smartphone 2003 (ARMV4) = Debug|Smartphone 2003 (ARMV4) + Release|Pocket PC 2003 (ARMV4) = Release|Pocket PC 2003 (ARMV4) + Release|Smartphone 2003 (ARMV4) = Release|Smartphone 2003 (ARMV4) + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {53F84E3B-9903-4046-897B-33FEFFED527A}.Debug|Pocket PC 2003 (ARMV4).ActiveCfg = Debug|Pocket PC 2003 (ARMV4) + {53F84E3B-9903-4046-897B-33FEFFED527A}.Debug|Smartphone 2003 (ARMV4).ActiveCfg = Debug|Smartphone 2003 (ARMV4) + {53F84E3B-9903-4046-897B-33FEFFED527A}.Release|Pocket PC 2003 (ARMV4).ActiveCfg = Release|Pocket PC 2003 (ARMV4) + {53F84E3B-9903-4046-897B-33FEFFED527A}.Release|Pocket PC 2003 (ARMV4).Build.0 = Release|Pocket PC 2003 (ARMV4) + {53F84E3B-9903-4046-897B-33FEFFED527A}.Release|Pocket PC 2003 (ARMV4).Deploy.0 = Release|Pocket PC 2003 (ARMV4) + {53F84E3B-9903-4046-897B-33FEFFED527A}.Release|Smartphone 2003 (ARMV4).ActiveCfg = Release|Smartphone 2003 (ARMV4) + {53F84E3B-9903-4046-897B-33FEFFED527A}.Release|Smartphone 2003 (ARMV4).Build.0 = Release|Smartphone 2003 (ARMV4) + {53F84E3B-9903-4046-897B-33FEFFED527A}.Release|Smartphone 2003 (ARMV4).Deploy.0 = Release|Smartphone 2003 (ARMV4) + {5C082222-FD44-4295-8055-915936F086BE}.Debug|Pocket PC 2003 (ARMV4).ActiveCfg = Debug|Pocket PC 2003 (ARMV4) + {5C082222-FD44-4295-8055-915936F086BE}.Debug|Pocket PC 2003 (ARMV4).Build.0 = Debug|Pocket PC 2003 (ARMV4) + {5C082222-FD44-4295-8055-915936F086BE}.Debug|Pocket PC 2003 (ARMV4).Deploy.0 = Debug|Pocket PC 2003 (ARMV4) + {5C082222-FD44-4295-8055-915936F086BE}.Debug|Smartphone 2003 (ARMV4).ActiveCfg = Debug|Smartphone 2003 (ARMV4) + {5C082222-FD44-4295-8055-915936F086BE}.Debug|Smartphone 2003 (ARMV4).Build.0 = Debug|Smartphone 2003 (ARMV4) + {5C082222-FD44-4295-8055-915936F086BE}.Debug|Smartphone 2003 (ARMV4).Deploy.0 = Debug|Smartphone 2003 (ARMV4) + {5C082222-FD44-4295-8055-915936F086BE}.Release|Pocket PC 2003 (ARMV4).ActiveCfg = Release|Pocket PC 2003 (ARMV4) + {5C082222-FD44-4295-8055-915936F086BE}.Release|Pocket PC 2003 (ARMV4).Build.0 = Release|Pocket PC 2003 (ARMV4) + {5C082222-FD44-4295-8055-915936F086BE}.Release|Pocket PC 2003 (ARMV4).Deploy.0 = Release|Pocket PC 2003 (ARMV4) + {5C082222-FD44-4295-8055-915936F086BE}.Release|Smartphone 2003 (ARMV4).ActiveCfg = Release|Smartphone 2003 (ARMV4) + {5C082222-FD44-4295-8055-915936F086BE}.Release|Smartphone 2003 (ARMV4).Build.0 = Release|Smartphone 2003 (ARMV4) + {5C082222-FD44-4295-8055-915936F086BE}.Release|Smartphone 2003 (ARMV4).Deploy.0 = Release|Smartphone 2003 (ARMV4) + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/projects/win_ce/libzrtp_wince.vcproj b/projects/win_ce/libzrtp_wince.vcproj new file mode 100644 index 0000000000..cbe4fb4389 --- /dev/null +++ b/projects/win_ce/libzrtp_wince.vcproj @@ -0,0 +1,761 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/win_ce/libzrtp_wince_not_ec.vcproj b/projects/win_ce/libzrtp_wince_not_ec.vcproj new file mode 100644 index 0000000000..d16b5559d6 --- /dev/null +++ b/projects/win_ce/libzrtp_wince_not_ec.vcproj @@ -0,0 +1,741 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/win_kernel/MAKEFILE.WIN32 b/projects/win_kernel/MAKEFILE.WIN32 new file mode 100644 index 0000000000..8a1a5e2802 --- /dev/null +++ b/projects/win_kernel/MAKEFILE.WIN32 @@ -0,0 +1,131 @@ +# +# Copyright (c) 2006 Philip R. Zimmermann. All rights reserved. +# Contact: http://philzimmermann.com +# For licensing and other legal details, see the file zrtp_legal.c. +# +# Andrew Rozinko + +# +# THIS MAKEFILE WORKS WITH MICROSOFT NMAKE ONLY +# + +# change this to point to your DDK + +DDK = ..\..\..\..\winddk\3790 +OS = wxp +BASENAME = libzrtp + +#RELEASE = 1 + +CC = cl +ASM = ml +LIB = lib + +all: $(BASENAME).lib + +# bnlib (the BigNumber engine) + +bnlib = \ + ../../third_party/bnlib/bn.obj \ + ../../third_party/bnlib/bn32.obj \ + ../../third_party/bnlib/bninit32.obj \ + ../../third_party/bnlib/lbn32.obj \ + ../../third_party/bnlib/lbnmem.obj \ + ../../third_party/bnlib/legal.obj + +protocol = \ + ../../src/zrtp.obj \ + ../../src/zrtp_crc.obj \ + ../../src/zrtp_crypto_aes.obj \ + ../../src/zrtp_crypto_atl.obj \ + ../../src/zrtp_crypto_hash.obj \ + ../../src/zrtp_crypto_pk.obj \ + ../../src/zrtp_crypto_sas.obj \ + ../../src/zrtp_datatypes.obj \ + ../../src/zrtp_engine.obj \ + ../../src/enterprise/zrtp_engine_driven.obj \ + ../../src/enterprise/zrtp_crypto_ec.obj \ + ../../src/enterprise/zrtp_crypto_ecdh.obj \ + ../../src/zrtp_iface_sys.obj \ + ../../src/zrtp_initiator.obj \ + ../../src/zrtp_legal.obj \ + ../../src/zrtp_list.obj \ + ../../src/zrtp_log.obj \ + ../../src/zrtp_pbx.obj \ + ../../src/zrtp_protocol.obj \ + ../../src/zrtp_responder.obj \ + ../../src/zrtp_rng.obj \ + ../../src/zrtp_srtp_builtin.obj \ + ../../src/zrtp_string.obj \ + ../../src/zrtp_utils.obj \ + ../../src/zrtp_utils_proto.obj + +bgaes = \ + ../../third_party/bgaes/aes_modes.obj \ + ../../third_party/bgaes/aescrypt.obj \ + ../../third_party/bgaes/aeskey.obj \ + ../../third_party/bgaes/aestab.obj \ + ../../third_party/bgaes/sha1.obj \ + ../../third_party/bgaes/sha2.obj + +OBJECTS = $(bnlib) $(protocol) $(bgaes) + +!IFNDEF RELEASE + +# Debug + +OUT_DIR = debug_ec.km + +DEFINES_D = -D_X86_=1 -Di386=1 -DSTD_CALL -DCONDITION_HANDLING=1 \ +-DNT_UP=1 -DNT_INST=0 -DWIN32=100 -D_NT1X_=100 \ +-DWINNT=1 -D_WIN32_WINNT=0x0500 -DWIN32_LEAN_AND_MEAN=1 -DDBG=1 -D_DEBUG -DDEBUG -DDEVL=1 \ +-DFPO=0 -D_DLL=1 -D_IDWBUILD -DRDRDBG -DSRVDBG -DDBG_MESSAGES=1 \ +-D_UNICODE -DLITTLE_ENDIAN -DZRTP_USE_ENTERPRISE=1 + +CFLAGS_D = $(DEFINES_D) -Zel -Zp8 -Gy -cbstring -Gz -QIfdiv- -QIf -Gi- -Gm- -GX- \ +-GR- -GF -FI$(DDK)\inc\$(OS)\warning.h -Z7 -Od -Oi -Oy- -W3 + +!ELSE + +# Release + +OUT_DIR = release_ec.km + +DEFINES_D = -D_X86_=1 -Di386=1 -DSTD_CALL -DCONDITION_HANDLING=1 \ +-DNT_UP=1 -DNO_DISK_ACCESS -DNT_INST=0 -DWIN32=100 -D_NT1X_=100 \ +-DWINNT=1 -D_WIN32_WINNT=0x0500 -DWIN32_LEAN_AND_MEAN=1 -DDEVL=1 \ +-DFPO=1 -DNDEBUG -D_DLL=1 -D_IDWBUILD -D_UNICODE \ +-DLITTLE_ENDIAN -DZRTP_USE_ENTERPRISE=1 + +CFLAGS_D = $(DEFINES_D) -Zel -Zp8 -Gy -cbstring -Gz -QIfdiv- -QIf -Gi- -Gm- -GX- \ +-GR- -GF -Oxs -Oy -FI$(DDK)\inc\$(OS)\warning.h -W3 -FAcs -Z7 + +!ENDIF + +ASM = ml +AFLAGS = /c /Cx /coff /Zi +AINCLUDE = -I. -I$(DDK)\inc + +CFLAGS = $(CFLAGS_D) -nologo -DHAVE_CONFIG_H=1 -DNT_DRIVER -D__BUILDMACHINE__=WinDDK \ + -I$(DDK)\inc\$(OS) -I$(DDK)\inc\ddk\$(OS) -I$(DDK)\inc\ddk\wdm\$(OS) \ + -I$(DDK)\inc\crt -I..\..\third_party\bnlib\config -I..\..\third_party\bnlib \ + -I..\..\third_party\bgaes -I..\..\test\include -I..\..\include -I..\..\include\enterprise + +.c.obj : + @$(CC) -c $(CFLAGS) $< /Fo$(OUT_DIR)/$( + +# +# THIS MAKEFILE WORKS WITH MICROSOFT NMAKE ONLY +# + +# change this to point to your DDK + +DDK = ..\..\..\..\winddk2003 +OS = wnet +BASENAME = libzrtp +BINPATH = $(DDK)\bin\win64\x86\amd64 + +#RELEASE = 1 + +CC = $(BINPATH)\cl +ASM = $(BINPATH)\ml +LIB = $(BINPATH)\lib + +all: $(BASENAME).lib + +# bnlib (the BigNumber engine) + +bnlib = \ + ../../third_party/bnlib/bn.obj \ + ../../third_party/bnlib/bn32.obj \ + ../../third_party/bnlib/bninit32.obj \ + ../../third_party/bnlib/lbn32.obj \ + ../../third_party/bnlib/lbnmem.obj \ + ../../third_party/bnlib/legal.obj + +protocol = \ + ../../src/zrtp.obj \ + ../../src/zrtp_crc.obj \ + ../../src/zrtp_crypto_aes.obj \ + ../../src/zrtp_crypto_atl.obj \ + ../../src/zrtp_crypto_hash.obj \ + ../../src/zrtp_crypto_pk.obj \ + ../../src/zrtp_crypto_sas.obj \ + ../../src/zrtp_datatypes.obj \ + ../../src/zrtp_engine.obj \ + ../../src/enterprise/zrtp_engine_driven.obj \ + ../../src/enterprise/zrtp_crypto_ec.obj \ + ../../src/enterprise/zrtp_crypto_ecdh.obj \ + ../../src/zrtp_iface_sys.obj \ + ../../src/zrtp_initiator.obj \ + ../../src/zrtp_legal.obj \ + ../../src/zrtp_list.obj \ + ../../src/zrtp_log.obj \ + ../../src/zrtp_pbx.obj \ + ../../src/zrtp_protocol.obj \ + ../../src/zrtp_responder.obj \ + ../../src/zrtp_rng.obj \ + ../../src/zrtp_srtp_builtin.obj \ + ../../src/zrtp_string.obj \ + ../../src/zrtp_utils.obj \ + ../../src/zrtp_utils_proto.obj + +bgaes = \ + ../../third_party/bgaes/aes_modes.obj \ + ../../third_party/bgaes/aescrypt.obj \ + ../../third_party/bgaes/aeskey.obj \ + ../../third_party/bgaes/aestab.obj \ + ../../third_party/bgaes/sha1.obj \ + ../../third_party/bgaes/sha2.obj + + +OBJECTS = $(bnlib) $(protocol) $(bgaes) + +!IFNDEF RELEASE + +# Debug + +OUT_DIR = debug64_ec.km + +DEFINES_D = -DWIN64=1 -D_WIN64=1 -D_AMD64_=1 -D_M_AMD64 -D_WINDOWS \ +-DSTD_CALL -DCONDITION_HANDLING=1 \ +-DNT_UP=1 -DNT_INST=0 -D_NT1X_=100 \ +-DWINNT=1 -D_WIN32_WINNT=0x0500 -DWIN32_LEAN_AND_MEAN=1 -DDBG=1 -D_DEBUG -DDEBUG -DDEVL=1 \ +-DFPO=0 -D_DLL=1 -D_IDWBUILD -DRDRDBG -DSRVDBG -DDBG_MESSAGES=1 \ +-D_UNICODE -DLITTLE_ENDIAN -DZRTP_USE_ENTERPRISE=1 + +CFLAGS_D = $(DEFINES_D) -Zp8 -Gy -cbstring -Gz -Gm- -EHs-c- \ +-GR- -GF -FI$(DDK)\inc\$(OS)\warning.h -Z7 -Od -Oi -Oy- -W3 + +!ELSE + +# Release + +OUT_DIR = release64_ec.km + +DEFINES_D = -DWIN64=1 -D_WIN64=1 -D_AMD64_=1 -D_M_AMD64 -D_WINDOWS \ +-DSTD_CALL -DCONDITION_HANDLING=1 \ +-DNT_UP=1 -DNO_DISK_ACCESS -DNT_INST=0 -DWIN32=100 -D_NT1X_=100 \ +-DWINNT=1 -D_WIN32_WINNT=0x0500 -DWIN32_LEAN_AND_MEAN=1 -DDEVL=1 \ +-DFPO=1 -DNDEBUG -D_DLL=1 -D_IDWBUILD -D_UNICODE \ +-DLITTLE_ENDIAN -DZRTP_USE_ENTERPRISE=1 + +CFLAGS_D = $(DEFINES_D) -Zel -Zp8 -Gy -cbstring -Gz -QIfdiv- -QIf -Gi- -Gm- -GX- \ +-GR- -GF -Oxs -Oy -FI$(DDK)\inc\$(OS)\warning.h -W3 -FAcs -Z7 + +!ENDIF + +ASM = ml +AFLAGS = /c /Cx /coff /Zi +AINCLUDE = -I. -I$(DDK)\inc + +CFLAGS = $(CFLAGS_D) -nologo -DHAVE_CONFIG_H=1 -DNT_DRIVER -D__BUILDMACHINE__=WinDDK \ + -I$(DDK)\inc\$(OS) -I$(DDK)\inc\ddk\$(OS) -I$(DDK)\inc\ddk\wdm\$(OS) \ + -I$(DDK)\inc\crt -I..\..\third_party\bnlib\config -I..\..\third_party\bnlib \ + -I..\..\third_party\bgaes -I..\..\test\include -I..\..\include -I..\..\include\enterprise + +.c.obj : + @$(CC) -c $(CFLAGS) $< /Fo$(OUT_DIR)/$( + +# +# THIS MAKEFILE WORKS WITH MICROSOFT NMAKE ONLY +# + +# change this to point to your DDK + +DDK = ..\..\..\..\winddk\3790 +OS = wxp +BASENAME = libzrtp + +#RELEASE = 1 + +CC = cl +ASM = ml +LIB = lib + +all: $(BASENAME).lib + +# bnlib (the BigNumber engine) + +bnlib = \ + ../../third_party/bnlib/bn.obj \ + ../../third_party/bnlib/bn32.obj \ + ../../third_party/bnlib/bninit32.obj \ + ../../third_party/bnlib/lbn32.obj \ + ../../third_party/bnlib/lbnmem.obj \ + ../../third_party/bnlib/legal.obj + +protocol = \ + ../../src/zrtp.obj \ + ../../src/zrtp_crc.obj \ + ../../src/zrtp_crypto_aes.obj \ + ../../src/zrtp_crypto_atl.obj \ + ../../src/zrtp_crypto_hash.obj \ + ../../src/zrtp_crypto_pk.obj \ + ../../src/zrtp_crypto_sas.obj \ + ../../src/zrtp_datatypes.obj \ + ../../src/zrtp_engine.obj \ + ../../src/zrtp_iface_sys.obj \ + ../../src/zrtp_initiator.obj \ + ../../src/zrtp_legal.obj \ + ../../src/zrtp_list.obj \ + ../../src/zrtp_log.obj \ + ../../src/zrtp_pbx.obj \ + ../../src/zrtp_protocol.obj \ + ../../src/zrtp_responder.obj \ + ../../src/zrtp_rng.obj \ + ../../src/zrtp_srtp_builtin.obj \ + ../../src/zrtp_string.obj \ + ../../src/zrtp_utils.obj \ + ../../src/zrtp_utils_proto.obj + +bgaes = \ + ../../third_party/bgaes/aes_modes.obj \ + ../../third_party/bgaes/aescrypt.obj \ + ../../third_party/bgaes/aeskey.obj \ + ../../third_party/bgaes/aestab.obj \ + ../../third_party/bgaes/sha1.obj \ + ../../third_party/bgaes/sha2.obj + +OBJECTS = $(bnlib) $(protocol) $(bgaes) + +!IFNDEF RELEASE + +# Debug + +OUT_DIR = debug.km + +DEFINES_D = -D_X86_=1 -Di386=1 -DSTD_CALL -DCONDITION_HANDLING=1 \ +-DNT_UP=1 -DNT_INST=0 -DWIN32=100 -D_NT1X_=100 \ +-DWINNT=1 -D_WIN32_WINNT=0x0500 -DWIN32_LEAN_AND_MEAN=1 -DDBG=1 -D_DEBUG -DDEBUG -DDEVL=1 \ +-DFPO=0 -D_DLL=1 -D_IDWBUILD -DRDRDBG -DSRVDBG -DDBG_MESSAGES=1 \ +-D_UNICODE -DLITTLE_ENDIAN -DZRTP_USE_ENTERPRISE=0 + +CFLAGS_D = $(DEFINES_D) -Zel -Zp8 -Gy -cbstring -Gz -QIfdiv- -QIf -Gi- -Gm- -GX- \ +-GR- -GF -FI$(DDK)\inc\$(OS)\warning.h -Z7 -Od -Oi -Oy- -W3 + +!ELSE + +# Release + +OUT_DIR = release.km + +DEFINES_D = -D_X86_=1 -Di386=1 -DSTD_CALL -DCONDITION_HANDLING=1 \ +-DNT_UP=1 -DNO_DISK_ACCESS -DNT_INST=0 -DWIN32=100 -D_NT1X_=100 \ +-DWINNT=1 -D_WIN32_WINNT=0x0500 -DWIN32_LEAN_AND_MEAN=1 -DDEVL=1 \ +-DFPO=1 -DNDEBUG -D_DLL=1 -D_IDWBUILD -D_UNICODE \ +-DLITTLE_ENDIAN -DZRTP_USE_ENTERPRISE=0 + +CFLAGS_D = $(DEFINES_D) -Zel -Zp8 -Gy -cbstring -Gz -QIfdiv- -QIf -Gi- -Gm- -GX- \ +-GR- -GF -Oxs -Oy -FI$(DDK)\inc\$(OS)\warning.h -W3 -FAcs -Z7 + +!ENDIF + +ASM = ml +AFLAGS = /c /Cx /coff /Zi +AINCLUDE = -I. -I$(DDK)\inc + +CFLAGS = $(CFLAGS_D) -nologo -DHAVE_CONFIG_H=1 -DNT_DRIVER -D__BUILDMACHINE__=WinDDK \ + -I$(DDK)\inc\$(OS) -I$(DDK)\inc\ddk\$(OS) -I$(DDK)\inc\ddk\wdm\$(OS) \ + -I. -Ibnlib -Iinclude \ + -I$(DDK)\inc\crt -I..\..\third_party\bnlib\config -I..\..\third_party\bnlib \ + -I..\..\third_party\bgaes -I..\..\test\include -I..\..\include -I..\..\include\enterprise + +.c.obj : + @$(CC) -c $(CFLAGS) $< /Fo$(OUT_DIR)/$( + +# +# THIS MAKEFILE WORKS WITH MICROSOFT NMAKE ONLY +# + +# change this to point to your DDK + +DDK = ..\..\..\..\winddk2003 +OS = wnet +BASENAME = libzrtp +BINPATH = $(DDK)\bin\win64\x86\amd64 + +#RELEASE = 1 + +CC = $(BINPATH)\cl +ASM = $(BINPATH)\ml +LIB = $(BINPATH)\lib + +all: $(BASENAME).lib + +# bnlib (the BigNumber engine) + +bnlib = \ + ../../third_party/bnlib/bn.obj \ + ../../third_party/bnlib/bn32.obj \ + ../../third_party/bnlib/bninit32.obj \ + ../../third_party/bnlib/lbn32.obj \ + ../../third_party/bnlib/lbnmem.obj \ + ../../third_party/bnlib/legal.obj + +protocol = \ + ../../src/zrtp.obj \ + ../../src/zrtp_crc.obj \ + ../../src/zrtp_crypto_aes.obj \ + ../../src/zrtp_crypto_atl.obj \ + ../../src/zrtp_crypto_hash.obj \ + ../../src/zrtp_crypto_pk.obj \ + ../../src/zrtp_crypto_sas.obj \ + ../../src/zrtp_datatypes.obj \ + ../../src/zrtp_engine.obj \ + ../../src/zrtp_iface_sys.obj \ + ../../src/zrtp_initiator.obj \ + ../../src/zrtp_legal.obj \ + ../../src/zrtp_list.obj \ + ../../src/zrtp_log.obj \ + ../../src/zrtp_pbx.obj \ + ../../src/zrtp_protocol.obj \ + ../../src/zrtp_responder.obj \ + ../../src/zrtp_rng.obj \ + ../../src/zrtp_srtp_builtin.obj \ + ../../src/zrtp_string.obj \ + ../../src/zrtp_utils.obj \ + ../../src/zrtp_utils_proto.obj + +bgaes = \ + ../../third_party/bgaes/aes_modes.obj \ + ../../third_party/bgaes/aescrypt.obj \ + ../../third_party/bgaes/aeskey.obj \ + ../../third_party/bgaes/aestab.obj \ + ../../third_party/bgaes/sha1.obj \ + ../../third_party/bgaes/sha2.obj + +OBJECTS = $(bnlib) $(protocol) $(bgaes) + +!IFNDEF RELEASE + +# Debug + +OUT_DIR = debug64.km + +DEFINES_D = -DWIN64=1 -D_WIN64=1 -D_AMD64_=1 -D_M_AMD64 -D_WINDOWS \ +-DSTD_CALL -DCONDITION_HANDLING=1 \ +-DNT_UP=1 -DNT_INST=0 -D_NT1X_=100 \ +-DWINNT=1 -D_WIN32_WINNT=0x0500 -DWIN32_LEAN_AND_MEAN=1 -DDBG=1 -D_DEBUG -DDEBUG -DDEVL=1 \ +-DFPO=0 -D_DLL=1 -D_IDWBUILD -DRDRDBG -DSRVDBG -DDBG_MESSAGES=1 \ +-D_UNICODE -DLITTLE_ENDIAN -DZRTP_USE_ENTERPRISE=0 + +CFLAGS_D = $(DEFINES_D) -Zp8 -Gy -cbstring -Gz -Gm- -EHs-c- \ +-GR- -GF -FI$(DDK)\inc\$(OS)\warning.h -Z7 -Od -Oi -Oy- -W3 + +!ELSE + +# Release + +OUT_DIR = release64.km + +DEFINES_D = -DWIN64=1 -D_WIN64=1 -D_AMD64_=1 -D_M_AMD64 -D_WINDOWS \ +-DSTD_CALL -DCONDITION_HANDLING=1 \ +-DNT_UP=1 -DNO_DISK_ACCESS -DNT_INST=0 -DWIN32=100 -D_NT1X_=100 \ +-DWINNT=1 -D_WIN32_WINNT=0x0500 -DWIN32_LEAN_AND_MEAN=1 -DDEVL=1 \ +-DFPO=1 -DNDEBUG -D_DLL=1 -D_IDWBUILD -D_UNICODE \ +-DLITTLE_ENDIAN -DZRTP_USE_ENTERPRISE=0 + +CFLAGS_D = $(DEFINES_D) -Zel -Zp8 -Gy -cbstring -Gz -QIfdiv- -QIf -Gi- -Gm- -GX- \ +-GR- -GF -Oxs -Oy -FI$(DDK)\inc\$(OS)\warning.h -W3 -FAcs -Z7 + +!ENDIF + +ASM = ml +AFLAGS = /c /Cx /coff /Zi +AINCLUDE = -I. -I$(DDK)\inc + +CFLAGS = $(CFLAGS_D) -nologo -DHAVE_CONFIG_H=1 -DNT_DRIVER -D__BUILDMACHINE__=WinDDK \ + -I$(DDK)\inc\$(OS) -I$(DDK)\inc\ddk\$(OS) -I$(DDK)\inc\ddk\wdm\$(OS) \ + -I$(DDK)\inc\crt -I..\..\third_party\bnlib\config -I..\..\third_party\bnlib \ + -I..\..\third_party\bgaes -I..\..\test\include -I..\..\include -I..\..\include\enterprise + +.c.obj : + @$(CC) -c $(CFLAGS) $< /Fo$(OUT_DIR)/$( + */ + +#include "zrtp.h" + +#define _ZTU_ "zrtp main" + +/*----------------------------------------------------------------------------*/ +extern zrtp_status_t zrtp_init_rng(zrtp_global_t* zrtp); +extern void zrtp_down_rng(zrtp_global_t* zrtp); + +extern zrtp_status_t zrtp_defaults_sas(zrtp_global_t* global_ctx); +extern zrtp_status_t zrtp_defaults_pkt(zrtp_global_t* global_ctx); +extern zrtp_status_t zrtp_defaults_atl(zrtp_global_t* global_ctx); +extern zrtp_status_t zrtp_defaults_aes_cipher(zrtp_global_t* global_ctx); +extern zrtp_status_t zrtp_defaults_hash(zrtp_global_t* global_ctx); +extern zrtp_status_t zrtp_prepare_pkt(); +extern zrtp_status_t zrtp_done_pkt(); + + +void zrtp_config_defaults(zrtp_config_t* config) +{ + zrtp_memset(config, 0, sizeof(zrtp_config_t)); + + zrtp_memcpy(config->client_id, "ZRTP def. peer", 15); + config->lic_mode = ZRTP_LICENSE_MODE_PASSIVE; + + ZSTR_SET_EMPTY(config->def_cache_path); + zrtp_zstrncpyc(ZSTR_GV(config->def_cache_path), "./zrtp_def_cache_path.dat", 25); + +#if (defined(ZRTP_USE_BUILTIN_CACHE) && (ZRTP_USE_BUILTIN_CACHE == 1)) + config->cb.cache_cb.on_init = zrtp_def_cache_init; + config->cb.cache_cb.on_down = zrtp_def_cache_down; + config->cb.cache_cb.on_put = zrtp_def_cache_put; + config->cb.cache_cb.on_put_mitm = zrtp_def_cache_put_mitm; + config->cb.cache_cb.on_get = zrtp_def_cache_get; + config->cb.cache_cb.on_get_mitm = zrtp_def_cache_get_mitm; + config->cb.cache_cb.on_set_verified = zrtp_def_cache_set_verified; + config->cb.cache_cb.on_get_verified = zrtp_def_cache_get_verified; + config->cb.cache_cb.on_reset_since = zrtp_def_cache_reset_since; + config->cb.cache_cb.on_presh_counter_set = zrtp_def_cache_set_presh_counter; + config->cb.cache_cb.on_presh_counter_get = zrtp_def_cache_get_presh_counter; +#endif + +#if (defined(ZRTP_USE_BUILTIN_SCEHDULER) && (ZRTP_USE_BUILTIN_SCEHDULER == 1)) + config->cb.sched_cb.on_init = zrtp_def_scheduler_init; + config->cb.sched_cb.on_down = zrtp_def_scheduler_down; + config->cb.sched_cb.on_call_later = zrtp_def_scheduler_call_later; + config->cb.sched_cb.on_cancel_call_later = zrtp_def_scheduler_cancel_call_later; + config->cb.sched_cb.on_wait_call_later = zrtp_def_scheduler_wait_call_later; +#endif +} + +zrtp_status_t zrtp_init(zrtp_config_t* config, zrtp_global_t** zrtp) +{ + zrtp_global_t* new_zrtp; + zrtp_status_t s = zrtp_status_ok; + + ZRTP_LOG(3, (_ZTU_,"INITIALIZING LIBZRTP...\n")); + + /* Print out configuration setting */ + zrtp_print_env_settings(config); + + new_zrtp = zrtp_sys_alloc(sizeof(zrtp_global_t)); + if (!new_zrtp) { + return zrtp_status_alloc_fail; + } + zrtp_memset(new_zrtp, 0, sizeof(zrtp_global_t)); + + /* + * Apply configuration according to the config + */ + new_zrtp->lic_mode = config->lic_mode; + new_zrtp->is_mitm = config->is_mitm; + ZSTR_SET_EMPTY(new_zrtp->def_cache_path); + zrtp_zstrcpy(ZSTR_GV(new_zrtp->def_cache_path), ZSTR_GV(config->def_cache_path)); + zrtp_memcpy(&new_zrtp->cb, &config->cb, sizeof(zrtp_callback_t)); + + ZSTR_SET_EMPTY(new_zrtp->client_id); + zrtp_memset(new_zrtp->client_id.buffer, ' ', sizeof(zrtp_client_id_t)); + zrtp_zstrncpyc( ZSTR_GV(new_zrtp->client_id), + (const char*)config->client_id, + sizeof(zrtp_client_id_t)); + + /* + * General Initialization + */ + init_mlist(&new_zrtp->sessions_head); + + zrtp_mutex_init(&new_zrtp->sessions_protector); + + init_mlist(&new_zrtp->hash_head); + init_mlist(&new_zrtp->cipher_head); + init_mlist(&new_zrtp->atl_head); + init_mlist(&new_zrtp->pktype_head); + init_mlist(&new_zrtp->sas_head); + + /* Init RNG context */ + s = zrtp_init_rng(new_zrtp); + if (zrtp_status_ok != s) { + ZRTP_LOG(1, (_ZTU_,"ERROR! zrtp_init_rng() failed:%s.\n", zrtp_log_status2str(s))); + return zrtp_status_rng_fail; + } + + /* Initialize SRTP engine */ + s = zrtp_srtp_init(new_zrtp); + if (zrtp_status_ok != s) { + ZRTP_LOG(1, (_ZTU_,"ERROR! zrtp_srtp_init() failed:<%s>\n", zrtp_log_status2str(s))); + return zrtp_status_fail; + } + + if (new_zrtp->cb.cache_cb.on_init) { + s = new_zrtp->cb.cache_cb.on_init(new_zrtp); + if (zrtp_status_ok != s) { + ZRTP_LOG(1, (_ZTU_,"ERROR! cache on_init() callback failed <%s>\n", zrtp_log_status2str(s))); + zrtp_srtp_down(new_zrtp); + return zrtp_status_fail; + } + } + + if (new_zrtp->cb.sched_cb.on_init) { + s = new_zrtp->cb.sched_cb.on_init(new_zrtp); + if (zrtp_status_ok != s) { + ZRTP_LOG(1, (_ZTU_,"ERROR! scheduler on_init() callback failed <%s>\n", zrtp_log_status2str(s))); + zrtp_srtp_down(new_zrtp); + return zrtp_status_fail; + } + } + + /* Load default crypto-components */ + zrtp_prepare_pkt(new_zrtp); + zrtp_defaults_sas(new_zrtp); + zrtp_defaults_pkt(new_zrtp); + zrtp_defaults_atl(new_zrtp); + zrtp_defaults_aes_cipher(new_zrtp); + zrtp_defaults_hash(new_zrtp); + + *zrtp = new_zrtp; + + ZRTP_LOG(3, (_ZTU_,"INITIALIZING LIBZRTP - DONE\n")); + return s; +} + + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_down(zrtp_global_t* zrtp) +{ + ZRTP_LOG(3, (_ZTU_,"DESTROYING LIBZRTP...\n")); + + if (!zrtp) { + return zrtp_status_bad_param; + } + + zrtp_comp_done(ZRTP_CC_HASH, zrtp); + zrtp_comp_done(ZRTP_CC_SAS, zrtp); + zrtp_comp_done(ZRTP_CC_CIPHER, zrtp); + zrtp_comp_done(ZRTP_CC_PKT, zrtp); + zrtp_comp_done(ZRTP_CC_ATL, zrtp); + zrtp_done_pkt(zrtp); + + zrtp_mutex_destroy(zrtp->sessions_protector); + + zrtp_srtp_down(zrtp); + + if (zrtp->cb.cache_cb.on_down) { + zrtp->cb.cache_cb.on_down(); + } + if (zrtp->cb.sched_cb.on_down) { + zrtp->cb.sched_cb.on_down(); + } + + zrtp_down_rng(zrtp); + + zrtp_sys_free(zrtp); + + ZRTP_LOG(3, (_ZTU_,"DESTROYING LIBZRTP - DONE\n")); + + return zrtp_status_ok; +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_session_init( zrtp_global_t* zrtp, + zrtp_profile_t* profile, + zrtp_zid_t zid, + uint8_t is_initiator, + zrtp_session_t **session) +{ + uint32_t i = 0; + zrtp_status_t s = zrtp_status_fail; + zrtp_session_t* new_session = NULL; + + if (!zrtp) { + return zrtp_status_bad_param; + } + + new_session = zrtp_sys_alloc(sizeof(zrtp_session_t)); + if (!new_session) { + return zrtp_status_alloc_fail; + } + + zrtp_memset(new_session, 0, sizeof(zrtp_session_t)); + new_session->id = zrtp->sessions_count++; + + { + zrtp_uchar32_t buff; + ZRTP_LOG(3, (_ZTU_,"START SESSION INITIALIZATION. sID=%u.\n", new_session->id)); + ZRTP_LOG(3, (_ZTU_,"ZID=%s.\n", hex2str((const char*)zid, sizeof(zrtp_uchar12_t), (char*)buff, sizeof(buff)) )); + } + + do { + /* + * Apply profile for the stream context: set flags and prepare Hello packet. + * If profile structure isn't provided, generate default. + */ + if (!profile) { + ZRTP_LOG(1, (_ZTU_,"Profile in NULL - loading default one.\n")); + zrtp_profile_defaults(&new_session->profile, zrtp); + } else { + ZRTP_LOG(1, (_ZTU_,"Loading User's profile:\n")); + if (zrtp_status_ok != zrtp_profile_check(profile, zrtp)) { + ZRTP_LOG(1, (_ZTU_,"ERROR! Can't apply wrong profile to the session sID=%u.\n", new_session->id)); + break; + } + + /* Adjust user's settings: force SHA-384 hash for ECDH-384P */ + if (zrtp_profile_find(profile, ZRTP_CC_PKT, ZRTP_PKTYPE_EC384P) > 0) { + ZRTP_LOG(3, (_ZTU_,"User wants ECDH384 - auto-adjust profile to use SHA-384.\n")); + profile->hash_schemes[0] = ZRTP_HASH_SHA384; + profile->hash_schemes[1] = ZRTP_HASH_SHA256; + profile->hash_schemes[2] = 0; + } + + zrtp_memcpy(&new_session->profile, profile, sizeof(zrtp_profile_t)); + + { + int i; + ZRTP_LOG(3, (_ZTU_," allowclear: %s\n", profile->allowclear?"ON":"OFF")); + ZRTP_LOG(3, (_ZTU_," autosecure: %s\n", profile->autosecure?"ON":"OFF")); + ZRTP_LOG(3, (_ZTU_," disclose_bit: %s\n", profile->disclose_bit?"ON":"OFF")); + ZRTP_LOG(3, (_ZTU_," TTL: %u\n", profile->cache_ttl)); + + ZRTP_LOG(3, (_ZTU_," SAS schemes: ")); + i=0; + while (profile->sas_schemes[i]) { + ZRTP_LOGC(3, ("%.4s ", zrtp_comp_id2type(ZRTP_CC_SAS, profile->sas_schemes[i++]))); + } + ZRTP_LOGC(3, ("\n")); ZRTP_LOG(1, (_ZTU_," Ciphers: ")); + i=0; + while (profile->cipher_types[i]) { + ZRTP_LOGC(3, ("%.4s ", zrtp_comp_id2type(ZRTP_CC_CIPHER, profile->cipher_types[i++]))); + } + ZRTP_LOGC(3, ("\n")); ZRTP_LOG(1, (_ZTU_," PK schemes: ")); + i=0; + while (profile->pk_schemes[i]) { + ZRTP_LOGC(3, ("%.4s ", zrtp_comp_id2type(ZRTP_CC_PKT, profile->pk_schemes[i++]))); + } + ZRTP_LOGC(3, ("\n")); ZRTP_LOG(1, (_ZTU_," ATL: ")); + i=0; + while (profile->auth_tag_lens[i]) { + ZRTP_LOGC(3, ("%.4s ", zrtp_comp_id2type(ZRTP_CC_ATL, profile->auth_tag_lens[i++]))); + } + ZRTP_LOGC(3, ("\n")); ZRTP_LOG(1, (_ZTU_," Hashes: ")); + i=0; + while (profile->hash_schemes[i]) { + ZRTP_LOGC(3, ("%.4s ", zrtp_comp_id2type(ZRTP_CC_HASH, profile->hash_schemes[i++]))); + } + ZRTP_LOGC(3, ("\n")); + } + } + + /* Set ZIDs */ + ZSTR_SET_EMPTY(new_session->zid); + ZSTR_SET_EMPTY(new_session->peer_zid); + zrtp_zstrncpyc(ZSTR_GV(new_session->zid), (const char*)zid, sizeof(zrtp_zid_t)); + + new_session->zrtp = zrtp; + new_session->is_initiator = is_initiator; + new_session->mitm_alert_detected = 0; + + /* + * Allocate memory for holding secrets and initialize with random values. + * Actual values will be written from the cache at the beginning of the protocol. + */ + new_session->secrets.rs1 = _zrtp_alloc_shared_secret(new_session); + new_session->secrets.rs2 = _zrtp_alloc_shared_secret(new_session); + new_session->secrets.auxs = _zrtp_alloc_shared_secret(new_session); + new_session->secrets.pbxs = _zrtp_alloc_shared_secret(new_session); + + if ( !new_session->secrets.rs1 || !new_session->secrets.rs2 || + !new_session->secrets.auxs || !new_session->secrets.pbxs) { + ZRTP_LOG(1, (_ZTU_,"ERROR! Can't allocate shared secrets sID=%u\n.", new_session->id)); + s = zrtp_status_alloc_fail; + break; + } + + /* Initialize SAS values */ + ZSTR_SET_EMPTY(new_session->sas1); + ZSTR_SET_EMPTY(new_session->sas2); + ZSTR_SET_EMPTY(new_session->sasbin); + ZSTR_SET_EMPTY(new_session->zrtpsess); + + /* Clear all stream structures */ + for (i=0; istreams[i].state = ZRTP_STATE_NONE; + new_session->streams[i].prev_state = ZRTP_STATE_NONE; + new_session->streams[i].mode = ZRTP_STREAM_MODE_UNKN; + } + + /* Initialize synchronization objects */ + s = zrtp_mutex_init(&new_session->streams_protector); + if (zrtp_status_ok != s) { + ZRTP_LOG(1, (_ZTU_,"ERROR! can't initialize Stream protector. sID=%u.\n", new_session->id)); + break; + } + s = zrtp_mutex_init(&new_session->init_protector); + if (zrtp_status_ok != s) { + ZRTP_LOG(1, (_ZTU_,"ERROR! can't initialize Init protector. sID=%u.\n", new_session->id)); + break; + } + + s = zrtp_status_ok; + } while (0); + + if (zrtp_status_ok != s) { + zrtp_sys_free(new_session); + return s; + } + + /* Add new session to the global list */ + zrtp_mutex_lock(zrtp->sessions_protector); + mlist_add(&zrtp->sessions_head, &new_session->_mlist); + zrtp_mutex_unlock(zrtp->sessions_protector); + + *session = new_session; + + ZRTP_LOG(3, (_ZTU_,"Session initialization - DONE. sID=%u.\n\n", new_session->id)); + + return zrtp_status_ok; +} + +/*----------------------------------------------------------------------------*/ +void zrtp_session_down(zrtp_session_t *session) +{ + int i =0; + + if (!session) { + return; + } + + /* Stop ZRTP engine and clear all crypto sources for every stream in the session. */ + zrtp_mutex_lock(session->streams_protector); + for(i=0; istreams[i]); + } + zrtp_mutex_unlock(session->streams_protector); + + /* Release memory allocated on initialization */ + if (session->secrets.rs1) { + zrtp_sys_free(session->secrets.rs1); + } + if (session->secrets.rs2) { + zrtp_sys_free(session->secrets.rs2); + } + if (session->secrets.auxs) { + zrtp_sys_free(session->secrets.auxs); + } + if (session->secrets.pbxs) { + zrtp_sys_free(session->secrets.pbxs); + } + + /* We don't need the session key anymore - clear it */ + zrtp_wipe_zstring(ZSTR_GV(session->zrtpsess)); + + /* Removing session from the global list */ + zrtp_mutex_lock(session->zrtp->sessions_protector); + mlist_del(&session->_mlist); + zrtp_mutex_unlock(session->zrtp->sessions_protector); + + zrtp_mutex_destroy(session->streams_protector); + zrtp_mutex_destroy(session->init_protector); + + zrtp_sys_free(session); +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_stream_attach(zrtp_session_t *session, zrtp_stream_t** stream) +{ + uint32_t i = 0; + zrtp_status_t s = zrtp_status_fail; + zrtp_stream_t* new_stream = NULL; + + ZRTP_LOG(3, (_ZTU_,"ATTACH NEW STREAM to sID=%d:\n", session->id)); + + /* + * Initialize first unused stream. If there are no available streams return error. + */ + zrtp_mutex_lock(session->streams_protector); + for (i=0; istreams[i].state) { + new_stream = &session->streams[i]; + zrtp_memset(new_stream, 0, sizeof(zrtp_stream_t)); + break; + } + } + zrtp_mutex_unlock(session->streams_protector); + + if (!new_stream) { + ZRTP_LOG(1, (_ZTU_,"\tWARNING! Can't attach one more stream. Limit is reached." + " Use #ZRTP_MAX_STREAMS_PER_SESSION. sID=%u\n", session->id)); + return zrtp_status_alloc_fail; + } + + ZSTR_SET_EMPTY(new_stream->signaling_hash); + + /* + * Initialize the private data stream with default initial values + */ + zrtp_mutex_init(&new_stream->stream_protector); + _zrtp_change_state(new_stream, ZRTP_STATE_ACTIVE); + new_stream->mode = ZRTP_STREAM_MODE_CLEAR; + new_stream->id = session->zrtp->streams_count++; + new_stream->session = session; + new_stream->zrtp = session->zrtp; + new_stream->mitm_mode = ZRTP_MITM_MODE_UNKN; + + ZSTR_SET_EMPTY(new_stream->cc.hmackey); + ZSTR_SET_EMPTY(new_stream->cc.peer_hmackey); + ZSTR_SET_EMPTY(new_stream->cc.zrtp_key); + ZSTR_SET_EMPTY(new_stream->cc.peer_zrtp_key); + + new_stream->dh_cc.initialized_with = ZRTP_COMP_UNKN; + bnBegin(&new_stream->dh_cc.peer_pv); + ZSTR_SET_EMPTY(new_stream->dh_cc.dhss); + + ZRTP_LOG(3, (_ZTU_,"\tEmpty slot was found - initializing new stream with ID=%u.\n", new_stream->id)); + + do { + zrtp_string32_t hash_buff = ZSTR_INIT_EMPTY(hash_buff); + zrtp_hash_t *hash = zrtp_comp_find(ZRTP_CC_HASH, ZRTP_HASH_SHA256, new_stream->zrtp); + s = zrtp_status_algo_fail; + + if (sizeof(uint16_t) != zrtp_randstr( new_stream->zrtp, + (uint8_t*)&new_stream->media_ctx.high_out_zrtp_seq, + sizeof(uint16_t))) { + break; + } + + /* + * Compute and store message hashes to prevent DoS attacks. + * Generate H0 as a random nonce and compute H1, H2 and H3 + * using the leftmost 128 bits from every hash. + * Then insert these directly into the message structures. + */ + + zrtp_memset(&new_stream->messages, 0, sizeof(new_stream->messages)); + ZSTR_SET_EMPTY(new_stream->messages.h0); + + /* Generate Random nonce, compute H1 and store in the DH packet */ + new_stream->messages.h0.length = (uint16_t)zrtp_randstr( new_stream->zrtp, + (unsigned char*)new_stream->messages.h0.buffer, + ZRTP_MESSAGE_HASH_SIZE); + if (ZRTP_MESSAGE_HASH_SIZE != new_stream->messages.h0.length) { + break; + } + + s = hash->hash(hash, ZSTR_GV(new_stream->messages.h0), ZSTR_GV(hash_buff)); + if (zrtp_status_ok != s) { + break; + } + zrtp_memcpy(new_stream->messages.dhpart.hash, hash_buff.buffer, ZRTP_MESSAGE_HASH_SIZE); + + /* Compute H2 for the Commit */ + s = hash->hash_c(hash, (char*)new_stream->messages.dhpart.hash, ZRTP_MESSAGE_HASH_SIZE, ZSTR_GV(hash_buff)); + if (zrtp_status_ok != s) { + break; + } + zrtp_memcpy(new_stream->messages.commit.hash, hash_buff.buffer, ZRTP_MESSAGE_HASH_SIZE); + + /* Compute H3 for the Hello message */ + s = hash->hash_c(hash, (char*)new_stream->messages.commit.hash, ZRTP_MESSAGE_HASH_SIZE, ZSTR_GV(hash_buff)); + if (zrtp_status_ok != s) { + break; + } + zrtp_memcpy(new_stream->messages.hello.hash, hash_buff.buffer, ZRTP_MESSAGE_HASH_SIZE); + + s = zrtp_status_ok; + } while (0); + + if (zrtp_status_ok != s) { + ZRTP_LOG(1, (_ZTU_,"\tERROR! Fail to compute messages hashes <%s>.\n", zrtp_log_status2str(s))); + return s; + } + + /* + * Preparing HELLO based on user's profile + */ + ZRTP_LOG(3, (_ZTU_,"\tPreparing ZRTP Hello according to the Session profile.\n")); + { + zrtp_packet_Hello_t* hello = &new_stream->messages.hello; + uint8_t i = 0; + int8_t* comp_ptr = NULL; + + zrtp_memcpy(hello->version, ZRTP_PROTOCOL_VERSION, ZRTP_VERSION_SIZE); + zrtp_memcpy(hello->cliend_id, session->zrtp->client_id.buffer, session->zrtp->client_id.length); + hello->pasive = (ZRTP_LICENSE_MODE_PASSIVE == session->zrtp->lic_mode) ? 1 : 0; + hello->mitmflag = session->zrtp->is_mitm; + hello->sigflag = 0; + zrtp_memcpy(hello->zid, session->zid.buffer, session->zid.length); + + comp_ptr = (int8_t*)hello->comp; + i = 0; + while ( session->profile.hash_schemes[i]) { + zrtp_memcpy( comp_ptr, + zrtp_comp_id2type(ZRTP_CC_HASH, session->profile.hash_schemes[i++]), + ZRTP_COMP_TYPE_SIZE ); + comp_ptr += ZRTP_COMP_TYPE_SIZE; + } + hello->hc = i; + + i = 0; + while (session->profile.cipher_types[i]) { + zrtp_memcpy( comp_ptr, + zrtp_comp_id2type(ZRTP_CC_CIPHER, session->profile.cipher_types[i++]), + ZRTP_COMP_TYPE_SIZE ); + comp_ptr += ZRTP_COMP_TYPE_SIZE; + } + hello->cc = i; + + i = 0; + while (session->profile.auth_tag_lens[i] ) { + zrtp_memcpy( comp_ptr, + zrtp_comp_id2type(ZRTP_CC_ATL, session->profile.auth_tag_lens[i++]), + ZRTP_COMP_TYPE_SIZE ); + comp_ptr += ZRTP_COMP_TYPE_SIZE; + } + hello->ac = i; + + i = 0; + while (session->profile.pk_schemes[i] ) { + zrtp_memcpy( comp_ptr, + zrtp_comp_id2type(ZRTP_CC_PKT, session->profile.pk_schemes[i++]), + ZRTP_COMP_TYPE_SIZE ); + comp_ptr += ZRTP_COMP_TYPE_SIZE; + } + hello->kc = i; + + i = 0; + while (session->profile.sas_schemes[i]) { + zrtp_memcpy( comp_ptr, + zrtp_comp_id2type(ZRTP_CC_SAS, session->profile.sas_schemes[i++]), + ZRTP_COMP_TYPE_SIZE ); + comp_ptr += ZRTP_COMP_TYPE_SIZE; + } + hello->sc = i; + + /* + * Hmac will appear at the end of the message, after the dynamic portion. + * i is the length of the dynamic part. + */ + i = (hello->hc + hello->cc + hello->ac + hello->kc + hello->sc) * ZRTP_COMP_TYPE_SIZE; + _zrtp_packet_fill_msg_hdr( new_stream, + ZRTP_HELLO, + ZRTP_HELLO_STATIC_SIZE + i + ZRTP_HMAC_SIZE, + &hello->hdr); + } + + *stream = new_stream; + + ZRTP_LOG(3, (_ZTU_,"ATTACH NEW STREAM - DONE.\n")); + return zrtp_status_ok; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t zrtp_signaling_hash_get( zrtp_stream_t* stream, + char *hash_buff, + uint32_t hash_buff_length) +{ + zrtp_string32_t hash_str = ZSTR_INIT_EMPTY(hash_str); + zrtp_hash_t *hash = NULL; + + if (!stream) { + return zrtp_status_bad_param; + } + + if (ZRTP_MESSAGE_HASH_SIZE*2+1 > hash_buff_length) { + return zrtp_status_buffer_size; + } + + if (stream->state < ZRTP_STATE_ACTIVE) { + return zrtp_status_wrong_state; + } + + hash = zrtp_comp_find(ZRTP_CC_HASH, ZRTP_HASH_SHA256, stream->zrtp); + hash->hash_c( hash, + (const char*)&stream->messages.hello.hdr, + zrtp_ntoh16(stream->messages.hello.hdr.length) * 4, + ZSTR_GV(hash_str) ); + + hex2str(hash_str.buffer, ZRTP_MESSAGE_HASH_SIZE, hash_buff, hash_buff_length); + + return zrtp_status_ok; +} + +zrtp_status_t zrtp_signaling_hash_set( zrtp_stream_t* ctx, + const char *hash_buff, + uint32_t hash_buff_length) +{ + if (!ctx) { + return zrtp_status_bad_param; + } + + if (ZRTP_MESSAGE_HASH_SIZE*2 < hash_buff_length) { + return zrtp_status_buffer_size; + } + + if (ctx->state != ZRTP_STATE_ACTIVE) { + return zrtp_status_wrong_state; + } + + str2hex( hash_buff, + hash_buff_length, + ctx->messages.signaling_hash.buffer, + ctx->messages.signaling_hash.max_length); + ctx->messages.signaling_hash.length = ZRTP_MESSAGE_HASH_SIZE; + + { + char buff[66]; + ZRTP_LOG(3, (_ZTU_,"SIGNALLING HAS was ADDED for the comparing. ID=%u\n", ctx->id)); + ZRTP_LOG(3, (_ZTU_,"Hash=%s.\n", hex2str(hash_buff, hash_buff_length, buff, sizeof(buff)))); + } + + return zrtp_status_ok; +} + + +/*----------------------------------------------------------------------------*/ +static const char* zrtp_pkt2str[] = { + "Preshared", + "Multistream", + "DH-2048", + "ECDH-256", + "DH-3072", + "ECDH-384", + "ECDH-521", + "DH-4096" +}; + +static const char* zrtp_hash2str[] = { + "SHA-256", + "SHA1", + "SHA-384" +}; + +static const char* zrtp_cipher2str[] = { + "AES-128", + "AES-256" +}; + +static const char* zrtp_atl2str[] = { + "HMAC-SHA1 32 bit", + "HMAC-SHA1 80 bit" +}; + +static const char* zrtp_sas2str[] = { + "Base-32", + "Base-256" +}; + +zrtp_status_t zrtp_session_get(zrtp_session_t *session, zrtp_session_info_t *info) +{ + int i=0; + if (!session || !info) { + return zrtp_status_bad_param; + } + + zrtp_memset(info, 0, sizeof(zrtp_session_info_t)); + + ZSTR_SET_EMPTY(info->peer_clientid); + ZSTR_SET_EMPTY(info->peer_version); + ZSTR_SET_EMPTY(info->zid); + ZSTR_SET_EMPTY(info->peer_zid); + ZSTR_SET_EMPTY(info->sas1); + ZSTR_SET_EMPTY(info->sasbin); + ZSTR_SET_EMPTY(info->sas2); + ZSTR_SET_EMPTY(info->auth_name); + ZSTR_SET_EMPTY(info->cipher_name); + ZSTR_SET_EMPTY(info->hash_name); + ZSTR_SET_EMPTY(info->sas_name); + ZSTR_SET_EMPTY(info->pk_name); + + info->id = session->id; + zrtp_zstrcpy(ZSTR_GV(info->zid), ZSTR_GV(session->zid)); + zrtp_zstrcpy(ZSTR_GV(info->peer_zid), ZSTR_GV(session->peer_zid)); + + for (i=0; istreams[i]; + if ((full_stream->state > ZRTP_STATE_ACTIVE) && !ZRTP_IS_STREAM_FAST(full_stream)) + { + zrtp_zstrcpyc(ZSTR_GV(info->pk_name), zrtp_pkt2str[full_stream->pubkeyscheme->base.id-1]); + + zrtp_zstrncpyc( ZSTR_GV(info->peer_clientid), + (const char*)full_stream->messages.peer_hello.cliend_id, 16); + zrtp_zstrncpyc( ZSTR_GV(info->peer_version), + (const char*)full_stream->messages.peer_hello.version, 4); + + info->secrets_ttl = full_stream->cache_ttl; + } + } + + info->sas_is_ready = (session->zrtpsess.length > 0) ? 1 : 0; + if (info->sas_is_ready) { + zrtp_zstrcpy(ZSTR_GV(info->sas1), ZSTR_GV(session->sas1)); + zrtp_zstrcpy(ZSTR_GV(info->sas2), ZSTR_GV(session->sas2)); + zrtp_zstrcpy(ZSTR_GV(info->sasbin), ZSTR_GV(session->sasbin)); + info->sas_is_base256 = (ZRTP_SAS_BASE256 == session->sasscheme->base.id); + + info->sas_is_verified = 0; + if (session->zrtp->cb.cache_cb.on_get_verified) { + session->zrtp->cb.cache_cb.on_get_verified( ZSTR_GV(session->zid), + ZSTR_GV(session->peer_zid), + &info->sas_is_verified); + } + + zrtp_zstrcpyc(ZSTR_GV(info->hash_name), zrtp_hash2str[session->hash->base.id-1]); + zrtp_zstrcpyc(ZSTR_GV(info->cipher_name), zrtp_cipher2str[session->blockcipher->base.id-1]); + zrtp_zstrcpyc(ZSTR_GV(info->auth_name), zrtp_atl2str[session->authtaglength->base.id-1]); + zrtp_zstrcpyc(ZSTR_GV(info->sas_name), zrtp_sas2str[session->sasscheme->base.id-1]); + + info->cached_flags = session->secrets.cached_curr; + info->matches_flags= session->secrets.matches_curr; + info->wrongs_flags = session->secrets.wrongs_curr; + } + + return zrtp_status_ok; +} + +zrtp_status_t zrtp_stream_get(zrtp_stream_t *stream, zrtp_stream_info_t *info) +{ + if (!stream || !info) { + return zrtp_status_bad_param; + } + + zrtp_memset(info, 0, sizeof(zrtp_stream_info_t)); + + info->id = stream->id; + info->state = stream->state; + info->mode = stream->mode; + info->mitm_mode = stream->mitm_mode; + + if (stream->state > ZRTP_STATE_ACTIVE) { + info->last_error = stream->last_error; + info->peer_passive = stream->peer_passive; + info->res_allowclear= stream->allowclear; + info->peer_disclose = stream->peer_disclose_bit; + info->peer_mitm = stream->peer_mitm_flag; + } + + return zrtp_status_ok; +} + +void zrtp_session_set_userdata(zrtp_session_t *session, void* udata) { + session->usr_data = udata; +} +void* zrtp_session_get_userdata(zrtp_session_t *session) { + return session->usr_data; +} + +void zrtp_stream_set_userdata(zrtp_stream_t *stream, void* udata) { + stream->usr_data = udata; +} +void* zrtp_stream_get_userdata(const zrtp_stream_t *stream) { + return stream->usr_data; +} + +/*----------------------------------------------------------------------------*/ +void zrtp_profile_defaults(zrtp_profile_t* profile, zrtp_global_t* zrtp) +{ + zrtp_memset(profile, 0, sizeof(zrtp_profile_t)); + + profile->autosecure = 1; + profile->allowclear = 0; + profile->discovery_optimization = 1; + profile->cache_ttl = ZRTP_CACHE_DEFAULT_TTL; + + profile->sas_schemes[0] = ZRTP_SAS_BASE256; + profile->sas_schemes[1] = ZRTP_SAS_BASE32; + profile->cipher_types[0] = ZRTP_CIPHER_AES256; + profile->cipher_types[1] = ZRTP_CIPHER_AES128; + profile->auth_tag_lens[0] = ZRTP_ATL_HS32; + profile->hash_schemes[0] = ZRTP_HASH_SHA256; + +#if (defined(ZRTP_ENABLE_EC) && (ZRTP_ENABLE_EC == 1)) + if (zrtp && (ZRTP_LICENSE_MODE_PASSIVE == zrtp->lic_mode)) { + profile->pk_schemes[0] = ZRTP_PKTYPE_DH2048; + profile->pk_schemes[1] = ZRTP_PKTYPE_EC256P; + profile->pk_schemes[2] = ZRTP_PKTYPE_DH3072; + } else { + profile->pk_schemes[0] = ZRTP_PKTYPE_EC256P; + profile->pk_schemes[1] = ZRTP_PKTYPE_DH3072; + profile->pk_schemes[2] = ZRTP_PKTYPE_DH2048; + } + profile->pk_schemes[3] = ZRTP_PKTYPE_MULT; +#else + if (zrtp && (ZRTP_LICENSE_MODE_PASSIVE == zrtp->lic_mode)) { + profile->pk_schemes[0] = ZRTP_PKTYPE_DH2048; + profile->pk_schemes[1] = ZRTP_PKTYPE_DH3072; + } else { + profile->pk_schemes[0] = ZRTP_PKTYPE_DH3072; + profile->pk_schemes[1] = ZRTP_PKTYPE_DH2048; + } + profile->pk_schemes[2] = ZRTP_PKTYPE_MULT; +#endif +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_profile_check(const zrtp_profile_t* profile, zrtp_global_t* zrtp) +{ + uint8_t i = 0; + + /* + * Fail if the required base components are not present in the profile. + */ + if (0 > zrtp_profile_find(profile, ZRTP_CC_HASH, ZRTP_HASH_SHA256)) { + ZRTP_LOG(1, (_ZTU_,"WARNING! can't find 'SHA256 ' in profile.\n")); + return zrtp_status_fail; + } + + if (0 > zrtp_profile_find(profile, ZRTP_CC_SAS, ZRTP_SAS_BASE32)) { + ZRTP_LOG(1, (_ZTU_,"WARNING! can't find 'base32' in profile.\n")); + return zrtp_status_fail; + } + + if (0 > zrtp_profile_find(profile, ZRTP_CC_CIPHER, ZRTP_CIPHER_AES128)) { + ZRTP_LOG(1, (_ZTU_,"WARNING! can't find 'AES1287 ' in profile.\n")); + return zrtp_status_fail; + } + + if (0 > zrtp_profile_find(profile, ZRTP_CC_PKT, ZRTP_PKTYPE_DH3072)) { + ZRTP_LOG(1, (_ZTU_,"WARNING! can't find 'DH3K' in profile.\n")); + return zrtp_status_fail; + } + + if (0 > zrtp_profile_find(profile, ZRTP_CC_PKT, ZRTP_PKTYPE_MULT)) { + ZRTP_LOG(1, (_ZTU_,"WARNING! can't find 'Mult' in profile.\n")); + return zrtp_status_fail; + } + + if (0 > zrtp_profile_find(profile, ZRTP_CC_ATL, ZRTP_ATL_HS32)) { + ZRTP_LOG(1, (_ZTU_,"WARNING! can't find '32 ' in profile.\n")); + return zrtp_status_fail; + } + + /* + * Check that each component in the profile is in the global set of components. + */ + i = 0; + while (profile->sas_schemes[i]) { + if (!zrtp_comp_find(ZRTP_CC_SAS, profile->sas_schemes[i++], zrtp)) { + return zrtp_status_fail; + } + } + + i = 0; + while (profile->cipher_types[i]) { + if (!zrtp_comp_find( ZRTP_CC_CIPHER, profile->cipher_types[i++], zrtp)) { + return zrtp_status_fail; + } + } + + i = 0; + while (profile->pk_schemes[i]) { + if (!zrtp_comp_find(ZRTP_CC_PKT, profile->pk_schemes[i++], zrtp)) { + return zrtp_status_fail; + } + } + + i = 0; + while (profile->auth_tag_lens[i]) { + if (!zrtp_comp_find(ZRTP_CC_ATL, profile->auth_tag_lens[i++], zrtp)) { + return zrtp_status_fail; + } + } + + i = 0; + while (profile->hash_schemes[i]) { + if (!zrtp_comp_find(ZRTP_CC_HASH, profile->hash_schemes[i++], zrtp)) { + return zrtp_status_fail; + } + } + + /* Can't use Preshared with No cahce */ + if (NULL == zrtp->cb.cache_cb.on_get) { + i = 0; + while (profile->pk_schemes[i]) { + if (ZRTP_PKTYPE_PRESH == profile->pk_schemes[i++]) { + ZRTP_LOG(1, (_ZTU_,"WARNING! can't use Preshared PK with no cache.\n")); + return zrtp_status_fail; + } + } + } + + return zrtp_status_ok; +} + + +/*----------------------------------------------------------------------------*/ +int zrtp_profile_find(const zrtp_profile_t* profile, zrtp_crypto_comp_t type, uint8_t id) + +{ + uint8_t* prof_elem = NULL; + unsigned int i = 0; + + if (!profile || !id) { + return -1; + } + + switch (type) + { + case ZRTP_CC_HASH: + prof_elem = (uint8_t*)profile->hash_schemes; + break; + case ZRTP_CC_SAS: + prof_elem = (uint8_t*)profile->sas_schemes; + break; + case ZRTP_CC_CIPHER: + prof_elem = (uint8_t*)profile->cipher_types; + break; + case ZRTP_CC_PKT: + prof_elem = (uint8_t*)profile->pk_schemes; + break; + case ZRTP_CC_ATL: + prof_elem = (uint8_t*)profile->auth_tag_lens; + break; + default: + return -1; + } + + + i = 0; + while ( prof_elem[i] ) { + if (id == prof_elem[i++]) return i; + } + + return -1; +} + + +/*============================================================================*/ +/* ZRTP components management part */ +/*============================================================================*/ + + +/*----------------------------------------------------------------------------*/ +#define DESTROY_COMP(mac_node, mac_tmp, mac_type, mac_head, mac_comp)\ +{ \ + mac_node = mac_tmp = NULL;\ + mac_comp = NULL;\ + mlist_for_each_safe(mac_node, mac_tmp, mac_head) \ + {\ + mac_comp = (zrtp_comp_t*) mlist_get_struct(mac_type, mlist, mac_node); \ + if (mac_comp->free)\ + mac_comp->free((mac_type*)mac_comp);\ + mlist_del(mac_node);\ + zrtp_sys_free(mac_comp);\ + } \ +}break + +zrtp_status_t zrtp_comp_done(zrtp_crypto_comp_t type, zrtp_global_t* zrtp) +{ + mlist_t* node = NULL; + mlist_t* tmp = NULL; + zrtp_comp_t* comp = NULL; + + switch (type) + { + case ZRTP_CC_HASH: + DESTROY_COMP(node, tmp, zrtp_hash_t, &zrtp->hash_head, comp); + case ZRTP_CC_SAS: + DESTROY_COMP(node, tmp, zrtp_sas_scheme_t, &zrtp->sas_head, comp); + case ZRTP_CC_CIPHER: + DESTROY_COMP(node, tmp, zrtp_cipher_t, &zrtp->cipher_head, comp); + case ZRTP_CC_PKT: + DESTROY_COMP(node, tmp, zrtp_pk_scheme_t, &zrtp->pktype_head, comp); + case ZRTP_CC_ATL: + DESTROY_COMP(node, tmp, zrtp_auth_tag_length_t, &zrtp->atl_head, comp); + default: + break; + } + + return zrtp_status_ok; +} + +/*----------------------------------------------------------------------------*/ +#define ZRTP_COMP_INIT(mac_type, mac_head, mac_elem)\ +{\ + mac_type* mac_e = (mac_type*)mac_elem; \ + mlist_add_tail(mac_head, &mac_e->mlist);\ + if (mac_e->base.init)\ + mac_e->base.init((mac_type*)mac_e);\ +} break;\ + +zrtp_status_t zrtp_comp_register( zrtp_crypto_comp_t type, + void *comp, + zrtp_global_t* zrtp ) +{ + switch (type) + { + case ZRTP_CC_HASH: + ZRTP_COMP_INIT(zrtp_hash_t, &zrtp->hash_head, comp); + case ZRTP_CC_SAS: + ZRTP_COMP_INIT(zrtp_sas_scheme_t, &zrtp->sas_head, comp); + case ZRTP_CC_CIPHER: + ZRTP_COMP_INIT(zrtp_cipher_t, &zrtp->cipher_head, comp); + case ZRTP_CC_ATL: + ZRTP_COMP_INIT(zrtp_auth_tag_length_t, &zrtp->atl_head, comp); + case ZRTP_CC_PKT: + ZRTP_COMP_INIT(zrtp_pk_scheme_t, &zrtp->pktype_head, comp); + default: + break; + } + + return zrtp_status_ok; +} + +/*----------------------------------------------------------------------------*/ +#define ZRTP_COMP_FIND(mac_head, mac_id, mac_type, res)\ +{\ + mlist_t* mac_node = NULL;\ + mlist_for_each(mac_node, mac_head)\ + {\ + zrtp_comp_t* mac_e = (zrtp_comp_t*) mlist_get_struct(mac_type, mlist, mac_node);\ + if ( mac_id == mac_e->id )\ + {\ + res = (mac_type*)mac_e;\ + break;\ + }\ + }\ +} break; + +void* zrtp_comp_find(zrtp_crypto_comp_t type, uint8_t id, zrtp_global_t* zrtp) +{ + void* res = NULL; + + switch (type) + { + case ZRTP_CC_HASH: + ZRTP_COMP_FIND(&zrtp->hash_head, id, zrtp_hash_t, res); + case ZRTP_CC_SAS: + ZRTP_COMP_FIND(&zrtp->sas_head, id, zrtp_sas_scheme_t, res); + case ZRTP_CC_CIPHER: + ZRTP_COMP_FIND(&zrtp->cipher_head, id, zrtp_cipher_t, res); + case ZRTP_CC_PKT: + ZRTP_COMP_FIND(&zrtp->pktype_head, id, zrtp_pk_scheme_t, res); + case ZRTP_CC_ATL: + ZRTP_COMP_FIND(&zrtp->atl_head, id, zrtp_auth_tag_length_t, res); + default: + break; + } + + return res ; +} + +/*----------------------------------------------------------------------------*/ +char* zrtp_comp_id2type(zrtp_crypto_comp_t type, uint8_t id) +{ + if (ZRTP_COMP_UNKN == id) + return "Unkn"; + + switch (type) + { + case ZRTP_CC_HASH: + switch (id) + { + case ZRTP_HASH_SHA256: return ZRTP_S256; + case ZRTP_HASH_SHA384: return ZRTP_S384; + default: return "Unkn"; + } + + case ZRTP_CC_SAS: + switch (id) + { + case ZRTP_SAS_BASE32: return ZRTP_B32; + case ZRTP_SAS_BASE256: return ZRTP_B256; + default: return "Unkn"; + } + + case ZRTP_CC_CIPHER: + switch (id) + { + case ZRTP_CIPHER_AES128: return ZRTP_AES1; + case ZRTP_CIPHER_AES256: return ZRTP_AES3; + default: return "Unkn"; + } + + case ZRTP_CC_PKT: + switch (id) + { + case ZRTP_PKTYPE_PRESH: return ZRTP_PRESHARED; + case ZRTP_PKTYPE_MULT: return ZRTP_MULT; + case ZRTP_PKTYPE_DH2048: return ZRTP_DH2K; + case ZRTP_PKTYPE_DH3072: return ZRTP_DH3K; + case ZRTP_PKTYPE_EC256P: return ZRTP_EC256P; + case ZRTP_PKTYPE_EC384P: return ZRTP_EC384P; + case ZRTP_PKTYPE_EC521P: return ZRTP_EC521P; + default: return "Unkn"; + } + + case ZRTP_CC_ATL: + switch (id) + { + case ZRTP_ATL_HS32: return ZRTP_HS32; + case ZRTP_ATL_HS80: return ZRTP_HS80; + default: return "Unkn"; + } + + default: + return "Unkn"; + } +} + +/*----------------------------------------------------------------------------*/ +uint8_t zrtp_comp_type2id(zrtp_crypto_comp_t type, char* name) +{ + switch (type) + { + case ZRTP_CC_HASH: + if (!zrtp_memcmp(ZRTP_S256, name, ZRTP_COMP_TYPE_SIZE)) { + return ZRTP_HASH_SHA256; + } + if (!zrtp_memcmp(ZRTP_S384, name, ZRTP_COMP_TYPE_SIZE)) { + return ZRTP_HASH_SHA384; + } + break; + + case ZRTP_CC_SAS: + if (!zrtp_memcmp(ZRTP_B32, name, ZRTP_COMP_TYPE_SIZE)) { + return ZRTP_SAS_BASE32; + } + if (!zrtp_memcmp(ZRTP_B256, name, ZRTP_COMP_TYPE_SIZE)) { + return ZRTP_SAS_BASE256; + } + break; + + case ZRTP_CC_CIPHER: + if (!zrtp_memcmp(ZRTP_AES1, name, ZRTP_COMP_TYPE_SIZE)) { + return ZRTP_CIPHER_AES128; + } + if (!zrtp_memcmp(ZRTP_AES3, name, ZRTP_COMP_TYPE_SIZE)) { + return ZRTP_CIPHER_AES256; + } + break; + + case ZRTP_CC_PKT: + if (!zrtp_memcmp(ZRTP_PRESHARED, name, ZRTP_COMP_TYPE_SIZE)) { + return ZRTP_PKTYPE_PRESH; + } + if (!zrtp_memcmp(ZRTP_MULT, name, ZRTP_COMP_TYPE_SIZE)) { + return ZRTP_PKTYPE_MULT; + } + if (!zrtp_memcmp(ZRTP_DH3K, name, ZRTP_COMP_TYPE_SIZE)) { + return ZRTP_PKTYPE_DH3072; + } + if (!zrtp_memcmp(ZRTP_DH2K, name, ZRTP_COMP_TYPE_SIZE)) { + return ZRTP_PKTYPE_DH2048; + } + if (!zrtp_memcmp(ZRTP_EC256P, name, ZRTP_COMP_TYPE_SIZE)) { + return ZRTP_PKTYPE_EC256P; + } + if (!zrtp_memcmp(ZRTP_EC384P, name, ZRTP_COMP_TYPE_SIZE)) { + return ZRTP_PKTYPE_EC384P; + } + if (!zrtp_memcmp(ZRTP_EC521P, name, ZRTP_COMP_TYPE_SIZE)) { + return ZRTP_PKTYPE_EC521P; + } + break; + + case ZRTP_CC_ATL: + if ( !zrtp_memcmp(ZRTP_HS32, name, ZRTP_COMP_TYPE_SIZE)) { + return ZRTP_ATL_HS32; + } + if (!zrtp_memcmp(ZRTP_HS80, name, ZRTP_COMP_TYPE_SIZE)) { + return ZRTP_ATL_HS80; + } + break; + + default: + return 0; + } + + return 0; +} diff --git a/src/zrtp_crc.c b/src/zrtp_crc.c new file mode 100644 index 0000000000..847b4e3f3f --- /dev/null +++ b/src/zrtp_crc.c @@ -0,0 +1,146 @@ +/* + * 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 + */ + +#include "zrtp.h" + +#define ZRTP_CRC32C_POLY 0x1EDC6F41 +#define ZRTP_CRC32C(crc_c,c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF]) + +/*----------------------------------------------------------------------------*/ +uint32_t zrtp_generate_crc(const uint8_t* buff, uint32_t length) +{ + uint32_t i=0; + uint32_t crc32 = ~0L; + uint32_t result; + uint8_t byte0,byte1,byte2,byte3; + + static const uint32_t crc_c[256] = + { + 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, + 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, + 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, + 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L, + 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL, + 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, + 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, + 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL, + 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL, + 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, + 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, + 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, + 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L, + 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL, + 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, + 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, + 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, + 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L, + 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L, + 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, + 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, + 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, + 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L, + 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L, + 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L, + 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, + 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, + 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L, + 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L, + 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L, + 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, + 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, + 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL, + 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L, + 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, + 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, + 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, + 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL, + 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL, + 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, + 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, + 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, + 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL, + 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L, + 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL, + 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, + 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, + 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL, + 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L, + 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL, + 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, + 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, + 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL, + 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L, + 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, + 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, + 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, + 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L, + 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L, + 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, + 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, + 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, + 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL, + 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L, + }; + + for (i=0; i>8) & 0xff; + byte2 = (result>>16) & 0xff; + byte3 = (result>>24) & 0xff; + + crc32 = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); + return ( crc32 ); +} + + +/*----------------------------------------------------------------------------*/ +void _zrtp_packet_insert_crc(char* packet, uint32_t length) +{ + uint32_t crc32; + uint32_t* packet_crc = (uint32_t*) (packet + length - 4); /* Last 4 bytes contain CRC */ + + *packet_crc = 0L; + crc32 = zrtp_generate_crc((const uint8_t*)packet, length-4); + *packet_crc = zrtp_hton32(crc32); +} + + +/*----------------------------------------------------------------------------*/ +int8_t _zrtp_packet_validate_crc(const char* packet, uint32_t length) +{ + ZRTP_UNALIGNED(uint32_t)*packet_crc = 0; + uint32_t original_crc32 = 0L; + uint32_t crc32 = 0L; + + packet_crc = (uint32_t*) (packet + length - 4); /* Last 4 bytes contain CRC */ + original_crc32 = zrtp_ntoh32(*packet_crc); + *packet_crc = 0L; + crc32 = zrtp_generate_crc((const uint8_t*)packet, length-4); + *packet_crc = zrtp_hton32(original_crc32); + + return !(original_crc32 == crc32); +} diff --git a/src/zrtp_crypto_aes.c b/src/zrtp_crypto_aes.c new file mode 100644 index 0000000000..f6058fd90e --- /dev/null +++ b/src/zrtp_crypto_aes.c @@ -0,0 +1,833 @@ +/* + * 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 + * Vitaly Rozhkov + */ + +#include "zrtp.h" + +#define _ZTU_ "zrtp cipher" + +typedef struct zrtp_aes_cfb_ctx { + uint8_t mode; + aes_encrypt_ctx aes_ctx[1]; + zrtp_v128_t iv; +} zrtp_aes_cfb_ctx_t; + +typedef struct zrtp_aes_ctr_ctx { + uint8_t mode; + aes_encrypt_ctx aes_ctx[1]; + zrtp_v128_t salt; + zrtp_v128_t counter; +}zrtp_aes_ctr_ctx_t; + + +/*===========================================================================*/ +/* Global AES functions */ +/*===========================================================================*/ + +/*---------------------------------------------------------------------------*/ +zrtp_status_t zrtp_aes_cfb_stop(zrtp_cipher_t *self, void *cipher_ctx) { + zrtp_memset(cipher_ctx, 0, sizeof(zrtp_aes_cfb_ctx_t)); + zrtp_sys_free(cipher_ctx); + return zrtp_status_ok; +} + +zrtp_status_t zrtp_aes_ctr_stop(zrtp_cipher_t *self, void *cipher_ctx) { + zrtp_memset(cipher_ctx, 0, sizeof(zrtp_aes_ctr_ctx_t)); + zrtp_sys_free(cipher_ctx); + return zrtp_status_ok; +} + +zrtp_status_t zrtp_aes_stop(zrtp_cipher_t *self, void *cipher_ctx) +{ + zrtp_status_t res; + zrtp_cipher_mode_t *mode = (zrtp_cipher_mode_t*)cipher_ctx; + switch (mode->mode) { + case ZRTP_CIPHER_MODE_CTR: + res = zrtp_aes_ctr_stop(self, cipher_ctx); + break; + case ZRTP_CIPHER_MODE_CFB: + res = zrtp_aes_cfb_stop(self, cipher_ctx); + break; + default: + res = zrtp_status_bad_param; + break; + } + return res; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t zrtp_aes_cfb_set_iv(zrtp_cipher_t *self, void* cipher_ctx, zrtp_v128_t *iv) +{ + zrtp_aes_cfb_ctx_t* ctx = (zrtp_aes_cfb_ctx_t*)cipher_ctx; + zrtp_memcpy(&ctx->iv, iv, sizeof(zrtp_v128_t)); + + /* clear previous context except the first byte (key length) */ + zrtp_bg_aes_mode_reset(ctx->aes_ctx); + return zrtp_status_ok; +} + +zrtp_status_t zrtp_aes_ctr_set_iv(zrtp_cipher_t *self, void *cipher_ctx, zrtp_v128_t *iv ) +{ + zrtp_aes_ctr_ctx_t* ctx = (zrtp_aes_ctr_ctx_t*)cipher_ctx; + zrtp_v128_xor(&ctx->counter, &ctx->salt, iv); + + /* clear previous context except the first byte (key length) */ + zrtp_bg_aes_mode_reset(ctx->aes_ctx); + return zrtp_status_ok; +} + +zrtp_status_t zrtp_aes_set_iv(zrtp_cipher_t *self, void *cipher_ctx, zrtp_v128_t *iv ) +{ + zrtp_status_t res; + zrtp_cipher_mode_t *mode = (zrtp_cipher_mode_t*)cipher_ctx; + + switch (mode->mode) { + case ZRTP_CIPHER_MODE_CTR: + res = zrtp_aes_ctr_set_iv(self, cipher_ctx, iv); + break; + case ZRTP_CIPHER_MODE_CFB: + res = zrtp_aes_cfb_set_iv(self, cipher_ctx, iv); + break; + default: + res = zrtp_status_bad_param; + break; + } + return res; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t zrtp_aes_cfb_encrypt( zrtp_cipher_t *self, + void* cipher_ctx, + unsigned char *buf, + int len) { + zrtp_aes_cfb_ctx_t* ctx = (zrtp_aes_cfb_ctx_t*)cipher_ctx; + AES_RETURN res = zrtp_bg_aes_cfb_encrypt(buf, buf, len, ctx->iv.v8, ctx->aes_ctx); + + return (EXIT_SUCCESS == res) ? zrtp_status_ok : zrtp_status_cipher_fail; +} + +void zrtp_aes_ctr_inc(unsigned char *counter) { + if(!(++counter[15])) { + ++counter[14]; + } +} + +zrtp_status_t zrtp_aes_ctr_encrypt( zrtp_cipher_t *self, + void *cipher_ctx, + unsigned char *buf, + int len ) { + zrtp_aes_ctr_ctx_t* ctx = (zrtp_aes_ctr_ctx_t*)cipher_ctx; + AES_RETURN res = zrtp_bg_aes_ctr_crypt(buf, buf, len, ctx->counter.v8, zrtp_aes_ctr_inc, ctx->aes_ctx); + + return (EXIT_SUCCESS == res) ? zrtp_status_ok : zrtp_status_cipher_fail; +} + +zrtp_status_t zrtp_aes_encrypt( zrtp_cipher_t *self, + void *cipher_ctx, + unsigned char *buf, + int len) +{ + zrtp_status_t res; + zrtp_cipher_mode_t* mode = (zrtp_cipher_mode_t*)cipher_ctx; + switch (mode->mode) { + case ZRTP_CIPHER_MODE_CTR: + res = zrtp_aes_ctr_encrypt(self, cipher_ctx, buf, len); + break; + case ZRTP_CIPHER_MODE_CFB: + res = zrtp_aes_cfb_encrypt(self, cipher_ctx, buf, len); + break; + default: + res = zrtp_status_bad_param; + break; + } + return res; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t zrtp_aes_cfb_decrypt( zrtp_cipher_t *self, + void* cipher_ctx, + unsigned char *buf, + int len) { + zrtp_aes_cfb_ctx_t* ctx = (zrtp_aes_cfb_ctx_t*)cipher_ctx; + AES_RETURN res = zrtp_bg_aes_cfb_decrypt(buf, buf, len, ctx->iv.v8, ctx->aes_ctx); + + return (EXIT_SUCCESS == res) ? zrtp_status_ok : zrtp_status_cipher_fail; +} + +zrtp_status_t zrtp_aes_ctr_decrypt( zrtp_cipher_t *self, + void *cipher_ctx, + unsigned char *buf, + int len) { + zrtp_aes_ctr_ctx_t* ctx = (zrtp_aes_ctr_ctx_t*)cipher_ctx; + + AES_RETURN res = zrtp_bg_aes_ctr_crypt(buf, buf, len, ctx->counter.v8, zrtp_aes_ctr_inc, ctx->aes_ctx); + return (EXIT_SUCCESS == res) ? zrtp_status_ok : zrtp_status_cipher_fail; +} + +zrtp_status_t zrtp_aes_decrypt( zrtp_cipher_t *self, + void *cipher_ctx, + unsigned char *buf, + int len) +{ + zrtp_status_t res; + zrtp_cipher_mode_t *mode = (zrtp_cipher_mode_t*)cipher_ctx; + + switch(mode->mode){ + case ZRTP_CIPHER_MODE_CTR: + res = zrtp_aes_ctr_decrypt(self, cipher_ctx, buf, len); + break; + case ZRTP_CIPHER_MODE_CFB: + res = zrtp_aes_cfb_decrypt(self, cipher_ctx, buf, len); + break; + default: + res = zrtp_status_bad_param; + break; + } + return res; +} + + +/*===========================================================================*/ +/* AES 128 implementation */ +/*===========================================================================*/ + +/*---------------------------------------------------------------------------*/ +void *zrtp_aes_cfb128_start(zrtp_cipher_t *self, void *key, void *extra_data) +{ + zrtp_aes_cfb_ctx_t *cipher_ctx = zrtp_sys_alloc(sizeof(zrtp_aes_cfb_ctx_t)); + if(NULL == cipher_ctx) { + return NULL; + } + cipher_ctx->mode = ZRTP_CIPHER_MODE_CFB; + zrtp_bg_aes_encrypt_key128(((zrtp_v128_t*)key)->v8, cipher_ctx->aes_ctx); + + return cipher_ctx; +} + + +void *zrtp_aes_ctr128_start( zrtp_cipher_t *self, void *key, void *extra_data) +{ + zrtp_aes_ctr_ctx_t *cipher_ctx = zrtp_sys_alloc(sizeof(zrtp_aes_ctr_ctx_t)); + if(NULL == cipher_ctx) { + return NULL; + } + + cipher_ctx->mode = ZRTP_CIPHER_MODE_CTR; + zrtp_memcpy(&cipher_ctx->salt, extra_data, sizeof(zrtp_v128_t)-2); + cipher_ctx->salt.v8[14] = cipher_ctx->salt.v8[15] =0; + + zrtp_memset(&cipher_ctx->counter, 0, sizeof(zrtp_v128_t)); + zrtp_bg_aes_encrypt_key128(((zrtp_v128_t*)key)->v8, cipher_ctx->aes_ctx); + + return cipher_ctx; +} + +void *zrtp_aes128_start( zrtp_cipher_t *self, void *key, void *extra_data, uint8_t mode) +{ + void *ctx; + switch (mode) { + case ZRTP_CIPHER_MODE_CTR: + ctx = zrtp_aes_ctr128_start(self, key, extra_data); + break; + case ZRTP_CIPHER_MODE_CFB: + ctx = zrtp_aes_cfb128_start(self, key, extra_data); + break; + default: + ctx = NULL; + break; + }; + return ctx; +} + +/*---------------------------------------------------------------------------*/ +/* Global CFB Test-Vectors */ +static uint8_t aes_cfb_test_key[32] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f +}; + +static uint8_t aes_cfb_test_iv[16] = { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff +}; + +static uint8_t aes_cfb_test_buf1a[50] = { + 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, + 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a +}; + +static uint8_t aes_cfb_test_buf1b[50]; +//static uint8_t aes_cfb_test_buf1c[50]; + +static uint8_t aes_cfb_test_buf2a[50] = { + 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, + 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89 +}; + +static uint8_t aes_cfb_test_buf2b[50]; + +static uint8_t aes_cfb_test_key3[32]; +static uint8_t aes_cfb_test_iv3[16]; +static uint8_t aes_cfb_test_buf3a[50]; + +static uint8_t aes_cfb_test_buf3b[50] = { + 0x66, 0xe9, 0x4b, 0xd4, 0xef, 0x8a, 0x2c, 0x3b, + 0x88, 0x4c, 0xfa, 0x59, 0xca, 0x34, 0x2b, 0x2e, + 0xf7, 0x95, 0xbd, 0x4a, 0x52, 0xe2, 0x9e, 0xd7, + 0x13, 0xd3, 0x13, 0xfa, 0x20, 0xe9, 0x8d, 0xbc, + 0xa1, 0x0c, 0xf6, 0x6d, 0x0f, 0xdd, 0xf3, 0x40, + 0x53, 0x70, 0xb4, 0xbf, 0x8d, 0xf5, 0xbf, 0xb3, + 0x47, 0xc7 +}; + +uint8_t aes_cfb_test_buf3c[50] = { + 0xdc, 0x95, 0xc0, 0x78, 0xa2, 0x40, 0x89, 0x89, + 0xad, 0x48, 0xa2, 0x14, 0x92, 0x84, 0x20, 0x87, + 0x08, 0xc3, 0x74, 0x84, 0x8c, 0x22, 0x82, 0x33, + 0xc2, 0xb3, 0x4f, 0x33, 0x2b, 0xd2, 0xe9, 0xd3, + 0x8b, 0x70, 0xc5, 0x15, 0xa6, 0x66, 0x3d, 0x38, + 0xcd, 0xb8, 0xe6, 0x53, 0x2b, 0x26, 0x64, 0x91, + 0x5d, 0x0d +}; + +/* Global CTR Test-Vectors */ +uint8_t aes_ctr_test_nonce[16] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* 258-bit AES CTR Test-Vectors */ +uint8_t aes_ctr_test_key256[48] = { + 0x00, 0x01, 0x02, 0x03, 0x05, 0x06, 0x07, 0x08, + 0x0A, 0x0B, 0x0C, 0x0D, 0x0F, 0x10, 0x11, 0x12, + 0x14, 0x15, 0x16, 0x17, 0x19, 0x1A, 0x1B, 0x1C, + 0x1E, 0x1F, 0x20, 0x21, 0x23, 0x24, 0x25, 0x26, + 0x83, 0x4E, 0xAD, 0xFC, 0xCA, 0xC7, 0xE1, 0xB3, + 0x06, 0x64, 0xB1, 0xAB, 0xA4, 0x48, 0x15, 0xAB +}; + +uint8_t aes_ctr_test_plaintext256[16] = { + 0x83, 0x4E, 0xAD, 0xFC, 0xCA, 0xC7, 0xE1, 0xB3, + 0x06, 0x64, 0xB1, 0xAB, 0xA4, 0x48, 0x15, 0xAB +}; + +uint8_t aes_ctr_test_ciphertext256[16] = { + 0x5d, 0x8e, 0xfd, 0xe6, 0x69, 0x62, 0xbf, 0x49, + 0xda, 0xe2, 0xea, 0xcf, 0x0b, 0x69, 0xe4, 0xf6 +}; + +/* 128-bit AES CFB Test-Vectors */ +uint8_t aes_ctr_test_key128[32] = { +0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, +0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, +0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, +0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0x00, 0x00 +}; + +uint8_t aes_ctr_test_plaintext128[32] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +uint8_t aes_ctr_test_ciphertext128[32] = { +0xe0, 0x3e, 0xad, 0x09, 0x35, 0xc9, 0x5e, 0x80, +0xe1, 0x66, 0xb1, 0x6d, 0xd9, 0x2b, 0x4e, 0xb4, +0xd2, 0x35, 0x13, 0x16, 0x2b, 0x02, 0xd0, 0xf7, +0x2a, 0x43, 0xa2, 0xfe, 0x4a, 0x5f, 0x97, 0xab +}; + + +zrtp_status_t zrtp_aes_cfb128_self_test(zrtp_cipher_t *self) +{ + + zrtp_status_t err = zrtp_status_fail; + int i = 0; + zrtp_v128_t tmp_iv; + zrtp_aes_cfb_ctx_t *ctx = (zrtp_aes_cfb_ctx_t*)self->start( self, + aes_cfb_test_key, + NULL, + ZRTP_CIPHER_MODE_CFB); + if(NULL == ctx) { + return zrtp_status_fail; + } + + ZRTP_LOG(3, (_ZTU_,"128 bit AES CFB\n")); + ZRTP_LOG(3, (_ZTU_,"1st test...\n")); + + zrtp_memcpy(aes_cfb_test_buf1b, aes_cfb_test_buf1a, sizeof(aes_cfb_test_buf1a)); + zrtp_memcpy(&tmp_iv, aes_cfb_test_iv, sizeof(aes_cfb_test_iv)); + self->set_iv(self, ctx, &tmp_iv); + + ZRTP_LOG(3, (_ZTU_,"\tencryption... ")); + + err = self->encrypt(self, ctx, aes_cfb_test_buf1b, sizeof(aes_cfb_test_buf1b)); + if (zrtp_status_ok != err) { + ZRTP_LOGC(1, ("ERROR! 128-bit AES CFB encrypt returns error %d\n", err)); + self->stop(self, ctx); + return err; + } + + for (i=0; i<16; i++) { + if (aes_cfb_test_buf1b[i] != 0x00) { + ZRTP_LOGC(1, ("ERROR! 128-bit AES CFB failed on encrypt test")); + self->stop(self, ctx); + return zrtp_status_fail; + } + } + ZRTP_LOGC(3, ("OK\n")); + + ZRTP_LOG(3, (_ZTU_,"\tdecryption... ")); + + zrtp_memcpy(&tmp_iv, aes_cfb_test_iv, sizeof(aes_cfb_test_iv)); + + self->set_iv(self, ctx, &tmp_iv); + err = self->decrypt(self, ctx, aes_cfb_test_buf1b, sizeof(aes_cfb_test_buf1b)); + if (zrtp_status_ok != err) { + ZRTP_LOGC(3, ("ERROR! 128-bit AES CFB decrypt returns error %d\n", err)); + self->stop(self, ctx); + return err; + } + + for (i=0; istop(self, ctx); + return zrtp_status_fail; + } + } + self->stop(self, ctx); + ZRTP_LOGC(3, ("OK\n")); + + ZRTP_LOG(3, (_ZTU_, "2nd test...\n")); + + ctx = self->start(self, aes_cfb_test_key3, NULL, ZRTP_CIPHER_MODE_CFB); + if (NULL == ctx) { + return zrtp_status_fail; + } + + ZRTP_LOG(3, (_ZTU_, "\tencryption... ")); + + zrtp_memcpy(&tmp_iv, aes_cfb_test_iv3, sizeof(tmp_iv)); + self->set_iv(self, ctx, &tmp_iv); + + err = self->encrypt(self, ctx, aes_cfb_test_buf3a, sizeof(aes_cfb_test_buf3a)); + if (zrtp_status_ok != err) { + ZRTP_LOGC(1, ("ERROR! 128-bit AES CFB encrypt returns error %d\n", err)); + self->stop(self, ctx); + return err; + } + + for (i=0; istop(self, ctx); + return zrtp_status_fail; + } + } + ZRTP_LOGC(3, ("OK\n")); + + ZRTP_LOG(3, (_ZTU_, "\tdecryption... ")); + zrtp_memcpy(&tmp_iv, aes_cfb_test_iv3, sizeof(tmp_iv)); + self->set_iv(self, ctx, &tmp_iv); + + err = self->decrypt(self, ctx, aes_cfb_test_buf3b, sizeof(aes_cfb_test_buf3b)); + if (zrtp_status_ok != err) { + ZRTP_LOGC(1, ("ERROR! 128-bit AES CFB decrypt returns error %d\n", err)); + self->stop(self, ctx); + return err; + } + + for (i=0; istop(self, ctx); + return zrtp_status_fail; + } + } + ZRTP_LOGC(3, ("OK\n")); + + self->stop(self, ctx); + return zrtp_status_ok; +} + +zrtp_status_t zrtp_aes_ctr128_self_test(zrtp_cipher_t *self) +{ + uint8_t tmp_buf[32]; + zrtp_status_t err = zrtp_status_fail; + int i; + + zrtp_aes_ctr_ctx_t *ctx = (zrtp_aes_ctr_ctx_t*)self->start( self, + aes_ctr_test_key128, + aes_ctr_test_key128+16, + ZRTP_CIPHER_MODE_CTR); + + if (NULL == ctx) { + return zrtp_status_fail; + } + + ZRTP_LOG(3, (_ZTU_,"128 bit AES CTR\n")); + ZRTP_LOG(3, (_ZTU_, "1st test...\n")); + + ZRTP_LOG(3, (_ZTU_, "\tencryption... ")); + + self->set_iv(self, ctx, (zrtp_v128_t*)aes_ctr_test_nonce); + + zrtp_memcpy(tmp_buf, aes_ctr_test_plaintext128, sizeof(tmp_buf)); + err = self->encrypt(self, ctx, tmp_buf, sizeof(tmp_buf)); + if (zrtp_status_ok != err) { + ZRTP_LOGC(1, ("ERROR! 128-bit encrypt returns error %d\n", err)); + self->stop(self, ctx); + return zrtp_status_fail; + } + + for (i=0; istop(self, ctx); + return err; + } + } + ZRTP_LOGC(3, ("OK\n")); + + ZRTP_LOG(3, (_ZTU_, "\tdecryption...")); + + self->set_iv(self, ctx, (zrtp_v128_t*)aes_ctr_test_nonce); + + err = self->decrypt(self, ctx, tmp_buf, sizeof(tmp_buf)); + if (zrtp_status_ok != err) { + ZRTP_LOGC(1, ("ERROR! 128-bit AES CTR decrypt returns error %d\n", err)); + self->stop(self, ctx); + return err; + } + + for (i=0; istop(self, ctx); + return zrtp_status_fail; + } + } + self->stop(self, ctx); + ZRTP_LOGC(3, ("OK\n")); + + return zrtp_status_ok; +} + +zrtp_status_t zrtp_aes128_self_test(zrtp_cipher_t *self, uint8_t mode) +{ + zrtp_status_t res; + switch(mode){ + case ZRTP_CIPHER_MODE_CTR: + res = zrtp_aes_ctr128_self_test(self); + break; + case ZRTP_CIPHER_MODE_CFB: + res = zrtp_aes_cfb128_self_test(self); + break; + default: + res = zrtp_status_bad_param; + break; + } + return res; +} + +/*===========================================================================*/ +/* AES 256 implementation */ +/*===========================================================================*/ + +/*---------------------------------------------------------------------------*/ +void *zrtp_aes_cfb256_start(zrtp_cipher_t *self, void *key, void *extra_data) +{ + zrtp_aes_cfb_ctx_t *cipher_ctx = zrtp_sys_alloc(sizeof(zrtp_aes_cfb_ctx_t)); + if(NULL == cipher_ctx) { + return NULL; + } + + cipher_ctx->mode = ZRTP_CIPHER_MODE_CFB; + zrtp_bg_aes_encrypt_key256(((zrtp_v256_t*)key)->v8, cipher_ctx->aes_ctx); + return cipher_ctx; +} + +void *zrtp_aes_ctr256_start(zrtp_cipher_t *self, void *key, void *extra_data) +{ + zrtp_aes_ctr_ctx_t *cipher_ctx = zrtp_sys_alloc(sizeof(zrtp_aes_ctr_ctx_t)); + if(NULL == cipher_ctx) { + return NULL; + } + + cipher_ctx->mode = ZRTP_CIPHER_MODE_CTR; + zrtp_memcpy(&cipher_ctx->salt, extra_data, sizeof(zrtp_v128_t)-2); + cipher_ctx->salt.v8[14] = cipher_ctx->salt.v8[15] =0; + + zrtp_memset(&cipher_ctx->counter, 0, sizeof(zrtp_v128_t)); + + zrtp_bg_aes_encrypt_key256(((zrtp_v256_t*)key)->v8, cipher_ctx->aes_ctx); + + return cipher_ctx; +} + +void *zrtp_aes256_start(zrtp_cipher_t *self, void *key, void *extra_data, uint8_t mode) +{ + void *ctx = NULL; + switch (mode) { + case ZRTP_CIPHER_MODE_CTR: + ctx = zrtp_aes_ctr256_start(self, key, extra_data); + break; + case ZRTP_CIPHER_MODE_CFB: + ctx = zrtp_aes_cfb256_start(self, key, extra_data); + break; + default: + ctx = NULL; + break; + } + return ctx; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t zrtp_aes_cfb256_self_test(zrtp_cipher_t *self) +{ + zrtp_status_t err; + int i; + zrtp_v128_t tmp_iv; + + zrtp_aes_cfb_ctx_t *ctx = (zrtp_aes_cfb_ctx_t*)self->start( self, + aes_cfb_test_key, + NULL, + ZRTP_CIPHER_MODE_CFB); + if (NULL == ctx) { + return zrtp_status_fail; + } + + ZRTP_LOG(3, (_ZTU_,"256 bit AES CFB\n")); + ZRTP_LOG(3, (_ZTU_, "1st test...\n")); + + zrtp_memcpy(aes_cfb_test_buf2b, aes_cfb_test_buf2a, sizeof(aes_cfb_test_buf2a)); + zrtp_memcpy(&tmp_iv, aes_cfb_test_iv, sizeof(tmp_iv)); + + ZRTP_LOG(3, (_ZTU_, "\tencryption... ")); + + self->set_iv(self, ctx, &tmp_iv); + err = self->encrypt(self, ctx, aes_cfb_test_buf2b, sizeof(aes_cfb_test_buf2b)); + if (zrtp_status_ok != err) { + ZRTP_LOGC(1, ("ERROR! 256-bit AES CFB encrypt returns error %d\n", err)); + self->stop(self, ctx); + return err; + } + + for (i=0; i<16; i++) { + if (aes_cfb_test_buf2b[i] != 0x00) { + ZRTP_LOGC(1, ("ERROR! 256-bit AES CFB failed on encrypt test\n")); + self->stop(self, ctx); + return zrtp_status_fail; + } + } + ZRTP_LOGC(3, ("OK\n")); + + ZRTP_LOG(3, (_ZTU_, "\tdecryption... ")); + + zrtp_memcpy(&tmp_iv, aes_cfb_test_iv, sizeof(tmp_iv)); + self->set_iv(self, ctx, &tmp_iv); + + err = self->decrypt(self, ctx, aes_cfb_test_buf2b, sizeof(aes_cfb_test_buf2b)); + if (zrtp_status_ok != err) { + ZRTP_LOGC(1, ("ERROR! 256-bit AES CFB decrypt returns error %d\n", err)); + self->stop(self, ctx); + return err; + } + for (i=0; istop(self, ctx); + return zrtp_status_fail; + } + } + self->stop(self, ctx); + ZRTP_LOGC(3, ("OK\n")); + + ZRTP_LOG(3, (_ZTU_, "2nd test...\n")); + + ctx = self->start(self, aes_cfb_test_key3, NULL, ZRTP_CIPHER_MODE_CFB); + if(NULL == ctx){ + return zrtp_status_fail; + } + + ZRTP_LOG(3, (_ZTU_, "\tencryption...")); + + zrtp_memset (aes_cfb_test_buf3a, 0, sizeof(aes_cfb_test_buf3a)); + zrtp_memcpy(&tmp_iv, aes_cfb_test_iv3, sizeof(tmp_iv)); + + self->set_iv(self, ctx, &tmp_iv); + err = self->encrypt(self, ctx, aes_cfb_test_buf3a, sizeof(aes_cfb_test_buf3a)); + if (zrtp_status_ok != err) { + ZRTP_LOGC(1, ("ERROR! 256-bit AES CFB encrypt returns error %d\n", err)); + self->stop(self, ctx); + return err; + } + + for (i=0; istop(self, ctx); + return zrtp_status_fail; + } + } + ZRTP_LOGC(3, ("OK\n")); + + ZRTP_LOG(3, (_ZTU_, "\tdecryption...")); + + zrtp_memcpy(&tmp_iv, aes_cfb_test_iv3, sizeof(tmp_iv)); + self->set_iv(self, ctx, &tmp_iv); + + err = self->decrypt(self, ctx, aes_cfb_test_buf3c, sizeof(aes_cfb_test_buf3c)); + if (zrtp_status_ok != err) { + ZRTP_LOGC(1, ("ERROR! 256-bit AES CFB decrypt returns error %d\n", err)); + self->stop(self, ctx); + return err; + } + + for (i=0; istop(self, ctx); + return zrtp_status_fail; + } + } + self->stop(self, ctx); + ZRTP_LOGC(3, ("OK\n")); + + return zrtp_status_ok; +} + +zrtp_status_t zrtp_aes_ctr256_self_test(zrtp_cipher_t *self) +{ + uint8_t tmp_buf[32]; + zrtp_status_t err = zrtp_status_fail; + int i; + + zrtp_aes_ctr_ctx_t *ctx = (zrtp_aes_ctr_ctx_t*)self->start( self, + aes_ctr_test_key256, + aes_ctr_test_key256+32, + ZRTP_CIPHER_MODE_CTR); + if (NULL == ctx) { + return zrtp_status_fail; + } + + ZRTP_LOG(3, (_ZTU_,"256 bit AES CTR\n")); + ZRTP_LOG(3, (_ZTU_, "1st test...\n")); + + ZRTP_LOG(3, (_ZTU_, "\tencryption... ")); + + self->set_iv(self, ctx, (zrtp_v128_t*)aes_ctr_test_nonce); + + zrtp_memcpy(tmp_buf, aes_ctr_test_plaintext256, sizeof(aes_ctr_test_plaintext256)); + err = self->encrypt(self, ctx, tmp_buf, sizeof(aes_ctr_test_plaintext256)); + if (zrtp_status_ok != err) { + ZRTP_LOGC(1, ("ERROR! 256-bit encrypt returns error %d\n", err)); + self->stop(self, ctx); + return zrtp_status_fail; + } + + for (i=0; istop(self, ctx); + return err; + } + } + + ZRTP_LOGC(3, ("OK\n")); + + ZRTP_LOG(3, (_ZTU_, "\tdecryption...")); + + self->set_iv(self, ctx, (zrtp_v128_t*)aes_ctr_test_nonce); + + err = self->decrypt(self, ctx, tmp_buf, sizeof(tmp_buf)); + if (zrtp_status_ok != err) { + ZRTP_LOGC(1, ("ERROR! 256-bit AES CTR decrypt returns error %d\n", err)); + self->stop(self, ctx); + return err; + } + + for (i=0; istop(self, ctx); + return zrtp_status_fail; + } + } + self->stop(self, ctx); + ZRTP_LOGC(3, ("OK\n")); + + return zrtp_status_ok; +} + +zrtp_status_t zrtp_aes256_self_test(zrtp_cipher_t *self, uint8_t mode) +{ + zrtp_status_t res; + switch (mode) { + case ZRTP_CIPHER_MODE_CTR: + res = zrtp_aes_ctr256_self_test(self); + break; + case ZRTP_CIPHER_MODE_CFB: + res = zrtp_aes_cfb256_self_test(self); + break; + default: + res = zrtp_status_bad_param; + break; + } + return res; +} + + +/*---------------------------------------------------------------------------*/ +zrtp_status_t zrtp_defaults_aes_cipher(zrtp_global_t* global_ctx) +{ + zrtp_cipher_t* cipher_aes128 = zrtp_sys_alloc(sizeof(zrtp_cipher_t)); + zrtp_cipher_t* cipher_aes256 = zrtp_sys_alloc(sizeof(zrtp_cipher_t)); + if (!cipher_aes128 || !cipher_aes256) { + if (cipher_aes128) { + zrtp_sys_free(cipher_aes128); + } + if (cipher_aes256) { + zrtp_sys_free(cipher_aes256); + } + return zrtp_status_alloc_fail; + } + + zrtp_memset(cipher_aes128, 0, sizeof(zrtp_cipher_t)); + zrtp_memset(cipher_aes256, 0, sizeof(zrtp_cipher_t)); + + zrtp_memcpy(cipher_aes128->base.type, ZRTP_AES1, ZRTP_COMP_TYPE_SIZE); + cipher_aes128->base.id = ZRTP_CIPHER_AES128; + cipher_aes128->base.zrtp = global_ctx; + cipher_aes128->start = zrtp_aes128_start; + cipher_aes128->set_iv = zrtp_aes_set_iv; + cipher_aes128->encrypt = zrtp_aes_encrypt; + cipher_aes128->decrypt = zrtp_aes_decrypt; + cipher_aes128->self_test = zrtp_aes128_self_test; + cipher_aes128->stop = zrtp_aes_stop; + + zrtp_memcpy(cipher_aes256->base.type, ZRTP_AES3, ZRTP_COMP_TYPE_SIZE); + cipher_aes256->base.id = ZRTP_CIPHER_AES256; + cipher_aes256->base.zrtp = global_ctx; + cipher_aes256->start = zrtp_aes256_start; + cipher_aes256->set_iv = zrtp_aes_set_iv; + cipher_aes256->encrypt = zrtp_aes_encrypt; + cipher_aes256->decrypt = zrtp_aes_decrypt; + cipher_aes256->self_test = zrtp_aes256_self_test; + cipher_aes256->stop = zrtp_aes_stop; + + zrtp_comp_register(ZRTP_CC_CIPHER, cipher_aes128, global_ctx); + zrtp_comp_register(ZRTP_CC_CIPHER, cipher_aes256, global_ctx); + + return zrtp_status_ok; +} diff --git a/src/zrtp_crypto_atl.c b/src/zrtp_crypto_atl.c new file mode 100644 index 0000000000..790a11006f --- /dev/null +++ b/src/zrtp_crypto_atl.c @@ -0,0 +1,44 @@ +/* + * 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 + */ + +#include "zrtp.h" + + +/*============================================================================*/ +/* SRTP Auth Tag Length support */ +/*============================================================================*/ + +zrtp_status_t zrtp_defaults_atl(zrtp_global_t* global_ctx) +{ + zrtp_auth_tag_length_t* atl32 = zrtp_sys_alloc(sizeof(zrtp_auth_tag_length_t)); + zrtp_auth_tag_length_t* atl80 = zrtp_sys_alloc(sizeof(zrtp_auth_tag_length_t)); + + if (!atl32 || !atl80) { + if(atl32) zrtp_sys_free(atl32); + if(atl80) zrtp_sys_free(atl80); + return zrtp_status_alloc_fail; + } + + zrtp_memset(atl32, 0, sizeof(zrtp_auth_tag_length_t)); + zrtp_memcpy(atl32->base.type, ZRTP_HS32, ZRTP_COMP_TYPE_SIZE); + atl32->base.id = ZRTP_ATL_HS32; + atl32->base.zrtp = global_ctx; + atl32->tag_length = 4; + + zrtp_memset(atl80, 0, sizeof(zrtp_auth_tag_length_t)); + zrtp_memcpy(atl80->base.type, ZRTP_HS80, ZRTP_COMP_TYPE_SIZE); + atl80->base.id = ZRTP_ATL_HS80; + atl80->base.zrtp = global_ctx; + atl80->tag_length = 10; + + zrtp_comp_register(ZRTP_CC_ATL, atl32, global_ctx); + zrtp_comp_register(ZRTP_CC_ATL, atl80, global_ctx); + + return zrtp_status_ok; +} diff --git a/src/zrtp_crypto_hash.c b/src/zrtp_crypto_hash.c new file mode 100644 index 0000000000..0d6753e30f --- /dev/null +++ b/src/zrtp_crypto_hash.c @@ -0,0 +1,1638 @@ +/* + * 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 + * Vitaly Rozhkov + */ + +#include "sha2.h" +#include "sha1.h" + +#include "zrtp.h" + +#define _ZTU_ "zrtp hash" + + +/*============================================================================*/ +/* HASH function */ +/*============================================================================*/ + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t zrtp_sha_c(zrtp_hash_t *self, const char* msg, uint32_t len, zrtp_stringn_t *dst) +{ + if (!self || !msg || !dst || !len) { + return zrtp_status_bad_param; + } + + switch (self->base.id) + { + case ZRTP_SRTP_HASH_SHA1: { + sha1_ctx ctx; + if (dst->max_length < SHA1_DIGEST_SIZE) { + return zrtp_status_buffer_size; + } + sha1_begin(&ctx); + sha1_hash((const unsigned char*)msg, len, &ctx); + sha1_end((unsigned char*)dst->buffer, &ctx); + dst->length = SHA1_DIGEST_SIZE; + } break; + + case ZRTP_HASH_SHA256: { + sha256_ctx ctx; + if (dst->max_length < SHA256_DIGEST_SIZE) { + return zrtp_status_buffer_size; + } + sha256_begin(&ctx); + sha256_hash((const unsigned char*)msg, len, &ctx); + sha256_end((unsigned char*)dst->buffer, &ctx); + dst->length = SHA256_DIGEST_SIZE; + } break; + + case ZRTP_HASH_SHA384: { + sha384_ctx ctx; + if (dst->max_length < SHA384_DIGEST_SIZE) { + return zrtp_status_buffer_size; + } + sha384_begin(&ctx); + sha384_hash((const unsigned char*)msg, len, &ctx); + sha384_end((unsigned char*)dst->buffer, &ctx); + dst->length = SHA384_DIGEST_SIZE; + } break; + } + + return zrtp_status_ok; +} + +static zrtp_status_t zrtp_sha(zrtp_hash_t *self, const zrtp_stringn_t *msg, zrtp_stringn_t *dst) { + if (!self || !msg || !dst) { + return zrtp_status_bad_param; + } + return zrtp_sha_c(self, msg->buffer, msg->length, dst); +} + +/*----------------------------------------------------------------------------*/ +static void* zrtp_sha_begin(zrtp_hash_t *self) +{ + void *ctx = NULL; + + switch (self->base.id) { + case ZRTP_SRTP_HASH_SHA1: + ctx = zrtp_sys_alloc(sizeof(sha1_ctx)); + if (ctx) { + sha1_begin(ctx); + } + break; + case ZRTP_HASH_SHA256: + ctx = zrtp_sys_alloc(sizeof(sha256_ctx)); + if (ctx) { + sha256_begin(ctx); + } + break; + case ZRTP_HASH_SHA384: + ctx = zrtp_sys_alloc(sizeof(sha384_ctx)); + if (ctx) { + sha384_begin(ctx); + } + break; + } + + return ctx; +} + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t zrtp_sha_update( zrtp_hash_t *self, + void *ctx, + const int8_t *msg, + uint32_t length) +{ + if (!ctx || !msg || !length) { + return zrtp_status_bad_param; + } + + switch (self->base.id) { + case ZRTP_SRTP_HASH_SHA1: + sha1_hash((const unsigned char*)msg, length, (sha1_ctx*)ctx); + break; + case ZRTP_HASH_SHA256: + sha256_hash((const unsigned char*)msg, length, (sha256_ctx*)ctx); + break; + case ZRTP_HASH_SHA384: + sha384_hash((const unsigned char*)msg, length, (sha384_ctx*)ctx); + break; + } + + return zrtp_status_ok; +} + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t zrtp_sha_end( zrtp_hash_t *self, + void *ctx, + zrtp_stringn_t *digest) +{ + if (!ctx || !digest) { + return zrtp_status_bad_param; + } + + switch (self->base.id) { + case ZRTP_SRTP_HASH_SHA1: + if (digest->max_length < SHA1_DIGEST_SIZE) { + return zrtp_status_buffer_size; + } + sha1_end((unsigned char*)digest->buffer,(sha1_ctx*)ctx); + digest->length = SHA1_DIGEST_SIZE; + break; + case ZRTP_HASH_SHA256: + if (digest->max_length < SHA256_DIGEST_SIZE) { + return zrtp_status_buffer_size; + } + sha256_end((unsigned char*)digest->buffer,(sha256_ctx*)ctx); + digest->length = SHA256_DIGEST_SIZE; + break; + case ZRTP_HASH_SHA384: + if (digest->max_length < SHA384_DIGEST_SIZE) { + return zrtp_status_buffer_size; + } + sha384_end((unsigned char*)digest->buffer,(sha384_ctx*)ctx); + digest->length = SHA384_DIGEST_SIZE; + break; + } + + zrtp_sys_free(ctx); + ctx = 0; + + return zrtp_status_ok; +} + + +/*============================================================================*/ +/* HMAC functions */ +/*============================================================================*/ + +typedef struct +{ + sha384_ctx context; + unsigned char k_ipad[128]; /* inner padding - key XORd with ipad */ + unsigned char k_opad[128]; /* outer padding - key XORd with opad */ +} hmac_sha384_context_t; + + +typedef struct +{ + sha256_ctx context; + unsigned char k_ipad[64]; + unsigned char k_opad[64]; +} hmac_sha256_context_t; + +typedef struct +{ + sha1_ctx context; + unsigned char k_ipad[64]; + unsigned char k_opad[64]; +} hmac_sha1_context_t; + + +/*----------------------------------------------------------------------------*/ +static void* zrtp_hmac_sha256_begin_c(zrtp_hash_t *self, const char *key, uint32_t length) +{ + const char *p_key; + uint32_t key_length; + char local_key[SHA256_BLOCK_SIZE]; + int i = 0; + hmac_sha256_context_t *ctx = zrtp_sys_alloc(sizeof(hmac_sha256_context_t)); + if (!ctx) { + return NULL; + } + zrtp_memset(ctx, 0, sizeof(hmac_sha256_context_t)); + + if (length > SHA256_BLOCK_SIZE) { + sha256_begin(&ctx->context); + sha256_hash((const unsigned char*)key, length, &ctx->context); + sha256_end((unsigned char*)local_key, &ctx->context); + + p_key = local_key; + key_length = SHA256_BLOCK_SIZE; + } else { + p_key = key; + key_length = length; + } + + /* + * the HMAC transform looks like: + * + * HASH(K XOR opad, HASH(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected + */ + + /* start out by storing key in pads */ + zrtp_memcpy(ctx->k_ipad, p_key, ZRTP_MIN(key_length, 64)); + zrtp_memcpy(ctx->k_opad, p_key, ZRTP_MIN(key_length, 64)); + + /* XOR key with ipad and opad values */ + for (i=0; i<64; i++) { + ctx->k_ipad[i] ^= (uint8_t)0x36; + ctx->k_opad[i] ^= (uint8_t)0x5c; + } + + /* perform inner hash */ + sha256_begin(&ctx->context); /* init context for 1st pass */ + sha256_hash(ctx->k_ipad, 64, &ctx->context); /* start with inner pad */ + + zrtp_memset(&local_key, 0, sizeof(local_key)); + return ctx; +} +static void* zrtp_hmac_sha384_begin_c(zrtp_hash_t *self, const char *key, uint32_t length) +{ + const char *p_key; + uint32_t key_length; + char local_key[SHA384_BLOCK_SIZE]; + int i = 0; + hmac_sha384_context_t *ctx = zrtp_sys_alloc(sizeof(hmac_sha384_context_t)); + if (!ctx) { + return NULL; + } + zrtp_memset(ctx, 0, sizeof(hmac_sha384_context_t)); + + if (length > SHA384_BLOCK_SIZE) { + sha384_begin(&ctx->context); + sha384_hash((const unsigned char*)key, length, &ctx->context); + sha384_end((unsigned char*)local_key, &ctx->context); + + p_key = local_key; + key_length = SHA384_BLOCK_SIZE; + } else { + p_key = key; + key_length = length; + } + + zrtp_memcpy(ctx->k_ipad, p_key, ZRTP_MIN(key_length, 128)); + zrtp_memcpy(ctx->k_opad, p_key, ZRTP_MIN(key_length, 128)); + + for (i=0; i<128; i++) { + ctx->k_ipad[i] ^= (uint8_t)0x36; + ctx->k_opad[i] ^= (uint8_t)0x5c; + } + + sha384_begin(&ctx->context); + sha384_hash(ctx->k_ipad, 128, &ctx->context); + + zrtp_memset(&local_key, 0, sizeof(local_key)); + return ctx; +} + +static void* zrtp_hmac_sha1_begin_c( zrtp_hash_t *self, + const char *key, + uint32_t length) +{ + const char *p_key; + uint32_t key_length; + char local_key[SHA1_BLOCK_SIZE]; + int i = 0; + hmac_sha1_context_t *ctx = zrtp_sys_alloc(sizeof(hmac_sha1_context_t)); + if (!ctx) { + return NULL; + } + zrtp_memset(ctx, 0, sizeof(hmac_sha1_context_t)); + + if (length > SHA1_BLOCK_SIZE) { + sha1_begin(&ctx->context); + sha1_hash((const unsigned char*)key, length, &ctx->context); + sha1_end((unsigned char*)local_key, &ctx->context); + + p_key = local_key; + key_length = SHA1_BLOCK_SIZE; + } else { + p_key = key; + key_length = length; + } + + zrtp_memcpy(ctx->k_ipad, p_key, ZRTP_MIN(key_length, 64)); + zrtp_memcpy(ctx->k_opad, p_key, ZRTP_MIN(key_length, 64)); + + for (i=0; i<64; i++) { + ctx->k_ipad[i] ^= (uint8_t)0x36; + ctx->k_opad[i] ^= (uint8_t)0x5c; + } + + sha1_begin(&ctx->context); + sha1_hash(ctx->k_ipad, 64, &ctx->context); + + zrtp_memset(&local_key, 0, sizeof(local_key)); + return ctx; +} + +static void* zrtp_hmac_begin(zrtp_hash_t *self, const zrtp_stringn_t *key) { + switch (self->base.id) + { + case ZRTP_SRTP_HASH_SHA1: + return zrtp_hmac_sha1_begin_c(self, key->buffer, key->length); + case ZRTP_HASH_SHA256: + return zrtp_hmac_sha256_begin_c(self, key->buffer, key->length); + case ZRTP_HASH_SHA384: + return zrtp_hmac_sha384_begin_c(self, key->buffer, key->length); + default: + return NULL; + } +} + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t zrtp_hmac_update(zrtp_hash_t *self, void *ctx, const char *msg, uint32_t length) +{ + if (!ctx || !msg) { + return zrtp_status_fail; + } + + if (0 != length) { + switch (self->base.id) { + case ZRTP_SRTP_HASH_SHA1: + sha1_hash((const unsigned char*)msg, length, &((hmac_sha1_context_t*)ctx)->context); + break; + case ZRTP_HASH_SHA256: + sha256_hash((const unsigned char*)msg, length, &((hmac_sha256_context_t*)ctx)->context); + break; + case ZRTP_HASH_SHA384: + sha384_hash((const unsigned char*)msg, length, &((hmac_sha384_context_t*)ctx)->context); + break; + default: + return zrtp_status_bad_param; + } + } + + return zrtp_status_ok; +} + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t zrtp_hmac_end( zrtp_hash_t *self, + void *ctx, + zrtp_stringn_t *digest, + uint32_t len) +{ + zrtp_string128_t dst = ZSTR_INIT_EMPTY(dst); + + if (!ctx || !digest) { + return zrtp_status_fail; + } + + switch (self->base.id) + { + case ZRTP_SRTP_HASH_SHA1: + /* finish up 1st pass */ + sha1_end((unsigned char*)dst.buffer, &((hmac_sha1_context_t*)ctx)->context); + + /* perform outer hash and init context for 2nd pass */ + sha1_begin(&((hmac_sha1_context_t*)ctx)->context); + /* start with outer pad */ + sha1_hash(((hmac_sha1_context_t*)ctx)->k_opad, 64, &((hmac_sha1_context_t*)ctx)->context); + /* then results of 1st hash */ + sha1_hash((const unsigned char*)dst.buffer, SHA1_DIGEST_SIZE, &((hmac_sha1_context_t*)ctx)->context); + /* finish up 2nd pass */ + sha1_end((unsigned char*)dst.buffer, &((hmac_sha1_context_t*)ctx)->context); + + len = (0 == len) ? SHA1_DIGEST_SIZE : ZRTP_MIN(len, SHA1_DIGEST_SIZE); + break; + case ZRTP_HASH_SHA256: + sha256_end((unsigned char*)dst.buffer, &((hmac_sha256_context_t*)ctx)->context); + sha256_begin(&((hmac_sha256_context_t*)ctx)->context); + sha256_hash(((hmac_sha256_context_t*)ctx)->k_opad, 64, &((hmac_sha256_context_t*)ctx)->context); + sha256_hash((const unsigned char*)dst.buffer, SHA256_DIGEST_SIZE, &((hmac_sha256_context_t*)ctx)->context); + sha256_end((unsigned char*)dst.buffer, &((hmac_sha256_context_t*)ctx)->context); + + len = (0 == len) ? SHA256_DIGEST_SIZE : ZRTP_MIN(len, SHA256_DIGEST_SIZE); + break; + case ZRTP_HASH_SHA384: + sha384_end((unsigned char*)dst.buffer, &((hmac_sha384_context_t*)ctx)->context); + sha384_begin(&((hmac_sha384_context_t*)ctx)->context); + sha384_hash(((hmac_sha384_context_t*)ctx)->k_opad, 128, &((hmac_sha384_context_t*)ctx)->context); + sha384_hash((const unsigned char*)dst.buffer, SHA384_DIGEST_SIZE, &((hmac_sha384_context_t*)ctx)->context); + sha384_end((unsigned char*)dst.buffer, &((hmac_sha384_context_t*)ctx)->context); + + len = (0 == len) ? SHA384_DIGEST_SIZE : ZRTP_MIN(len, SHA384_DIGEST_SIZE); + break; + default: + return zrtp_status_bad_param; + } + + digest->length = ZRTP_MIN(len, digest->max_length); + zrtp_memcpy(digest->buffer, dst.buffer, digest->length); + + zrtp_sys_free(ctx); + + return zrtp_status_ok; +} + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t zrtp_hmac_c( zrtp_hash_t *self, + const char *key, + const uint32_t key_len, + const char *msg, + const uint32_t msg_len, + zrtp_stringn_t *digest) +{ + unsigned char *p_key; + uint32_t l_key_len; + sha1_ctx context1; + sha256_ctx context2; + sha384_ctx context3; + unsigned char k_ipad[128]; /* inner padding - key XORd with ipad */ + unsigned char k_opad[128]; /* outer padding - key XORd with opad */ + unsigned i; + unsigned char local_key[SHA384_BLOCK_SIZE]; + uint32_t local_key_len = 0; + + + if (!self || !digest || !key || !msg) { + return zrtp_status_buffer_size; + } + + switch (self->base.id) { + case ZRTP_SRTP_HASH_SHA1: + local_key_len = SHA1_BLOCK_SIZE; + break; + case ZRTP_HASH_SHA256: + local_key_len = SHA256_BLOCK_SIZE; + break; + case ZRTP_HASH_SHA384: + local_key_len = SHA384_BLOCK_SIZE; + break; + default: + return zrtp_status_bad_param; + } + + if (digest->max_length < local_key_len) { + return zrtp_status_buffer_size; + } + + if (key_len > local_key_len) { + switch (self->base.id) + { + case ZRTP_SRTP_HASH_SHA1: + sha1_begin(&context1); + sha1_hash((const unsigned char*)key, key_len, &context1); + sha1_end(local_key, &context1); + break; + case ZRTP_HASH_SHA256: + sha256_begin(&context2); + sha256_hash((const unsigned char*)key, key_len, &context2); + sha256_end(local_key, &context2); + break; + case ZRTP_HASH_SHA384: + sha384_begin(&context3); + sha384_hash((const unsigned char*)key, key_len, &context3); + sha384_end(local_key, &context3); + break; + } + + p_key = local_key; + l_key_len = local_key_len; + } else { + p_key = (unsigned char*)key; + l_key_len = key_len; + } + + /* + * the HMAC transform looks like: + * + * HASH(K XOR opad, HASH(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected + */ + + /* start out by storing key in pads */ + zrtp_memset(k_ipad, 0, sizeof(k_ipad)); + zrtp_memset(k_opad, 0, sizeof(k_opad)); + zrtp_memcpy(k_ipad, p_key, ZRTP_MIN(l_key_len, local_key_len)); + zrtp_memcpy(k_opad, p_key, ZRTP_MIN(l_key_len, local_key_len)); + + /* XOR key with ipad and opad values */ + for (i=0; ibase.id) { + case ZRTP_SRTP_HASH_SHA1: + /* perform inner hash */ + sha1_begin(&context1); /* init context for 1st pass */ + sha1_hash(k_ipad, local_key_len, &context1);/* start with inner pad */ + sha1_hash((const unsigned char*)msg, msg_len, &context1); /* then text of datagram */ + sha1_end((unsigned char*)digest->buffer, &context1); /* finish up 1st pass */ + + /* perform outer hash */ + sha1_begin(&context1); /* init context for 2nd pass */ + sha1_hash(k_opad, local_key_len, &context1);/* start with outer pad */ + sha1_hash((const unsigned char*)digest->buffer, SHA1_DIGEST_SIZE, &context1); /* then results of 1st hash */ + sha1_end((unsigned char*)digest->buffer, &context1); /* finish up 2nd pass */ + + digest->length = SHA1_DIGEST_SIZE; + break; + case ZRTP_HASH_SHA256: + sha256_begin(&context2); + sha256_hash(k_ipad, local_key_len, &context2); + sha256_hash((const unsigned char*)msg, msg_len, &context2); + sha256_end((unsigned char*)digest->buffer, &context2); + + sha256_begin(&context2); + sha256_hash(k_opad, local_key_len, &context2); + sha256_hash((const unsigned char*)digest->buffer, SHA256_DIGEST_SIZE, &context2); + sha256_end((unsigned char*)digest->buffer, &context2); + + digest->length = SHA256_DIGEST_SIZE; + break; + case ZRTP_HASH_SHA384: + sha384_begin(&context3); + sha384_hash(k_ipad, local_key_len, &context3); + sha384_hash((const unsigned char*)msg, msg_len, &context3); + sha384_end((unsigned char*)digest->buffer, &context3); + + sha384_begin(&context3); + sha384_hash(k_opad, local_key_len, &context3); + sha384_hash((const unsigned char*)digest->buffer, SHA384_DIGEST_SIZE, &context3); + sha384_end((unsigned char*)digest->buffer, &context3); + + digest->length = SHA384_DIGEST_SIZE; + break; + } + + return zrtp_status_ok; +} + +static zrtp_status_t zrtp_hmac( zrtp_hash_t *self, + const zrtp_stringn_t *key, + const zrtp_stringn_t *msg, + zrtp_stringn_t *digest) { + return zrtp_hmac_c(self, key->buffer, key->length, msg->buffer, msg->length, digest); +} + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t zrtp_hmac_truncated_c( zrtp_hash_t *self, + const char *key, + const uint32_t key_len, + const char *msg, + const uint32_t msg_len, + uint32_t necessary_len, + zrtp_stringn_t *digest) +{ + uint32_t necessary_len_max = 0; + switch (self->base.id) { + case ZRTP_SRTP_HASH_SHA1: + necessary_len_max = SHA1_DIGEST_SIZE; + break; + case ZRTP_HASH_SHA256: + necessary_len_max = SHA256_DIGEST_SIZE; + break; + case ZRTP_HASH_SHA384: + necessary_len_max = SHA384_DIGEST_SIZE; + break; + } + if (necessary_len > necessary_len_max) { + return zrtp_status_buffer_size; + } + + if (0 == necessary_len) { + zrtp_hmac_c(self, key, key_len, msg, msg_len, digest); + } else { + zrtp_string128_t dst = ZSTR_INIT_EMPTY(dst); + + zrtp_hmac_c(self, key, key_len, msg, msg_len, (zrtp_stringn_t *)&dst); + switch (self->base.id) { + case ZRTP_SRTP_HASH_SHA1: + necessary_len = ZRTP_MIN(necessary_len, SHA1_DIGEST_SIZE); + break; + case ZRTP_HASH_SHA256: + necessary_len = ZRTP_MIN(necessary_len, SHA256_DIGEST_SIZE); + break; + case ZRTP_HASH_SHA384: + necessary_len = ZRTP_MIN(necessary_len, SHA384_DIGEST_SIZE); + break; + } + digest->length = ZRTP_MIN(necessary_len, digest->max_length); + zrtp_memcpy(digest->buffer, dst.buffer, digest->length); + } + + return zrtp_status_ok; +} + +static zrtp_status_t zrtp_hmac_truncated( zrtp_hash_t *self, + const zrtp_stringn_t *key, + const zrtp_stringn_t *msg, + uint32_t len, + zrtp_stringn_t *digest) { + return zrtp_hmac_truncated_c(self, key->buffer, key->length, msg->buffer, msg->length, len, digest); + +} + + +/*============================================================================*/ +/* SHA and SHMAC test cases */ +/*============================================================================*/ + + +/* + * SHA1 Test Vectors + */ + +static uint8_t sha1_msg_8[1] = { + 0xa8 +}; + +static uint8_t sha1_MD_8[20] = { + 0x99, 0xf2, 0xaa, 0x95, 0xe3, 0x6f, 0x95, 0xc2, + 0xac, 0xb0, 0xea, 0xf2, 0x39, 0x98, 0xf0, 0x30, + 0x63, 0x8f, 0x3f, 0x15 +}; + +static uint8_t sha1_msg_128[16] = { + 0xc5, 0xa2, 0x2d, 0xd6, 0xed, 0xa3, 0xfe, 0x2b, + 0xdc, 0x4d, 0xdb, 0x3c, 0xe6, 0xb3, 0x5f, 0xd1 +}; + +static uint8_t sha1_MD_128[20] = { + 0xfa, 0xc8, 0xab, 0x93, 0xc1, 0xae, 0x6c, 0x16, + 0xf0, 0x31, 0x18, 0x72, 0xb9, 0x84, 0xf7, 0x29, + 0xdc, 0x92, 0x8c, 0xcd +}; + +static uint8_t sha1_msg_512[64] = { + 0x7e, 0x3a, 0x4c, 0x32, 0x5c, 0xb9, 0xc5, 0x2b, + 0x88, 0x38, 0x7f, 0x93, 0xd0, 0x1a, 0xe8, 0x6d, + 0x42, 0x09, 0x8f, 0x5e, 0xfa, 0x7f, 0x94, 0x57, + 0x38, 0x8b, 0x5e, 0x74, 0xb6, 0xd2, 0x8b, 0x24, + 0x38, 0xd4, 0x2d, 0x8b, 0x64, 0x70, 0x33, 0x24, + 0xd4, 0xaa, 0x25, 0xab, 0x6a, 0xad, 0x15, 0x3a, + 0xe3, 0x0c, 0xd2, 0xb2, 0xaf, 0x4d, 0x5e, 0x5c, + 0x00, 0xa8, 0xa2, 0xd0, 0x22, 0x0c, 0x61, 0x16 +}; + +static uint8_t sha1_MD_512[20] = { + 0xa3, 0x05, 0x44, 0x27, 0xcd, 0xb1, 0x3f, 0x16, + 0x4a, 0x61, 0x0b, 0x34, 0x87, 0x02, 0x72, 0x4c, + 0x80, 0x8a, 0x0d, 0xcc +}; + +static uint8_t sha1_msg_2096[262] = { + 0x5f, 0xc2, 0xc3, 0xf6, 0xa7, 0xe7, 0x9d, 0xc9, + 0x4b, 0xe5, 0x26, 0xe5, 0x16, 0x6a, 0x23, 0x88, + 0x99, 0xd5, 0x49, 0x27, 0xce, 0x47, 0x00, 0x18, + 0xfb, 0xfd, 0x66, 0x8f, 0xd9, 0xdd, 0x97, 0xcb, + 0xf6, 0x4e, 0x2c, 0x91, 0x58, 0x4d, 0x01, 0xda, + 0x63, 0xbe, 0x3c, 0xc9, 0xfd, 0xff, 0x8a, 0xdf, + 0xef, 0xc3, 0xac, 0x72, 0x8e, 0x1e, 0x33, 0x5b, + 0x9c, 0xdc, 0x87, 0xf0, 0x69, 0x17, 0x2e, 0x32, + 0x3d, 0x09, 0x4b, 0x47, 0xfa, 0x1e, 0x65, 0x2a, + 0xfe, 0x4d, 0x6a, 0xa1, 0x47, 0xa9, 0xf4, 0x6f, + 0xda, 0x33, 0xca, 0xcb, 0x65, 0xf3, 0xaa, 0x12, + 0x23, 0x47, 0x46, 0xb9, 0x00, 0x7a, 0x8c, 0x85, + 0xfe, 0x98, 0x2a, 0xfe, 0xd7, 0x81, 0x52, 0x21, + 0xe4, 0x3d, 0xba, 0x55, 0x3d, 0x8f, 0xe8, 0xa0, + 0x22, 0xcd, 0xac, 0x1b, 0x99, 0xee, 0xee, 0xa3, + 0x59, 0xe5, 0xa9, 0xd2, 0xe7, 0x2e, 0x38, 0x2d, + 0xff, 0xa6, 0xd1, 0x9f, 0x35, 0x9f, 0x4f, 0x27, + 0xdc, 0x34, 0x34, 0xcd, 0x27, 0xda, 0xee, 0xda, + 0x8e, 0x38, 0x59, 0x48, 0x73, 0x39, 0x86, 0x78, + 0x06, 0x5f, 0xbb, 0x23, 0x66, 0x5a, 0xba, 0x93, + 0x09, 0xd9, 0x46, 0x13, 0x5d, 0xa0, 0xe4, 0xa4, + 0xaf, 0xda, 0xdf, 0xf1, 0x4d, 0xb1, 0x8e, 0x85, + 0xe7, 0x1d, 0xd9, 0x3c, 0x3b, 0xf9, 0xfa, 0xf7, + 0xf2, 0x5c, 0x81, 0x94, 0xc4, 0x26, 0x9b, 0x1e, + 0xe3, 0xd9, 0x93, 0x40, 0x97, 0xab, 0x99, 0x00, + 0x25, 0xd9, 0xc3, 0xaa, 0xf6, 0x3d, 0x51, 0x09, + 0xf5, 0x23, 0x35, 0xdd, 0x39, 0x59, 0xd3, 0x8a, + 0xe4, 0x85, 0x05, 0x0e, 0x4b, 0xbb, 0x62, 0x35, + 0x57, 0x4f, 0xc0, 0x10, 0x2b, 0xe8, 0xf7, 0xa3, + 0x06, 0xd6, 0xe8, 0xde, 0x6b, 0xa6, 0xbe, 0xcf, + 0x80, 0xf3, 0x74, 0x15, 0xb5, 0x7f, 0x98, 0x98, + 0xa5, 0x82, 0x4e, 0x77, 0x41, 0x41, 0x97, 0x42, + 0x2b, 0xe3, 0xd3, 0x6a, 0x60, 0x80 +}; + +static uint8_t sha1_MD_2096[20] = { + 0x04, 0x23, 0xdc, 0x76, 0xa8, 0x79, 0x11, 0x07, + 0xd1, 0x4e, 0x13, 0xf5, 0x26, 0x5b, 0x34, 0x3f, + 0x24, 0xcc, 0x0f, 0x19 +}; + + + +/* + * HMAC SHA1 Test Vectors from RFC 2202 + */ + +static uint8_t test_case1_hmac_sha1_key[20] = { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b +}; +static uint8_t test_case1_hmac_sha1_data[8] = { + 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 +}; +static uint8_t test_case1_hmac_sha1_result[20] = { + 0xb6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, + 0xe2, 0x8b, 0xc0, 0xb6, 0xfb, 0x37, 0x8c, 0x8e, + 0xf1, 0x46, 0xbe, 0x00 +}; + + +static uint8_t test_case2_hmac_sha1_key[4] = { + 0x4a, 0x65, 0x66, 0x65 +}; +static uint8_t test_case2_hmac_sha1_data[28] = { + 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, + 0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, + 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68, + 0x69, 0x6e, 0x67, 0x3f +}; +static uint8_t test_case2_hmac_sha1_result[20] = { + 0xef, 0xfc, 0xdf, 0x6a, 0xe5, 0xeb, 0x2f, 0xa2, + 0xd2, 0x74, 0x16, 0xd5, 0xf1, 0x84, 0xdf, 0x9c, + 0x25, 0x9a, 0x7c, 0x79 +}; + + +static uint8_t test_case3_hmac_sha1_key[20] = { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa +}; +static uint8_t test_case3_hmac_sha1_data[50] = { + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd +}; +static uint8_t test_case3_hmac_sha1_result[20] = { + 0x12, 0x5d, 0x73, 0x42, 0xb9, 0xac, 0x11, 0xcd, + 0x91, 0xa3, 0x9a, 0xf4, 0x8a, 0xa1, 0x7b, 0x4f, + 0x63, 0xf1, 0x75, 0xd3 +}; + + +static uint8_t test_case4_hmac_sha1_key[25] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19 +}; +static uint8_t test_case4_hmac_sha1_data[50] = { + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd +}; +static uint8_t test_case4_hmac_sha1_result[20] = { + 0x4c, 0x90, 0x07, 0xf4, 0x02, 0x62, 0x50, 0xc6, + 0xbc, 0x84, 0x14, 0xf9, 0xbf, 0x50, 0xc8, 0x6c, + 0x2d, 0x72, 0x35, 0xda +}; + + +static uint8_t test_case5_hmac_sha1_key[20] = { + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c +}; +static uint8_t test_case5_hmac_sha1_data[20] = { + 0x54, 0x65, 0x73, 0x74, 0x20, 0x57, 0x69, 0x74, + 0x68, 0x20, 0x54, 0x72, 0x75, 0x6e, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e +}; +static uint8_t test_case5_hmac_sha1_result[20] = { + 0x4c, 0x1a, 0x03, 0x42, 0x4b, 0x55, 0xe0, 0x7f, + 0xe7, 0xf2, 0x7b, 0xe1, 0xd5, 0x8b, 0xb9, 0x32, + 0x4a, 0x9a, 0x5a, 0x04 +}; + + +static uint8_t test_case6_hmac_sha1_key[80] = { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa +}; +static uint8_t test_case6_hmac_sha1_data[54] = { + 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, + 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, + 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, + 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20, + 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79, + 0x20, 0x46, 0x69, 0x72, 0x73, 0x74 +}; +static uint8_t test_case6_hmac_sha1_result[20] = { + 0xaa, 0x4a, 0xe5, 0xe1, 0x52, 0x72, 0xd0, 0x0e, + 0x95, 0x70, 0x56, 0x37, 0xce, 0x8a, 0x3b, 0x55, + 0xed, 0x40, 0x21, 0x12 +}; + + +static uint8_t test_case7_hmac_sha1_key[80] = { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa +}; +static uint8_t test_case7_hmac_sha1_data[73] = { + 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, + 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, + 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, + 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, 0x72, + 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x4f, 0x6e, + 0x65, 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x2d, + 0x53, 0x69, 0x7a, 0x65, 0x20, 0x44, 0x61, 0x74, + 0x61 +}; +static uint8_t test_case7_hmac_sha1_result[20] = { + 0xe8, 0xe9, 0x9d, 0x0f, 0x45, 0x23, 0x7d, 0x78, + 0x6d, 0x6b, 0xba, 0xa7, 0x96, 0x5c, 0x78, 0x08, + 0xbb, 0xff, 0x1a, 0x91 +}; + + + +/* + * SHA256 Test Vectors + */ + +static uint8_t sha256_msg_8[1] = { + 0xbd +}; + +static uint8_t sha256_MD_8[32] = { + 0x68, 0x32, 0x57, 0x20, 0xaa, 0xbd, 0x7c, 0x82, + 0xf3, 0x0f, 0x55, 0x4b, 0x31, 0x3d, 0x05, 0x70, + 0xc9, 0x5a, 0xcc, 0xbb, 0x7d, 0xc4, 0xb5, 0xaa, + 0xe1, 0x12, 0x04, 0xc0, 0x8f, 0xfe, 0x73, 0x2b +}; + +static uint8_t sha256_msg_128[16] = { + 0xfd, 0xf4, 0x70, 0x09, 0x84, 0xee, 0x11, 0xb7, + 0x0a, 0xf1, 0x88, 0x0d, 0x0e, 0x0f, 0xef, 0xd4 +}; + +static uint8_t sha256_MD_128[32] = { + 0xb0, 0x1a, 0xe1, 0x6e, 0xed, 0x3b, 0x4a, 0x77, + 0x0f, 0x12, 0x7b, 0x98, 0x46, 0x9b, 0xa2, 0x6f, + 0xe3, 0xd8, 0xe9, 0xf5, 0x9d, 0x8a, 0x29, 0x83, + 0x21, 0x4a, 0xfe, 0x6c, 0xff, 0x0e, 0x6b, 0x6c +}; + + +static uint8_t sha256_msg_512[64] = { + 0x35, 0x92, 0xec, 0xfd, 0x1e, 0xac, 0x61, 0x8f, + 0xd3, 0x90, 0xe7, 0xa9, 0xc2, 0x4b, 0x65, 0x65, + 0x32, 0x50, 0x93, 0x67, 0xc2, 0x1a, 0x0e, 0xac, + 0x12, 0x12, 0xac, 0x83, 0xc0, 0xb2, 0x0c, 0xd8, + 0x96, 0xeb, 0x72, 0xb8, 0x01, 0xc4, 0xd2, 0x12, + 0xc5, 0x45, 0x2b, 0xbb, 0xf0, 0x93, 0x17, 0xb5, + 0x0c, 0x5c, 0x9f, 0xb1, 0x99, 0x75, 0x53, 0xd2, + 0xbb, 0xc2, 0x9b, 0xb4, 0x2f, 0x57, 0x48, 0xad +}; + +static uint8_t sha256_MD_512[32] = { + 0x10, 0x5a, 0x60, 0x86, 0x58, 0x30, 0xac, 0x3a, + 0x37, 0x1d, 0x38, 0x43, 0x32, 0x4d, 0x4b, 0xb5, + 0xfa, 0x8e, 0xc0, 0xe0, 0x2d, 0xda, 0xa3, 0x89, + 0xad, 0x8d, 0xa4, 0xf1, 0x02, 0x15, 0xc4, 0x54 +}; + +static uint8_t sha256_msg_2096[262] = { + 0xf6, 0xce, 0x82, 0x21, 0xbf, 0x64, 0x27, 0x3c, + 0x91, 0xc4, 0xcb, 0x41, 0xeb, 0xba, 0x1b, 0xfc, + 0xfa, 0x12, 0xc0, 0x43, 0xc7, 0x01, 0x31, 0x7e, + 0xb0, 0xc0, 0xcb, 0x66, 0x15, 0x7a, 0x23, 0x0c, + 0x53, 0x68, 0x9b, 0x1d, 0xf6, 0x3b, 0x33, 0x65, + 0x2a, 0xba, 0xa2, 0x93, 0x73, 0xac, 0xa6, 0x3c, + 0x9e, 0xf8, 0x98, 0x22, 0xf8, 0x0b, 0x43, 0xb5, + 0xbd, 0x7a, 0xf6, 0xda, 0xd3, 0xe8, 0xd8, 0xec, + 0xb8, 0x2b, 0x7c, 0x00, 0xba, 0xaa, 0xb5, 0x6e, + 0x66, 0x09, 0xac, 0x8d, 0x42, 0x09, 0x2f, 0xbd, + 0xbf, 0xa9, 0x4c, 0xab, 0x69, 0x92, 0x1f, 0xd0, + 0x61, 0xb1, 0xe8, 0x3b, 0x0d, 0x26, 0x60, 0x91, + 0x0e, 0x5d, 0x4e, 0x52, 0x72, 0x7a, 0x55, 0x5d, + 0x2b, 0xfb, 0x10, 0xb7, 0xc0, 0x98, 0x61, 0x88, + 0x43, 0x6e, 0x05, 0x66, 0x83, 0x5d, 0x6c, 0xd6, + 0x82, 0xaf, 0xc8, 0x10, 0x2a, 0xfa, 0x65, 0x03, + 0x3b, 0x47, 0x38, 0x99, 0x88, 0x73, 0xba, 0x3c, + 0x63, 0xd6, 0xf7, 0x99, 0x56, 0x23, 0xe1, 0xa4, + 0x14, 0x8f, 0xeb, 0xdc, 0xae, 0x36, 0xd3, 0xd0, + 0x0a, 0xba, 0xbf, 0xe2, 0x92, 0x2d, 0x8c, 0x4b, + 0x29, 0x31, 0x63, 0x5f, 0x63, 0x5d, 0x8d, 0x12, + 0xf5, 0xe3, 0x88, 0xbc, 0x6a, 0x70, 0x5a, 0x19, + 0x18, 0x54, 0x25, 0x94, 0x53, 0xe3, 0xfc, 0xc5, + 0xe0, 0x1b, 0xf5, 0x38, 0xac, 0x87, 0x7f, 0x70, + 0xbe, 0x62, 0xf6, 0x2b, 0x6b, 0x00, 0x75, 0xe8, + 0xc9, 0x6a, 0xec, 0xa7, 0x66, 0x49, 0x72, 0xf0, + 0x39, 0x05, 0xdc, 0x16, 0xd8, 0x2d, 0x8e, 0xbd, + 0xec, 0x1a, 0x91, 0x9a, 0xe2, 0xcf, 0xe6, 0x7a, + 0xe4, 0x24, 0x1a, 0x86, 0x08, 0x24, 0x1b, 0xc5, + 0xc7, 0xb3, 0x4a, 0xe2, 0xb0, 0x74, 0xd1, 0x30, + 0x5d, 0xe9, 0x37, 0xeb, 0xa7, 0xdc, 0x32, 0xc1, + 0x16, 0xfe, 0xbc, 0x90, 0x9b, 0xcf, 0x68, 0x72, + 0x82, 0xbd, 0xf7, 0xf7, 0xa2, 0x90 +}; + +static uint8_t sha256_MD_2096[32] = { + 0xef, 0xd3, 0x5c, 0x0d, 0x49, 0xe6, 0xa2, 0x2c, + 0x2b, 0x54, 0x59, 0x9a, 0xbb, 0x0d, 0xfa, 0x41, + 0x94, 0x35, 0xa5, 0xb7, 0x49, 0xef, 0x1c, 0x71, + 0x23, 0xd5, 0x9a, 0x2f, 0xb5, 0xdb, 0x8f, 0x75 +}; + + +/* + * HMAC SHA256 Test Vectors from RFC 4231 + */ + +static uint8_t test_case1_hmac_sha2_key[20] = { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b +}; + +static uint8_t test_case1_hmac_sha2_data[8] = { + 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 +}; +static uint8_t test_case1_hmac_sha256_result[32] = { + 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, + 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b, + 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, + 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7 +}; +static uint8_t test_case1_hmac_sha384_result[48] = { + 0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62, + 0x6b, 0x08, 0x25, 0xf4, 0xab, 0x46, 0x90, 0x7f, + 0x15, 0xf9, 0xda, 0xdb, 0xe4, 0x10, 0x1e, 0xc6, + 0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, 0xc5, 0x9c, + 0xfa, 0xea, 0x9e, 0xa9, 0x07, 0x6e, 0xde, 0x7f, + 0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6 +}; + + +static uint8_t test_case2_hmac_sha2_key[4] = { + 0x4a, 0x65, 0x66, 0x65 +}; +static uint8_t test_case2_hmac_sha2_data[28] = { + 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, + 0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, + 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68, + 0x69, 0x6e, 0x67, 0x3f +}; +static uint8_t test_case2_hmac_sha256_result[32] = { + 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, + 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7, + 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, + 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43 +}; +static uint8_t test_case2_hmac_sha384_result[48] = { + 0xaf, 0x45, 0xd2, 0xe3, 0x76, 0x48, 0x40, 0x31, + 0x61, 0x7f, 0x78, 0xd2, 0xb5, 0x8a, 0x6b, 0x1b, + 0x9c, 0x7e, 0xf4, 0x64, 0xf5, 0xa0, 0x1b, 0x47, + 0xe4, 0x2e, 0xc3, 0x73, 0x63, 0x22, 0x44, 0x5e, + 0x8e, 0x22, 0x40, 0xca, 0x5e, 0x69, 0xe2, 0xc7, + 0x8b, 0x32, 0x39, 0xec, 0xfa, 0xb2, 0x16, 0x49 +}; + + +static uint8_t test_case3_hmac_sha2_key[20] = { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa +}; +static uint8_t test_case3_hmac_sha2_data[50] = { + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd +}; +static uint8_t test_case3_hmac_sha256_result[32] = { + 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, + 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7, + 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22, + 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe +}; +static uint8_t test_case3_hmac_sha384_result[48] = { + 0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a, + 0x0a, 0xa2, 0xac, 0xe0, 0x14, 0xc8, 0xa8, 0x6f, + 0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb, + 0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b, + 0x2a, 0x5a, 0xb3, 0x9d, 0xc1, 0x38, 0x14, 0xb9, + 0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27 +}; + + +static uint8_t test_case4_hmac_sha2_key[25] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19 +}; +static uint8_t test_case4_hmac_sha2_data[50] = { + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd +}; +static uint8_t test_case4_hmac_sha256_result[32] = { + 0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, + 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a, + 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07, + 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b +}; +static uint8_t test_case4_hmac_sha384_result[48] = { + 0x3e, 0x8a, 0x69, 0xb7, 0x78, 0x3c, 0x25, 0x85, + 0x19, 0x33, 0xab, 0x62, 0x90, 0xaf, 0x6c, 0xa7, + 0x7a, 0x99, 0x81, 0x48, 0x08, 0x50, 0x00, 0x9c, + 0xc5, 0x57, 0x7c, 0x6e, 0x1f, 0x57, 0x3b, 0x4e, + 0x68, 0x01, 0xdd, 0x23, 0xc4, 0xa7, 0xd6, 0x79, + 0xcc, 0xf8, 0xa3, 0x86, 0xc6, 0x74, 0xcf, 0xfb +}; + + +static uint8_t test_case5_hmac_sha2_key[20] = { + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c +}; +static uint8_t test_case5_hmac_sha2_data[20] = { + 0x54, 0x65, 0x73, 0x74, 0x20, 0x57, 0x69, 0x74, + 0x68, 0x20, 0x54, 0x72, 0x75, 0x6e, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e +}; +static uint8_t test_case5_hmac_sha256_result[16] = { + 0xa3, 0xb6, 0x16, 0x74, 0x73, 0x10, 0x0e, 0xe0, + 0x6e, 0x0c, 0x79, 0x6c, 0x29, 0x55, 0x55, 0x2b +}; +static uint8_t test_case5_hmac_sha384_result[16] = { + 0x3a, 0xbf, 0x34, 0xc3, 0x50, 0x3b, 0x2a, 0x23, + 0xa4, 0x6e, 0xfc, 0x61, 0x9b, 0xae, 0xf8, 0x97 +}; + + +static uint8_t test_case6_hmac_sha2_key[131] = { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa +}; +static uint8_t test_case6_hmac_sha2_data[54] = { + 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, + 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, + 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, + 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20, + 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79, + 0x20, 0x46, 0x69, 0x72, 0x73, 0x74 +}; +static uint8_t test_case6_hmac_sha256_result[32] = { + 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, + 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, + 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, + 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54 +}; +static uint8_t test_case6_hmac_sha384_result[48] = { + 0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90, + 0x88, 0xd2, 0xc6, 0x3a, 0x04, 0x1b, 0xc5, 0xb4, + 0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f, + 0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6, + 0x0c, 0x2e, 0xf6, 0xab, 0x40, 0x30, 0xfe, 0x82, + 0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52 +}; + + +static uint8_t test_case7_hmac_sha2_key[131] = { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa +}; + +static uint8_t test_case7_hmac_sha2_data[152] = { + 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75, + 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c, + 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, + 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65, + 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, + 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, + 0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64, + 0x61, 0x74, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65, + 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, + 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20, + 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62, + 0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65, + 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c, + 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e +}; +static uint8_t test_case7_hmac_sha256_result[32] = { + 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, + 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44, + 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, + 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2 +}; +static uint8_t test_case7_hmac_sha384_result[48] = { + 0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d, + 0x35, 0x1e, 0x2f, 0x25, 0x4e, 0x8f, 0xd3, 0x2c, + 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a, + 0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5, + 0xa6, 0x78, 0xcc, 0x31, 0xe7, 0x99, 0x17, 0x6d, + 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e +}; + + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_sha_test( zrtp_hash_t *self, + const uint8_t *test_vector, + int vector_length, + const uint8_t *test_result, + int test_length) +{ + zrtp_status_t res; + zrtp_string256_t hval = ZSTR_INIT_EMPTY(hval); + + res = self->hash_c(self, (const char*)test_vector, vector_length, (zrtp_stringn_t*)&hval); + if (zrtp_status_ok != res) { + return res; + } + + return (0 == zrtp_memcmp(hval.buffer, test_result, test_length)) ? zrtp_status_ok : zrtp_status_fail; +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_hmac_test( zrtp_hash_t *self, + const uint8_t *key, + uint16_t key_length, + const uint8_t *test_vector, + uint16_t vector_length, + const uint8_t *test_result, + int test_length) +{ + zrtp_status_t res; + zrtp_string256_t hval = ZSTR_INIT_EMPTY(hval); + zrtp_string256_t zrtp_key = ZSTR_INIT_EMPTY(zrtp_key); + zrtp_string256_t zrtp_test_vector = ZSTR_INIT_EMPTY(zrtp_test_vector); + + zrtp_zstrncpyc(ZSTR_GV(zrtp_key), (const char*)key, key_length); + zrtp_zstrncpyc(ZSTR_GV(zrtp_test_vector), (const char*)test_vector, vector_length); + + res = self->hmac(self, ZSTR_GV(zrtp_key), ZSTR_GV(zrtp_test_vector), ZSTR_GV(hval)); + if (zrtp_status_ok != res) { + return res; + } + + return (0 == zrtp_memcmp(hval.buffer, test_result, test_length)) ? zrtp_status_ok : zrtp_status_fail; +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_sha256_self_test(zrtp_hash_t *self) +{ + zrtp_status_t res; + ZRTP_LOG(3, (_ZTU_,"SHA256 Testing\n")); + + ZRTP_LOG(3, (_ZTU_, "\t8-bit test... ")); + res = zrtp_sha_test(self, sha256_msg_8, sizeof(sha256_msg_8), sha256_MD_8, sizeof(sha256_MD_8)); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t128-bit test... ")); + res = zrtp_sha_test(self, sha256_msg_128, sizeof(sha256_msg_128), sha256_MD_128, sizeof(sha256_MD_128)); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t512-bit test... ")); + res = zrtp_sha_test(self, sha256_msg_512, sizeof(sha256_msg_512), sha256_MD_512, sizeof(sha256_MD_512)); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t2096-bit test... ")); + res = zrtp_sha_test(self, sha256_msg_2096, sizeof(sha256_msg_2096), sha256_MD_2096, sizeof(sha256_MD_2096)); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + return res; +} + +zrtp_status_t zrtp_sha384_self_test(zrtp_hash_t *self) +{ + return zrtp_status_ok; +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_hmac_sha256_self_test(zrtp_hash_t *self) +{ + zrtp_status_t res; + ZRTP_LOG(3, (_ZTU_,"HMAC SHA256 Testing\n")); + + ZRTP_LOG(3, (_ZTU_, "\t1 case test... ")); + res = zrtp_hmac_test( self, + test_case1_hmac_sha2_key, + sizeof(test_case1_hmac_sha2_key), + test_case1_hmac_sha2_data, + sizeof(test_case1_hmac_sha2_data), + test_case1_hmac_sha256_result, + sizeof(test_case1_hmac_sha256_result)); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t2 case test... ")); + res = zrtp_hmac_test( self, + test_case2_hmac_sha2_key, + sizeof(test_case2_hmac_sha2_key), + test_case2_hmac_sha2_data, + sizeof(test_case2_hmac_sha2_data), + test_case2_hmac_sha256_result, + sizeof(test_case2_hmac_sha256_result)); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t3 case test... ")); + res = zrtp_hmac_test( self, + test_case3_hmac_sha2_key, + sizeof(test_case3_hmac_sha2_key), + test_case3_hmac_sha2_data, + sizeof(test_case3_hmac_sha2_data), + test_case3_hmac_sha256_result, + sizeof(test_case3_hmac_sha256_result)); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t4 case test... ")); + res = zrtp_hmac_test(self, + test_case4_hmac_sha2_key, + sizeof(test_case4_hmac_sha2_key), + test_case4_hmac_sha2_data, + sizeof(test_case4_hmac_sha2_data), + test_case4_hmac_sha256_result, + sizeof(test_case4_hmac_sha256_result)); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t5 case test...")); + res = zrtp_hmac_test(self, + test_case5_hmac_sha2_key, + sizeof(test_case5_hmac_sha2_key), + test_case5_hmac_sha2_data, + sizeof(test_case5_hmac_sha2_data), + test_case5_hmac_sha256_result, + sizeof(test_case5_hmac_sha256_result)); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t6 case test... ")); + res = zrtp_hmac_test(self, + test_case6_hmac_sha2_key, + sizeof(test_case6_hmac_sha2_key), + test_case6_hmac_sha2_data, + sizeof(test_case6_hmac_sha2_data), + test_case6_hmac_sha256_result, + sizeof(test_case6_hmac_sha256_result)); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t7 case test...")); + res = zrtp_hmac_test(self, + test_case7_hmac_sha2_key, + sizeof(test_case7_hmac_sha2_key), + test_case7_hmac_sha2_data, + sizeof(test_case7_hmac_sha2_data), + test_case7_hmac_sha256_result, + sizeof(test_case7_hmac_sha256_result)); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + return res; +} + +zrtp_status_t zrtp_hmac_sha384_self_test(zrtp_hash_t *self) +{ + zrtp_status_t res; + ZRTP_LOG(3, (_ZTU_,"HMAC SHA384 Testing\n")); + + ZRTP_LOG(3, (_ZTU_, "\t1 case test... ")); + res = zrtp_hmac_test( self, + test_case1_hmac_sha2_key, + sizeof(test_case1_hmac_sha2_key), + test_case1_hmac_sha2_data, + sizeof(test_case1_hmac_sha2_data), + test_case1_hmac_sha384_result, + sizeof(test_case1_hmac_sha384_result)); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t2 case test... ")); + res = zrtp_hmac_test( self, + test_case2_hmac_sha2_key, + sizeof(test_case2_hmac_sha2_key), + test_case2_hmac_sha2_data, + sizeof(test_case2_hmac_sha2_data), + test_case2_hmac_sha384_result, + sizeof(test_case2_hmac_sha384_result)); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t3 case test... ")); + res = zrtp_hmac_test( self, + test_case3_hmac_sha2_key, + sizeof(test_case3_hmac_sha2_key), + test_case3_hmac_sha2_data, + sizeof(test_case3_hmac_sha2_data), + test_case3_hmac_sha384_result, + sizeof(test_case3_hmac_sha384_result)); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t4 case test... ")); + res = zrtp_hmac_test(self, + test_case4_hmac_sha2_key, + sizeof(test_case4_hmac_sha2_key), + test_case4_hmac_sha2_data, + sizeof(test_case4_hmac_sha2_data), + test_case4_hmac_sha384_result, + sizeof(test_case4_hmac_sha384_result)); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t5 case test...")); + res = zrtp_hmac_test(self, + test_case5_hmac_sha2_key, + sizeof(test_case5_hmac_sha2_key), + test_case5_hmac_sha2_data, + sizeof(test_case5_hmac_sha2_data), + test_case5_hmac_sha384_result, + sizeof(test_case5_hmac_sha384_result)); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t6 case test... ")); + res = zrtp_hmac_test(self, + test_case6_hmac_sha2_key, + sizeof(test_case6_hmac_sha2_key), + test_case6_hmac_sha2_data, + sizeof(test_case6_hmac_sha2_data), + test_case6_hmac_sha384_result, + sizeof(test_case6_hmac_sha384_result)); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t7 case test...")); + res = zrtp_hmac_test(self, + test_case7_hmac_sha2_key, + sizeof(test_case7_hmac_sha2_key), + test_case7_hmac_sha2_data, + sizeof(test_case7_hmac_sha2_data), + test_case7_hmac_sha384_result, + sizeof(test_case7_hmac_sha384_result)); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + return res; +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_sha1_self_test(zrtp_hash_t *self) +{ + zrtp_status_t res; + ZRTP_LOG(3, (_ZTU_,"SHA1 Testing\n")); + + ZRTP_LOG(3, (_ZTU_, "\t8-bit test... ")); + res = zrtp_sha_test(self, sha1_msg_8, sizeof(sha1_msg_8), sha1_MD_8, ZRTP_SRTP_HASH_SHA1); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t128-bit test... ")); + res = zrtp_sha_test(self, sha1_msg_128, sizeof(sha1_msg_128), sha1_MD_128, ZRTP_SRTP_HASH_SHA1); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t512-bit test... ")); + res = zrtp_sha_test(self, sha1_msg_512, sizeof(sha1_msg_512), sha1_MD_512, ZRTP_SRTP_HASH_SHA1); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t2096-bit test... ")); + res = zrtp_sha_test(self, sha1_msg_2096, sizeof(sha1_msg_2096), sha1_MD_2096, ZRTP_SRTP_HASH_SHA1); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + return res; +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_hmac_sha1_self_test(zrtp_hash_t *self) +{ + zrtp_status_t res; + ZRTP_LOG(3, (_ZTU_,"HMAC SHA1 Testing\n")); + + ZRTP_LOG(3, (_ZTU_, "\t1 case test... ")); + res = zrtp_hmac_test(self, + test_case1_hmac_sha1_key, + sizeof(test_case1_hmac_sha1_key), + test_case1_hmac_sha1_data, + sizeof(test_case1_hmac_sha1_data), + test_case1_hmac_sha1_result, + ZRTP_SRTP_HASH_SHA1); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t2 case test... ")); + res = zrtp_hmac_test(self, + test_case2_hmac_sha1_key, + sizeof(test_case2_hmac_sha1_key), + test_case2_hmac_sha1_data, + sizeof(test_case2_hmac_sha1_data), + test_case2_hmac_sha1_result, + ZRTP_SRTP_HASH_SHA1); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t3 case test... ")); + res = zrtp_hmac_test(self, + test_case3_hmac_sha1_key, + sizeof(test_case3_hmac_sha1_key), + test_case3_hmac_sha1_data, + sizeof(test_case3_hmac_sha1_data), + test_case3_hmac_sha1_result, + ZRTP_SRTP_HASH_SHA1); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t4 case test... ")); + res = zrtp_hmac_test(self, + test_case4_hmac_sha1_key, + sizeof(test_case4_hmac_sha1_key), + test_case4_hmac_sha1_data, + sizeof(test_case4_hmac_sha1_data), + test_case4_hmac_sha1_result, + ZRTP_SRTP_HASH_SHA1); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t5 case test... ")); + res = zrtp_hmac_test(self, + test_case5_hmac_sha1_key, + sizeof(test_case5_hmac_sha1_key), + test_case5_hmac_sha1_data, + sizeof(test_case5_hmac_sha1_data), + test_case5_hmac_sha1_result, + ZRTP_SRTP_HASH_SHA1); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t6 case test... ")); + res = zrtp_hmac_test(self, + test_case6_hmac_sha1_key, + sizeof(test_case6_hmac_sha1_key), + test_case6_hmac_sha1_data, + sizeof(test_case6_hmac_sha1_data), + test_case6_hmac_sha1_result, + ZRTP_SRTP_HASH_SHA1); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + ZRTP_LOG(3, (_ZTU_, "\t7 case test... ")); + res = zrtp_hmac_test(self, + test_case7_hmac_sha1_key, + sizeof(test_case7_hmac_sha1_key), + test_case7_hmac_sha1_data, + sizeof(test_case7_hmac_sha1_data), + test_case7_hmac_sha1_result, + ZRTP_SRTP_HASH_SHA1); + ZRTP_LOGC(3, ("%s\n", zrtp_status_ok == res?"OK":"FALSE")); + + return res; +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_defaults_hash(zrtp_global_t* global_ctx) +{ + zrtp_hash_t* hash_sha384 = zrtp_sys_alloc(sizeof(zrtp_hash_t)); + zrtp_hash_t* hash_sha256 = zrtp_sys_alloc(sizeof(zrtp_hash_t)); + zrtp_hash_t* hash_sha1 = zrtp_sys_alloc(sizeof(zrtp_hash_t)); + if (!hash_sha256 || !hash_sha1 || !hash_sha384) { + if (hash_sha384) { + zrtp_sys_free(hash_sha384); + } + if (hash_sha256) { + zrtp_sys_free(hash_sha256); + } + if (hash_sha1) { + zrtp_sys_free(hash_sha1); + } + return zrtp_status_alloc_fail; + } + + zrtp_memset(hash_sha384, 0, sizeof(zrtp_hash_t)); + zrtp_memset(hash_sha256, 0, sizeof(zrtp_hash_t)); + zrtp_memset(hash_sha1, 0, sizeof(zrtp_hash_t)); + + zrtp_memcpy(hash_sha384->base.type, ZRTP_S384, ZRTP_COMP_TYPE_SIZE); + hash_sha384->base.id = ZRTP_HASH_SHA384; + hash_sha384->base.zrtp = global_ctx; + hash_sha384->block_length = SHA384_BLOCK_SIZE; + hash_sha384->digest_length = SHA384_DIGEST_SIZE; + + hash_sha384->hash_begin = zrtp_sha_begin; + hash_sha384->hash_update = zrtp_sha_update; + hash_sha384->hash_end = zrtp_sha_end; + hash_sha384->hash = zrtp_sha; + hash_sha384->hash_c = zrtp_sha_c; + hash_sha384->hash_self_test = zrtp_sha384_self_test; + + hash_sha384->hmac_begin_c = zrtp_hmac_sha384_begin_c; + hash_sha384->hmac_begin = zrtp_hmac_begin; + hash_sha384->hmac_update = zrtp_hmac_update; + hash_sha384->hmac_end = zrtp_hmac_end; + hash_sha384->hmac = zrtp_hmac; + hash_sha384->hmac_c = zrtp_hmac_c; + hash_sha384->hmac_truncated = zrtp_hmac_truncated; + hash_sha384->hmac_truncated_c = zrtp_hmac_truncated_c; + hash_sha384->hmac_self_test = zrtp_hmac_sha384_self_test; + + zrtp_memcpy(hash_sha256->base.type, ZRTP_S256, ZRTP_COMP_TYPE_SIZE); + hash_sha256->base.id = ZRTP_HASH_SHA256; + hash_sha256->base.zrtp = global_ctx; + hash_sha256->block_length = SHA256_BLOCK_SIZE; + hash_sha256->digest_length = SHA256_DIGEST_SIZE; + + hash_sha256->hash_begin = zrtp_sha_begin; + hash_sha256->hash_update = zrtp_sha_update; + hash_sha256->hash_end = zrtp_sha_end; + hash_sha256->hash = zrtp_sha; + hash_sha256->hash_c = zrtp_sha_c; + hash_sha256->hash_self_test = zrtp_sha256_self_test; + + hash_sha256->hmac_begin_c = zrtp_hmac_sha256_begin_c; + hash_sha256->hmac_begin = zrtp_hmac_begin; + hash_sha256->hmac_update = zrtp_hmac_update; + hash_sha256->hmac_end = zrtp_hmac_end; + hash_sha256->hmac = zrtp_hmac; + hash_sha256->hmac_c = zrtp_hmac_c; + hash_sha256->hmac_truncated = zrtp_hmac_truncated; + hash_sha256->hmac_truncated_c = zrtp_hmac_truncated_c; + hash_sha256->hmac_self_test = zrtp_hmac_sha256_self_test; + + + zrtp_memcpy(hash_sha1->base.type, ZRTP_S160, ZRTP_COMP_TYPE_SIZE); + hash_sha1->base.id = ZRTP_SRTP_HASH_SHA1; + hash_sha1->base.zrtp = global_ctx; + hash_sha1->block_length = SHA1_BLOCK_SIZE; + hash_sha1->digest_length = SHA1_DIGEST_SIZE; + + hash_sha1->hash_begin = zrtp_sha_begin; + hash_sha1->hash_update = zrtp_sha_update; + hash_sha1->hash_end = zrtp_sha_end; + hash_sha1->hash = zrtp_sha; + hash_sha1->hash_c = zrtp_sha_c; + hash_sha1->hash_self_test = zrtp_sha1_self_test; + + hash_sha1->hmac_begin_c = zrtp_hmac_sha1_begin_c; + hash_sha1->hmac_begin = zrtp_hmac_begin; + hash_sha1->hmac_update = zrtp_hmac_update; + hash_sha1->hmac_end = zrtp_hmac_end; + hash_sha1->hmac = zrtp_hmac; + hash_sha1->hmac_c = zrtp_hmac_c; + hash_sha1->hmac_truncated = zrtp_hmac_truncated; + hash_sha1->hmac_truncated_c = zrtp_hmac_truncated_c; + hash_sha1->hmac_self_test = zrtp_hmac_sha1_self_test; + + zrtp_comp_register(ZRTP_CC_HASH, hash_sha384, global_ctx); + zrtp_comp_register(ZRTP_CC_HASH, hash_sha256, global_ctx); + zrtp_comp_register(ZRTP_CC_HASH, hash_sha1, global_ctx); + + return zrtp_status_ok; +} diff --git a/src/zrtp_crypto_pk.c b/src/zrtp_crypto_pk.c new file mode 100644 index 0000000000..5961b04794 --- /dev/null +++ b/src/zrtp_crypto_pk.c @@ -0,0 +1,357 @@ +/* + * 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 + */ + +#include "zrtp.h" + +#define _ZTU_ "zrtp dh" + +/*============================================================================*/ +/* Global DH Functions */ +/*============================================================================*/ + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t zrtp_dh_init(void *s) +{ + struct BigNum* p = NULL; + struct BigNum* p_1 = NULL; + uint8_t* p_data = NULL; + unsigned int p_data_length = 0; + zrtp_pk_scheme_t *self = (zrtp_pk_scheme_t *) s; + + switch (self->base.id) { + case ZRTP_PKTYPE_DH2048: + p = &self->base.zrtp->P_2048; + p_1 = &self->base.zrtp->P_2048_1; + p_data = self->base.zrtp->P_2048_data; + p_data_length = sizeof(self->base.zrtp->P_2048_data); + break; + case ZRTP_PKTYPE_DH3072: + p = &self->base.zrtp->P_3072; + p_1 = &self->base.zrtp->P_3072_1; + p_data = self->base.zrtp->P_3072_data; + p_data_length = sizeof(self->base.zrtp->P_3072_data); + break; + default: + return zrtp_status_bad_param; + } + + bnBegin(p); + bnInsertBigBytes(p, (const unsigned char *)p_data, 0, p_data_length); + + bnBegin(p_1); + bnCopy(p_1, p); + bnSub(p_1, &self->base.zrtp->one); + + return zrtp_status_ok; +} + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t zrtp_dh_free(void *s) +{ + zrtp_pk_scheme_t *self = (zrtp_pk_scheme_t *) s; + switch (self->base.id) { + case ZRTP_PKTYPE_DH2048: + bnEnd(&self->base.zrtp->P_2048); + bnEnd(&self->base.zrtp->P_2048_1); + break; + case ZRTP_PKTYPE_DH3072: + bnEnd(&self->base.zrtp->P_3072); + bnEnd(&self->base.zrtp->P_3072_1); + break; + default: + return zrtp_status_bad_param; + } + + return zrtp_status_ok; +} + +/*----------------------------------------------------------------------------*/ +static struct BigNum* _zrtp_get_p(zrtp_pk_scheme_t *self) +{ + struct BigNum* p = NULL; + switch (self->base.id) { + case ZRTP_PKTYPE_DH2048: + p = &self->base.zrtp->P_2048; + break; + case ZRTP_PKTYPE_DH3072: + p = &self->base.zrtp->P_3072; + break; + default: + break; + } + + return p; +} + +static zrtp_status_t zrtp_dh_initialize( zrtp_pk_scheme_t *self, + zrtp_dh_crypto_context_t *dh_cc) +{ + unsigned char* buffer = zrtp_sys_alloc(sizeof(zrtp_uchar128_t)); + struct BigNum* p = _zrtp_get_p(self); + zrtp_time_t start_ts = zrtp_time_now(); + + ZRTP_LOG(1,(_ZTU_,"\tDH TEST: %.4s zrtp_dh_initialize() START. now=%llums.\n", self->base.type, start_ts)); + + if (!buffer) { + return zrtp_status_alloc_fail; + } + if (!p) { + zrtp_sys_free(buffer); + return zrtp_status_bad_param; + } + + if (64 != zrtp_randstr(self->base.zrtp, buffer, 64)) { + zrtp_sys_free(buffer); + return zrtp_status_rng_fail; + } + + bnBegin(&dh_cc->sv); + bnInsertBigBytes(&dh_cc->sv, (const unsigned char *)buffer, 0, self->sv_length); + bnBegin(&dh_cc->pv); + bnExpMod(&dh_cc->pv, &self->base.zrtp->G, &dh_cc->sv, p); + + zrtp_sys_free(buffer); + + ZRTP_LOG(1,(_ZTU_,"\tDH TEST: zrtp_dh_initialize() for %.4s was executed ts=%llums d=%llums.\n", self->base.type, zrtp_time_now(), zrtp_time_now()-start_ts)); + return zrtp_status_ok; +} + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t zrtp_dh_compute( zrtp_pk_scheme_t *self, + zrtp_dh_crypto_context_t *dh_cc, + struct BigNum *dhresult, + struct BigNum *pv) +{ + struct BigNum* p = _zrtp_get_p(self); + zrtp_time_t start_ts = zrtp_time_now(); + if (!p) { + return zrtp_status_bad_param; + } + + ZRTP_LOG(1,(_ZTU_,"\tDH TEST: %.4s zrtp_dh_compute() START. now=%llums.\n", self->base.type, start_ts)); + + bnExpMod(dhresult, pv, &dh_cc->sv, p); + ZRTP_LOG(1,(_ZTU_,"\tDH TEST: zrtp_dh_compute() for %.4s was executed ts=%llums d=%llums.\n", self->base.type, zrtp_time_now(), zrtp_time_now()-start_ts)); + return zrtp_status_ok; +} + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t zrtp_dh_validate(zrtp_pk_scheme_t *self, struct BigNum *pv) +{ + struct BigNum* p = _zrtp_get_p(self); + if (!p) { + return zrtp_status_bad_param; + } + + if (!pv || 0 == bnCmp(pv, &self->base.zrtp->one) || 0 == bnCmp(pv, p)) { + return zrtp_status_fail; + } else { + return zrtp_status_ok; + } +} + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t zrtp_dh_self_test(zrtp_pk_scheme_t *self) +{ + zrtp_status_t s = zrtp_status_ok; + zrtp_dh_crypto_context_t alice_cc; + zrtp_dh_crypto_context_t bob_cc; + struct BigNum alice_k; + struct BigNum bob_k; + zrtp_time_t start_ts = zrtp_time_now(); + + ZRTP_LOG(3, (_ZTU_, "PKS %.4s testing... ", self->base.type)); + + bnBegin(&alice_k); + bnBegin(&bob_k); + + do { + /* Both sides initalise DH schemes and compute secret and public values. */ + s = self->initialize(self, &alice_cc); + if (zrtp_status_ok != s) { + break; + } + s = self->initialize(self, &bob_cc); + if (zrtp_status_ok != s) { + break; + } + + /* Both sides validate public values. (to provide exact performance estimation) */ + s = self->validate(self, &bob_cc.pv); + if (zrtp_status_ok != s) { + break; + } + s = self->validate(self, &alice_cc.pv); + if (zrtp_status_ok != s) { + break; + } + + /* Compute secret keys and compare them. */ + s = self->compute(self, &alice_cc, &alice_k, &bob_cc.pv); + if (zrtp_status_ok != s) { + break; + } + s= self->compute(self, &bob_cc, &bob_k, &alice_cc.pv); + if (zrtp_status_ok != s) { + break; + } + + s = (0 == bnCmp(&alice_k, &bob_k)) ? zrtp_status_ok : zrtp_status_algo_fail; + } while (0); + + bnEnd(&alice_k); + bnEnd(&bob_k); + + ZRTP_LOGC(3, ("%s (%llu ms)\n", zrtp_log_status2str(s), (zrtp_time_now()-start_ts)/2)); + + return s; +} + +/*----------------------------------------------------------------------------*/ +#if (defined(ZRTP_ENABLE_EC) && (ZRTP_ENABLE_EC == 1)) +extern zrtp_status_t zrtp_defaults_ec_pkt(zrtp_global_t* zrtp); +#endif + +zrtp_status_t zrtp_defaults_pkt(zrtp_global_t* zrtp) +{ + zrtp_pk_scheme_t* presh = zrtp_sys_alloc(sizeof(zrtp_pk_scheme_t)); + zrtp_pk_scheme_t* dh2048 = zrtp_sys_alloc(sizeof(zrtp_pk_scheme_t)); + zrtp_pk_scheme_t* dh3072 = zrtp_sys_alloc(sizeof(zrtp_pk_scheme_t)); + zrtp_pk_scheme_t* multi = zrtp_sys_alloc(sizeof(zrtp_pk_scheme_t)); + + uint8_t P_2048_data[] = + { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, + 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, + 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, + 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, + 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, + 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + + uint8_t P_3072_data[] = + { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, + 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, + 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, + 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, + 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, + 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, + 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, + 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, + 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, + 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, + 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, + 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, + 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, + 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + + if (!dh2048 || !dh3072 || !presh || !multi) { + if (presh) { + zrtp_sys_free(presh); + } + if (dh2048) { + zrtp_sys_free(dh2048); + } + if (dh3072) { + zrtp_sys_free(dh3072); + } + if (multi) { + zrtp_sys_free(multi); + } + return zrtp_status_alloc_fail; + } + + zrtp_memset(dh3072, 0, sizeof(zrtp_pk_scheme_t)); + zrtp_memcpy(dh3072->base.type, ZRTP_DH3K, ZRTP_COMP_TYPE_SIZE); + dh3072->base.id = ZRTP_PKTYPE_DH3072; + dh3072->base.zrtp = zrtp; + dh3072->sv_length = 256/8; + dh3072->pv_length = 384; + dh3072->base.init = zrtp_dh_init; + dh3072->base.free = zrtp_dh_free; + dh3072->initialize = zrtp_dh_initialize; + dh3072->compute = zrtp_dh_compute; + dh3072->validate = zrtp_dh_validate; + dh3072->self_test = zrtp_dh_self_test; + zrtp_memcpy(zrtp->P_3072_data, P_3072_data, sizeof(P_3072_data)); + zrtp_comp_register(ZRTP_CC_PKT, dh3072, zrtp); + + zrtp_memset(dh2048, 0, sizeof(zrtp_pk_scheme_t)); + zrtp_memcpy(dh2048->base.type, ZRTP_DH2K, ZRTP_COMP_TYPE_SIZE); + dh2048->base.id = ZRTP_PKTYPE_DH2048; + dh2048->base.zrtp = zrtp; + dh2048->sv_length = 256/8; + dh2048->pv_length = 256; + dh2048->base.init = zrtp_dh_init; + dh2048->base.free = zrtp_dh_free; + dh2048->initialize = zrtp_dh_initialize; + dh2048->compute = zrtp_dh_compute; + dh2048->validate = zrtp_dh_validate; + dh2048->self_test = zrtp_dh_self_test; + zrtp_memcpy(zrtp->P_2048_data, P_2048_data, sizeof(P_2048_data)); + zrtp_comp_register(ZRTP_CC_PKT, dh2048, zrtp); + + zrtp_memset(multi, 0, sizeof(zrtp_pk_scheme_t)); + zrtp_memcpy(multi->base.type, ZRTP_MULT, ZRTP_COMP_TYPE_SIZE); + multi->base.id = ZRTP_PKTYPE_MULT; + zrtp_comp_register(ZRTP_CC_PKT, multi, zrtp); + + zrtp_memset(presh, 0, sizeof(zrtp_pk_scheme_t)); + zrtp_memcpy(presh->base.type, ZRTP_PRESHARED, ZRTP_COMP_TYPE_SIZE); + presh->base.id = ZRTP_PKTYPE_PRESH; + zrtp_comp_register(ZRTP_CC_PKT, presh, zrtp); + +#if (defined(ZRTP_ENABLE_EC) && (ZRTP_ENABLE_EC == 1)) + return zrtp_defaults_ec_pkt(zrtp); +#else + return zrtp_status_ok; +#endif +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_prepare_pkt(zrtp_global_t* zrtp) +{ + bnInit(); + bnBegin(&zrtp->one); + bnSetQ(&zrtp->one, 1); + bnBegin(&zrtp->G); + bnSetQ(&zrtp->G, 2); + + return zrtp_status_ok; +} + +zrtp_status_t zrtp_done_pkt(zrtp_global_t* zrtp) +{ + bnEnd(&zrtp->one); + bnEnd(&zrtp->G); + + return zrtp_status_ok; +} diff --git a/src/zrtp_crypto_sas.c b/src/zrtp_crypto_sas.c new file mode 100644 index 0000000000..93fc851dee --- /dev/null +++ b/src/zrtp_crypto_sas.c @@ -0,0 +1,745 @@ +/* + * 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 + */ + +#include "zrtp.h" + +/* These 3-syllable words are no longer than 11 characters. */ +extern uint8_t hash_word_list_odd[256][12]; + +/* These 2-syllable words are no longer than 9 characters. */ +extern uint8_t hash_word_list_even[256][10]; + +/*----------------------------------------------------------------------------*/ +/* + * copyright 2002, 2003 Bryce "Zooko" Wilcox-O'Hearn + * mailto:zooko@zooko.com + * + * See the end of this file for the free software, open source license (BSD-style). + */ + +/** + * Copyright (c) 2002 Bryce "Zooko" Wilcox-O'Hearn + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software to deal in this software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of this software, and to permit + * persons to whom this software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of this software. + * + * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THIS SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THIS SOFTWARE. + */ + +zrtp_status_t b2a(zrtp_stringn_t *os, zrtp_stringn_t *result) +{ + static const char chars[]="ybndrfg8ejkmcpqxot1uwisza345h769"; + + if (!os || !result) { + return zrtp_status_bad_param; + } else { + /* pointer into the os buffer, initially pointing to the "one-past-the-end" octet */ + const uint8_t* osp = (uint8_t*)os->buffer + os->length; + /* pointer into the result buffer, initially pointing to the "one-past-the-end" quintet */ + uint8_t* resp; + /* to hold up to 32 bits worth of the input */ + uint32_t x = 0; + + result->length = os->length*8; + result->length = (result->length % 5) ? ((result->length/5) + 1) : result->length/5; + + /* pointer into the result buffer, initially pointing to the "one-past-the-end" quintet */ + resp = (uint8_t*)result->buffer + result->length; + + /* Now this is a real live Duff's device. You gotta love it. */ + switch ((osp - (uint8_t*)os->buffer) % 5) { + case 0: + do { + x = *--osp; + *--resp = chars[x % 32]; /* The least sig 5 bits go into the final quintet. */ + x /= 32; /* ... now we have 3 bits worth in x... */ + case 4: + x |= ((uint32_t)(*--osp)) << 3; /* ... now we have 11 bits worth in x... */ + *--resp = chars[x % 32]; + x /= 32; /* ... now we have 6 bits worth in x... */ + *--resp = chars[x % 32]; + x /= 32; /* ... now we have 1 bits worth in x... */ + case 3: + /* The 8 bits from the 2-indexed octet. So now we have 9 bits worth in x... */ + x |= ((uint32_t)(*--osp)) << 1; + *--resp = chars[x % 32]; + x /= 32; /* ... now we have 4 bits worth in x... */ + case 2: + /* The 8 bits from the 1-indexed octet. So now we have 12 bits worth in x... */ + x |= ((uint32_t)(*--osp)) << 4; + *--resp = chars[x%32]; + x /= 32; /* ... now we have 7 bits worth in x... */ + *--resp = chars[x%32]; + x /= 32; /* ... now we have 2 bits worth in x... */ + case 1: + /* The 8 bits from the 0-indexed octet. So now we have 10 bits worth in x... */ + x |= ((uint32_t)(*--osp)) << 2; + *--resp = chars[x%32]; + x /= 32; /* ... now we have 5 bits worth in x... */ + *--resp = chars[x]; + } while (osp > (const uint8_t *)os->buffer); + } /* switch ((osp - os.buf) % 5) */ + + return zrtp_status_ok; + } +} + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t SAS32_compute( zrtp_sas_scheme_t *self, + zrtp_stream_t *stream, + zrtp_hash_t *hash, + uint8_t is_transferred ) +{ + zrtp_session_t *session = stream->session; + static const zrtp_string16_t sas_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_SAS_STR); + + zrtp_string64_t sas_digest = ZSTR_INIT_EMPTY(sas_digest); + zrtp_string8_t vad = ZSTR_INIT_EMPTY(vad); + + ZSTR_SET_EMPTY(session->sas1); + ZSTR_SET_EMPTY(session->sas2); + + if (!is_transferred && !stream->protocol) { + return zrtp_status_bad_param; + } + + /* + * Generate SAS source as: + * sashash = KDF(ZRTPSess, "SAS", (ZIDi | ZIDr), 256) + */ + if (!is_transferred) { + _zrtp_kdf( stream, + ZSTR_GV(stream->protocol->cc->s0), + ZSTR_GV(sas_label), + ZSTR_GV(stream->protocol->cc->kdf_context), + ZRTP_HASH_SIZE, + ZSTR_GV(sas_digest)); + + + /* Binary sas value is the leftmost ZRTP_SAS_DIGEST_LENGTH bytes */ + zrtp_zstrncpy(ZSTR_GV(session->sasbin), ZSTR_GV(sas_digest), ZRTP_SAS_DIGEST_LENGTH); + } else { + zrtp_zstrcpy(ZSTR_GV(sas_digest), ZSTR_GV(session->sasbin)); + } + + /* Take the leftmost 20 bits from sas source and render bas32 value */ + sas_digest.length = 3; + sas_digest.buffer[2] &= 0xF0; + if (zrtp_status_ok == b2a(ZSTR_GV(sas_digest), ZSTR_GV(vad)) && vad.length >= 4) { + zrtp_zstrncpy(ZSTR_GV(session->sas1), ZSTR_GV(vad), 4); + return zrtp_status_ok; + } + + return zrtp_status_fail; +} + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t SAS256_compute( zrtp_sas_scheme_t *self, + zrtp_stream_t *stream, + zrtp_hash_t *hash, + uint8_t is_transferred ) +{ + zrtp_session_t *session = stream->session; + ZSTR_SET_EMPTY(session->sas1); + ZSTR_SET_EMPTY(session->sas2); + + if (!is_transferred && !stream->protocol) { + return zrtp_status_bad_param; + } + + /* + * Generate SAS source as: + * sashash = KDF(ZRTPSess, "SAS", (ZIDi | ZIDr), 256) + */ + if (!is_transferred) + { + static const zrtp_string16_t sas_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_SAS_STR); + zrtp_string64_t sas_digest = ZSTR_INIT_EMPTY(sas_digest); + + _zrtp_kdf( stream, + ZSTR_GV(stream->protocol->cc->s0), + ZSTR_GV(sas_label), + ZSTR_GV(stream->protocol->cc->kdf_context), + ZRTP_HASH_SIZE, + ZSTR_GV(sas_digest)); + + /* Binary sas value is last ZRTP_SAS_DIGEST_LENGTH bytes */ + zrtp_zstrncpy(ZSTR_GV(session->sasbin), ZSTR_GV(sas_digest), ZRTP_SAS_DIGEST_LENGTH); + } + + zrtp_zstrcpyc(ZSTR_GV(session->sas1), (const char *)hash_word_list_even[(uint8_t)session->sasbin.buffer[0]]); + zrtp_zstrcpyc(ZSTR_GV(session->sas2), (const char *)hash_word_list_odd[(uint8_t)session->sasbin.buffer[1]]); + + return zrtp_status_ok; +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_defaults_sas(zrtp_global_t* zrtp) +{ + zrtp_sas_scheme_t* base32 = zrtp_sys_alloc(sizeof(zrtp_sas_scheme_t)); + zrtp_sas_scheme_t* base256 = zrtp_sys_alloc(sizeof(zrtp_sas_scheme_t)); + + if (!base32 || !base256) { + if (base32) { + zrtp_sys_free(base32); + } + if (base256) { + zrtp_sys_free(base256); + } + return zrtp_status_alloc_fail; + } + + zrtp_memset(base32, 0, sizeof(zrtp_sas_scheme_t)); + zrtp_memcpy(base32->base.type, ZRTP_B32, ZRTP_COMP_TYPE_SIZE); + base32->base.id = ZRTP_SAS_BASE32; + base32->base.zrtp = zrtp; + base32->compute = SAS32_compute; + + zrtp_memset(base256, 0, sizeof(zrtp_sas_scheme_t)); + zrtp_memcpy(base256->base.type, ZRTP_B256, ZRTP_COMP_TYPE_SIZE); + base256->base.id = ZRTP_SAS_BASE256; + base256->base.zrtp = zrtp; + base256->compute = SAS256_compute; + + zrtp_comp_register(ZRTP_CC_SAS, base32, zrtp); + zrtp_comp_register(ZRTP_CC_SAS, base256, zrtp); + + return zrtp_status_ok; +} + + +uint8_t hash_word_list_odd[256][12] = { + "adroitness", + "adviser", + "aftermath", + "aggregate", + "alkali", + "almighty", + "amulet", + "amusement", + "antenna", + "applicant", + "Apollo", + "armistice", + "article", + "asteroid", + "Atlantic", + "atmosphere", + "autopsy", + "Babylon", + "backwater", + "barbecue", + "belowground", + "bifocals", + "bodyguard", + "bookseller", + "borderline", + "bottomless", + "Bradbury", + "bravado", + "Brazilian", + "breakaway", + "Burlington", + "businessman", + "butterfat", + "Camelot", + "candidate", + "cannonball", + "Capricorn", + "caravan", + "caretaker", + "celebrate", + "cellulose", + "certify", + "chambermaid", + "Cherokee", + "Chicago", + "clergyman", + "coherence", + "combustion", + "commando", + "company", + "component", + "concurrent", + "confidence", + "conformist", + "congregate", + "consensus", + "consulting", + "corporate", + "corrosion", + "councilman", + "crossover", + "crucifix", + "cumbersome", + "customer", + "Dakota", + "decadence", + "December", + "decimal", + "designing", + "detector", + "detergent", + "determine", + "dictator", + "dinosaur", + "direction", + "disable", + "disbelief", + "disruptive", + "distortion", + "document", + "embezzle", + "enchanting", + "enrollment", + "enterprise", + "equation", + "equipment", + "escapade", + "Eskimo", + "everyday", + "examine", + "existence", + "exodus", + "fascinate", + "filament", + "finicky", + "forever", + "fortitude", + "frequency", + "gadgetry", + "Galveston", + "getaway", + "glossary", + "gossamer", + "graduate", + "gravity", + "guitarist", + "hamburger", + "Hamilton", + "handiwork", + "hazardous", + "headwaters", + "hemisphere", + "hesitate", + "hideaway", + "holiness", + "hurricane", + "hydraulic", + "impartial", + "impetus", + "inception", + "indigo", + "inertia", + "infancy", + "inferno", + "informant", + "insincere", + "insurgent", + "integrate", + "intention", + "inventive", + "Istanbul", + "Jamaica", + "Jupiter", + "leprosy", + "letterhead", + "liberty", + "maritime", + "matchmaker", + "maverick", + "Medusa", + "megaton", + "microscope", + "microwave", + "midsummer", + "millionaire", + "miracle", + "misnomer", + "molasses", + "molecule", + "Montana", + "monument", + "mosquito", + "narrative", + "nebula", + "newsletter", + "Norwegian", + "October", + "Ohio", + "onlooker", + "opulent", + "Orlando", + "outfielder", + "Pacific", + "pandemic", + "Pandora", + "paperweight", + "paragon", + "paragraph", + "paramount", + "passenger", + "pedigree", + "Pegasus", + "penetrate", + "perceptive", + "performance", + "pharmacy", + "phonetic", + "photograph", + "pioneer", + "pocketful", + "politeness", + "positive", + "potato", + "processor", + "provincial", + "proximate", + "puberty", + "publisher", + "pyramid", + "quantity", + "racketeer", + "rebellion", + "recipe", + "recover", + "repellent", + "replica", + "reproduce", + "resistor", + "responsive", + "retraction", + "retrieval", + "retrospect", + "revenue", + "revival", + "revolver", + "sandalwood", + "sardonic", + "Saturday", + "savagery", + "scavenger", + "sensation", + "sociable", + "souvenir", + "specialist", + "speculate", + "stethoscope", + "stupendous", + "supportive", + "surrender", + "suspicious", + "sympathy", + "tambourine", + "telephone", + "therapist", + "tobacco", + "tolerance", + "tomorrow", + "torpedo", + "tradition", + "travesty", + "trombonist", + "truncated", + "typewriter", + "ultimate", + "undaunted", + "underfoot", + "unicorn", + "unify", + "universe", + "unravel", + "upcoming", + "vacancy", + "vagabond", + "vertigo", + "Virginia", + "visitor", + "vocalist", + "voyager", + "warranty", + "Waterloo", + "whimsical", + "Wichita", + "Wilmington", + "Wyoming", + "yesteryear", + "Yucatan" + }; + +uint8_t hash_word_list_even[256][10] = { + "aardvark", + "absurd", + "accrue", + "acme", + "adrift", + "adult", + "afflict", + "ahead", + "aimless", + "Algol", + "allow", + "alone", + "ammo", + "ancient", + "apple", + "artist", + "assume", + "Athens", + "atlas", + "Aztec", + "baboon", + "backfield", + "backward", + "banjo", + "beaming", + "bedlamp", + "beehive", + "beeswax", + "befriend", + "Belfast", + "berserk", + "billiard", + "bison", + "blackjack", + "blockade", + "blowtorch", + "bluebird", + "bombast", + "bookshelf", + "brackish", + "breadline", + "breakup", + "brickyard", + "briefcase", + "Burbank", + "button", + "buzzard", + "cement", + "chairlift", + "chatter", + "checkup", + "chisel", + "choking", + "chopper", + "Christmas", + "clamshell", + "classic", + "classroom", + "cleanup", + "clockwork", + "cobra", + "commence", + "concert", + "cowbell", + "crackdown", + "cranky", + "crowfoot", + "crucial", + "crumpled", + "crusade", + "cubic", + "dashboard", + "deadbolt", + "deckhand", + "dogsled", + "dragnet", + "drainage", + "dreadful", + "drifter", + "dropper", + "drumbeat", + "drunken", + "Dupont", + "dwelling", + "eating", + "edict", + "egghead", + "eightball", + "endorse", + "endow", + "enlist", + "erase", + "escape", + "exceed", + "eyeglass", + "eyetooth", + "facial", + "fallout", + "flagpole", + "flatfoot", + "flytrap", + "fracture", + "framework", + "freedom", + "frighten", + "gazelle", + "Geiger", + "glitter", + "glucose", + "goggles", + "goldfish", + "gremlin", + "guidance", + "hamlet", + "highchair", + "hockey", + "indoors", + "indulge", + "inverse", + "involve", + "island", + "jawbone", + "keyboard", + "kickoff", + "kiwi", + "klaxon", + "locale", + "lockup", + "merit", + "minnow", + "miser", + "Mohawk", + "mural", + "music", + "necklace", + "Neptune", + "newborn", + "nightbird", + "Oakland", + "obtuse", + "offload", + "optic", + "orca", + "payday", + "peachy", + "pheasant", + "physique", + "playhouse", + "Pluto", + "preclude", + "prefer", + "preshrunk", + "printer", + "prowler", + "pupil", + "puppy", + "python", + "quadrant", + "quiver", + "quota", + "ragtime", + "ratchet", + "rebirth", + "reform", + "regain", + "reindeer", + "rematch", + "repay", + "retouch", + "revenge", + "reward", + "rhythm", + "ribcage", + "ringbolt", + "robust", + "rocker", + "ruffled", + "sailboat", + "sawdust", + "scallion", + "scenic", + "scorecard", + "Scotland", + "seabird", + "select", + "sentence", + "shadow", + "shamrock", + "showgirl", + "skullcap", + "skydive", + "slingshot", + "slowdown", + "snapline", + "snapshot", + "snowcap", + "snowslide", + "solo", + "southward", + "soybean", + "spaniel", + "spearhead", + "spellbind", + "spheroid", + "spigot", + "spindle", + "spyglass", + "stagehand", + "stagnate", + "stairway", + "standard", + "stapler", + "steamship", + "sterling", + "stockman", + "stopwatch", + "stormy", + "sugar", + "surmount", + "suspense", + "sweatband", + "swelter", + "tactics", + "talon", + "tapeworm", + "tempest", + "tiger", + "tissue", + "tonic", + "topmost", + "tracker", + "transit", + "trauma", + "treadmill", + "Trojan", + "trouble", + "tumor", + "tunnel", + "tycoon", + "uncut", + "unearth", + "unwind", + "uproot", + "upset", + "upshot", + "vapor", + "village", + "virus", + "Vulcan", + "waffle", + "wallet", + "watchword", + "wayside", + "willow", + "woodlark", + "Zulu" + }; diff --git a/src/zrtp_datatypes.c b/src/zrtp_datatypes.c new file mode 100644 index 0000000000..2da8fdc636 --- /dev/null +++ b/src/zrtp_datatypes.c @@ -0,0 +1,120 @@ +/* + * 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 + */ + +#include "zrtp.h" + +/*---------------------------------------------------------------------------*/ +void zrtp_bitmap_right_shift(uint8_t *x, int width_bytes, int index) +{ + const int base_index = index >> 3; + const int bit_index = index & 7; + int i, from; + uint8_t b; + + if (index > width_bytes*8) { + for(i=0; i < width_bytes; i++) { + x[i] = 0; + } + return; + } + + if (bit_index == 0) { + /* copy each word from left side to right side */ + x[width_bytes-1] = x[width_bytes-1-base_index]; + for (i=width_bytes-1; i > base_index; i--) { + x[i-1] = x[i-1-base_index]; + } + } else { + /* set each word to the OR of the two bit-shifted words */ + for (i = width_bytes; i > base_index; i--) { + from = i-1 - base_index; + b = x[from] << bit_index; + if (from > 0) { + b |= x[from-1] >> (8-bit_index); + } + x[i-1] = b; + } + } + + /* now wrap up the final portion */ + for (i=0; i < base_index; i++) { + x[i] = 0; + } +} + +/*---------------------------------------------------------------------------*/ +void zrtp_bitmap_left_shift(uint8_t *x, int width_bytes, int index) +{ + int i; + const int base_index = index >> 3; + const int bit_index = index & 7; + + if (index > width_bytes*8) { + for(i=0; i < width_bytes; i++) { + x[i] = 0; + } + return; + } + + if (0 == bit_index) { + for (i=0; i < width_bytes - base_index; i++) { + x[i] = x[i+base_index]; + } + } else { + for (i=0; i < width_bytes - base_index - 1; i++) { + x[i] = (x[i+base_index] >> bit_index) ^ (x[i+base_index+1] << (8 - bit_index)); + } + + x[width_bytes - base_index-1] = x[width_bytes-1] >> bit_index; + } + + /* now wrap up the final portion */ + for (i = width_bytes - base_index; i < width_bytes; i++) { + x[i] = 0; + } +} + +void zrtp_v128_xor(zrtp_v128_t *z, zrtp_v128_t *x, zrtp_v128_t *y) +{ + _zrtp_v128_xor(z, x, y); +} + +/*---------------------------------------------------------------------------*/ +uint32_t zrtp_swap32(uint32_t x) +{ + uint32_t res = (x >> 8 & 0x0000ff00) | (x << 8 & 0x00ff0000); + res |= (x >> 24 ) | (x << 24); + return res; +} + +#ifdef ZRTP_NO_64BIT_MATH +uint64_t zrtp_swap64(uint64_t x) +{ + uint8_t *p = &x; + uint8_t tmp; + int i; + + for(i=0; i<4; i++) { + tmp = p[i]; + p[i] = p[7-i]; + p[7-i] = tmp; + } + return x; +} +#else +uint64_t zrtp_swap64(uint64_t x) +{ + uint64_t res; + res = (x >> 8 & 0x00000000ff000000ll) | (x << 8 & 0x000000ff00000000ll); + res |= (x >> 24 & 0x0000000000ff0000ll) | (x << 24 & 0x0000ff0000000000ll); + res |= (x >> 40 & 0x000000000000ff00ll) | (x << 40 & 0x00ff000000000000ll); + res |= (x >> 56 & 0x00000000000000ffll) | (x << 56 & 0xff00000000000000ll); + return res; +} +#endif /* ZRTP_NO_64BIT_MATH */ diff --git a/src/zrtp_engine.c b/src/zrtp_engine.c new file mode 100644 index 0000000000..35d01d84ab --- /dev/null +++ b/src/zrtp_engine.c @@ -0,0 +1,1441 @@ +/* + * 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 + */ + +#include "zrtp.h" + +#define _ZTU_ "zrtp engine" + +/*! + * Data type for state-handlers: every state has a state handler + * function which is called by zrtp_process_srtp(). + */ +typedef zrtp_status_t state_handler_t( zrtp_stream_t* stream, zrtp_rtp_info_t* packet ); +extern state_handler_t* state_handler[ZRTP_STATE_COUNT]; + +extern zrtp_status_t _zrtp_machine_process_sasrelay(zrtp_stream_t *stream, zrtp_rtp_info_t *packet); + +static void _zrtp_machine_switch_to_error(zrtp_stream_t* stream); +static zrtp_status_t _zrtp_machine_enter_initiatingclear(zrtp_stream_t* stream); +static zrtp_status_t _zrtp_machine_enter_clear(zrtp_stream_t* stream); +static zrtp_status_t _zrtp_machine_enter_pendingerror(zrtp_stream_t *stream, zrtp_protocol_error_t code); + +zrtp_status_t _zrtp_machine_process_hello(zrtp_stream_t* stream, zrtp_rtp_info_t* packet); +zrtp_status_t _zrtp_machine_process_goclear(zrtp_stream_t* stream, zrtp_rtp_info_t* packet); + +static void _send_helloack(zrtp_stream_t* stream); +static void _send_goclearack(zrtp_stream_t* stream); + +zrtp_status_t _zrtp_machine_start_send_and_resend_hello(zrtp_stream_t* stream); +static zrtp_status_t _zrtp_machine_start_send_and_resend_goclear(zrtp_stream_t* stream); +static zrtp_status_t _zrtp_machine_start_send_and_resend_errorack(zrtp_stream_t* stream); +static zrtp_status_t _zrtp_machine_start_send_and_resend_error(zrtp_stream_t* stream); + +void _clear_stream_crypto(zrtp_stream_t* stream); + + +/*===========================================================================*/ +// MARK: ===> Main ZRTP interfaces +/*===========================================================================*/ + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_process_rtcp(zrtp_stream_t *stream, char* packet, unsigned int* length) +{ + + /* + * In transition states, drop outgoing packets. In SECURE state, encrypt + outgoing packets. In all other states leave them unchanged. + */ + + if (stream) { + switch (stream->state) + { + case ZRTP_STATE_START_INITIATINGSECURE: + case ZRTP_STATE_INITIATINGSECURE: + case ZRTP_STATE_WAIT_CONFIRM1: + case ZRTP_STATE_WAIT_CONFIRMACK: + case ZRTP_STATE_PENDINGSECURE: + case ZRTP_STATE_WAIT_CONFIRM2: + case ZRTP_STATE_PENDINGCLEAR: + return zrtp_status_drop; + + case ZRTP_STATE_SASRELAYING: + case ZRTP_STATE_SECURE: + { + zrtp_rtp_info_t info; + + if (*length < RTCP_HDR_SIZE) { + return zrtp_status_fail; + } + + zrtp_memset(&info, 0, sizeof(info)); + info.packet = packet; + info.length = length; + info.seq = 0; /*sequence number will be generated in zrtp_srtp_protect_rtcp()*/ + info.ssrc = (uint32_t) *(packet+sizeof(uint32_t)); + + return _zrtp_protocol_encrypt(stream->protocol, &info, 0); + } + + default: + return zrtp_status_ok; + } + } + + return zrtp_status_ok; +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_process_srtcp(zrtp_stream_t *stream, char* packet, unsigned int* length) +{ + + /* + * In transition states, drop incoming packets. In SECURE state, decrypt + * incoming packets. In all other states leave them unchanged. + */ + + if (stream) { + switch (stream->state) + { + case ZRTP_STATE_INITIATINGCLEAR: + case ZRTP_STATE_PENDINGCLEAR: + case ZRTP_STATE_INITIATINGSECURE: + case ZRTP_STATE_PENDINGSECURE: + return zrtp_status_drop; + + case ZRTP_STATE_SECURE: + case ZRTP_STATE_SASRELAYING: + { + zrtp_rtp_info_t info; + + if (*length < RTCP_HDR_SIZE) { + return zrtp_status_fail; + } + + zrtp_memset(&info, 0, sizeof(info)); + info.packet = packet; + info.length = length; + info.seq = 0; /*sequence number will be determined from packet in zrtp_srtp_unprotect_rtcp()*/ + info.ssrc = (uint32_t) *(packet+sizeof(uint32_t)); + + return _zrtp_protocol_decrypt(stream->protocol, &info, 0); + } + + default: + return zrtp_status_ok; + } + } + + return zrtp_status_ok; +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_process_rtp(zrtp_stream_t *stream, char* packet, unsigned int* length) +{ + zrtp_rtp_info_t info; + + if (!stream || !packet || !length) { + return zrtp_status_bad_param; + } + + /* Skip packet processing within uninitiated stream */ + if ((stream->state < ZRTP_STATE_START) || (stream->state > ZRTP_STATE_NO_ZRTP)) { + return zrtp_status_ok; + } + + /* Prepare RTP packet: detect type and other options */ + if (zrtp_status_ok != _zrtp_packet_preparse(stream, packet, length, &info, 0)) { + return zrtp_status_fail; + } + + /* Drop packets in transition states and encrypt in SECURE state */ + switch (stream->state) + { + case ZRTP_STATE_START_INITIATINGSECURE: + case ZRTP_STATE_INITIATINGSECURE: + case ZRTP_STATE_WAIT_CONFIRM1: + case ZRTP_STATE_WAIT_CONFIRMACK: + case ZRTP_STATE_PENDINGSECURE: + case ZRTP_STATE_WAIT_CONFIRM2: + case ZRTP_STATE_PENDINGCLEAR: + if (ZRTP_NONE == info.type) { + /* Add dropped media to the entropy hash */ + ZRTP_LOG(1,(_ZTU_,"Add %d bytes of entropy to the RNG pool.\n", *length)); + zrtp_entropy_add(stream->zrtp, (unsigned char*)packet, *length); + + return zrtp_status_drop; + } + break; + + case ZRTP_STATE_SASRELAYING: + case ZRTP_STATE_SECURE: + if (ZRTP_NONE == info.type) { + return _zrtp_protocol_encrypt(stream->protocol, &info, 1); + } + break; + + default: + break; + } + + return zrtp_status_ok; +} + +/*----------------------------------------------------------------------------*/ +extern int _send_message(zrtp_stream_t* stream, zrtp_msg_type_t type, const void* message, uint32_t ssrc); +zrtp_status_t zrtp_process_srtp(zrtp_stream_t *stream, char* packet, unsigned int* length) +{ + zrtp_rtp_info_t info; + zrtp_status_t s = zrtp_status_ok; + + if (!stream || !packet || !length) { + return zrtp_status_bad_param; + } + + if (*length <= RTP_HDR_SIZE) { + return zrtp_status_bad_param; + } + + /* Preparse RTP packet: detect type and other options */ + s = _zrtp_packet_preparse(stream, packet, length, &info, 1); + if (zrtp_status_ok != s) { + return s; + } + + /*************************************************************************/ + /* For Zfone3 Compatibility */ + if (ZRTP_ZFONEPING == info.type) { + zrtp_packet_zfoneping_t* ping = (zrtp_packet_zfoneping_t*) info.message; + zrtp_packet_zfonepingack_t pingack; + + zrtp_memcpy(pingack.version, ZRTP_ZFONE_PROTOCOL_VERSION, 4); + zrtp_memcpy(pingack.endpointhash, stream->session->zid.buffer, sizeof(pingack.endpointhash)); + zrtp_memcpy(pingack.peerendpointhash, ping->endpointhash, sizeof(pingack.endpointhash)); + pingack.peerssrc = info.ssrc; + + _zrtp_packet_fill_msg_hdr( stream, + ZRTP_ZFONEPINGACK, + sizeof(zrtp_packet_zfonepingack_t) - sizeof(zrtp_msg_hdr_t), + &pingack.hdr); + + _zrtp_packet_send_message(stream, ZRTP_ZFONEPINGACK, &pingack); + return zrtp_status_drop; + } + /*************************************************************************/ + + /* Skip packet processing within non-started stream */ + if ((stream->state < ZRTP_STATE_START) || (stream->state > ZRTP_STATE_NO_ZRTP)) { + return (ZRTP_NONE == info.type) ? zrtp_status_ok : zrtp_status_drop; + } + + /* + * This mutex should protect stream data against asynchr. calls e.g.: + * zrtp_stream_secure(), zrtp_stream_clear() etc. Media packet handlers + * don't change any internal data, so this applies only to ZRTP messages. + */ + if (info.type != ZRTP_NONE) { + zrtp_mutex_lock(stream->stream_protector); + } + + /* Extra protection. We need protocol to handle ZRTP messages in following states. */ + switch (stream->state) + { + case ZRTP_STATE_INITIATINGSECURE: + case ZRTP_STATE_WAIT_CONFIRM1: + case ZRTP_STATE_WAIT_CONFIRMACK: + case ZRTP_STATE_PENDINGSECURE: + case ZRTP_STATE_WAIT_CONFIRM2: + case ZRTP_STATE_SECURE: + case ZRTP_STATE_SASRELAYING: + if (!stream->protocol) { + if (info.type != ZRTP_NONE) { + zrtp_mutex_unlock(stream->stream_protector); + } + return zrtp_status_fail; + } + default: + break; + } + + /* Handle Error packet from any state */ + if (ZRTP_ERROR == info.type && stream->state > ZRTP_STATE_START) + { + switch (stream->state) + { + case ZRTP_STATE_NONE: + case ZRTP_STATE_ACTIVE: + case ZRTP_STATE_SECURE: + case ZRTP_STATE_PENDINGERROR: + case ZRTP_STATE_INITIATINGERROR: + case ZRTP_STATE_NO_ZRTP: + break; + default: + { + zrtp_packet_Error_t* error = (zrtp_packet_Error_t*) info.message; + _zrtp_machine_enter_pendingerror(stream, zrtp_ntoh32(error->code)); + } break; + } + } + + /* Process packet by state-machine according to packet type and current protocol state */ + if (state_handler[stream->state]) { + s = state_handler[stream->state](stream, &info); + } + + /* Unlock stream mutex for a ZRTP message packet. See comments above. */ + if (info.type != ZRTP_NONE) { + s = zrtp_status_drop; + zrtp_mutex_unlock(stream->stream_protector); + } + + return s; +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_stream_start(zrtp_stream_t* stream, uint32_t ssrc) +{ + zrtp_status_t s = zrtp_status_ok; + /* + * (ZRTP stream starts from START state and HELLO packets resending. + * Stream can be started from START, ERROR or NOZRTP states only.) + */ + ZRTP_LOG(3,(_ZTU_,"START STREAM ID=%u mode=%s state=%s.\n", + stream->id, zrtp_log_mode2str(stream->mode), zrtp_log_state2str(stream->state))); + + if ( (ZRTP_STATE_ACTIVE != stream->state) && + (ZRTP_STATE_ERROR != stream->state) && + (ZRTP_STATE_NO_ZRTP != stream->state)) { + ZRTP_LOG(1,(_ZTU_,"ERROR! Can't start Stream ID=%u from %s state.\n", + stream->id, zrtp_log_state2str(stream->state))); + s = zrtp_status_wrong_state; + } else { + stream->media_ctx.ssrc = zrtp_hton32(ssrc); + + _zrtp_change_state(stream, ZRTP_STATE_START); + _zrtp_machine_start_send_and_resend_hello(stream); + } + + return s; +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_stream_stop(zrtp_stream_t* stream) +{ + zrtp_status_t s = zrtp_status_ok; + /* + * Stop all packet replays, deinitialize crypto data and prepare the stream + * for the next use. The stream can be terminated from any protocol state. + */ + ZRTP_LOG(3,(_ZTU_,"STOP STREAM ID=%u mode=%s state=%s.\n", + stream->id, zrtp_log_mode2str(stream->mode), zrtp_log_state2str(stream->state))); + + if (stream->state != ZRTP_STATE_NONE) { + /* + * This function can be called in parallel to the main processing loop + * - protect internal stream data. + */ + zrtp_mutex_lock(stream->stream_protector); + + _zrtp_cancel_send_packet_later(stream, ZRTP_NONE); + if (stream->zrtp->cb.sched_cb.on_wait_call_later) { + stream->zrtp->cb.sched_cb.on_wait_call_later(stream); + } + + _clear_stream_crypto(stream); + + zrtp_mutex_unlock(stream->stream_protector); + zrtp_mutex_destroy(stream->stream_protector); + + zrtp_memset(stream, 0, sizeof(zrtp_stream_t)); + stream->mode = ZRTP_STREAM_MODE_UNKN; + _zrtp_change_state(stream, ZRTP_STATE_NONE); + } else { + s = zrtp_status_wrong_state; + } + + return s; +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_stream_clear(zrtp_stream_t *stream) +{ + /* + * This function can be called for two reasons: either our user is + * initiating the go-clear ritual or we accepting that ritual as + * initiated by the other end of the line. If our user initiates the + * go-clear process libzrtp switches to INITIATING_CLEAR and runs + * GoClear replays. The go-clear ritual can be started from SECURE state + * only. If the other end of the line is initiating and this function is + * being called to accept the go-clear procedure - protocol transites to + * CLEAR state imediately. One can accept go-clear from PENDING CLEAR + * state only. See state-macine diagram for more information. + */ + zrtp_status_t s = zrtp_status_fail; + + /* This function can be called in parallel to the main processing loop - protect stream data. */ + zrtp_mutex_lock(stream->stream_protector); + + ZRTP_LOG(3,(_ZTU_,"CLEAR STREAM ID=%u mode=%s state=%s.\n", + stream->id, zrtp_log_mode2str(stream->mode), zrtp_log_state2str(stream->state))); + + switch (stream->state) + { + case ZRTP_STATE_SECURE: + /* Clearing ritual can't be started if "allow clear" is disabled */ + if (stream->session->profile.allowclear) { + s = _zrtp_machine_enter_initiatingclear(stream); + } + break; + case ZRTP_STATE_PENDINGCLEAR: + s = _zrtp_machine_enter_clear(stream); + break; + default: + break; + } + + zrtp_mutex_unlock(stream->stream_protector); + + return s; +} + +/*----------------------------------------------------------------------------*/ +void _initiating_secure(zrtp_stream_t *stream, zrtp_retry_task_t* task) +{ + /* + * In accordance with the ZRTP standard, there can be multiple simultaneous + * DH streams, as well as preshared streams. + * + * Before entering the INITIATING_SECURE state, we check several conditions. + * For details see \doc\img\odg\zrtp_streams.odg and zrtp_statemach.odg) + */ + + /* The first call to this function is already protected by a mutex in zrtp_process_srtp() */ + uint8_t use_mutex = (task->_retrys > 0); + + if (!task->_is_enabled) { + return; + } + + if (use_mutex) { + zrtp_mutex_lock(stream->stream_protector); + } + + ZRTP_LOG(3,(_ZTU_,"\tInitiating Secure iteration... ID=%u.\n", stream->id)); + + /* Skip the last replay after switching to another state to avoid unwanted replays */ + if (stream->state <= ZRTP_STATE_START_INITIATINGSECURE) + { + stream->mode = _zrtp_define_stream_mode(stream); + ZRTP_LOG(3,(_ZTU_,"\tGot mode=%s. Check approval of starting.\n", zrtp_log_mode2str(stream->mode))); + if (!_zrtp_can_start_stream(stream, &stream->concurrent, stream->mode)) + { + if (task->_retrys > ZRTP_PROCESS_T1_MAX_COUNT) { + ZRTP_LOG(3,(_ZTU_,"\tInitiating Secure. Max retransmissions count reached" + "for stream ID=%u.\n", stream->id)); + + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_timeout, 0); + } else { + ZRTP_LOG(3,(_ZTU_,"\tInitiating Secure. stream ID=%u is DH but one more DH" + " stream is in progress - waiting...\n", stream->id)); + + task->_retrys++; + if (stream->zrtp->cb.sched_cb.on_call_later) { + stream->zrtp->cb.sched_cb.on_call_later(stream, task); + } + } + } + else + { + ZRTP_LOG(3,(_ZTU_,"\tMode=%s Cccepted. Starting ZRTP Initiator Protocol.\n", zrtp_log_mode2str(stream->mode))); + _zrtp_cancel_send_packet_later(stream, ZRTP_PROCESS); + _zrtp_machine_enter_initiatingsecure(stream); + } + } + + if (use_mutex) { + zrtp_mutex_unlock(stream->stream_protector); + } +} + +zrtp_status_t _zrtp_machine_start_initiating_secure(zrtp_stream_t *stream) +{ + /* + * This function creates a task to do retries of the first packet in the + * "Going secure" procedure, and then _initiating_secure() will start + * protocol. + */ + zrtp_retry_task_t* task = &stream->messages.dh_task; + task->_is_enabled = 1; + task->_retrys = 0; + task->callback = _initiating_secure; + task->timeout = ZRTP_PROCESS_T1; + + /* + * Prevent race conditions on starting multiple streams. + */ + zrtp_mutex_lock(stream->session->init_protector); + + _zrtp_change_state(stream, ZRTP_STATE_START_INITIATINGSECURE); + _initiating_secure(stream, task); + + zrtp_mutex_unlock(stream->session->init_protector); + + return zrtp_status_ok; +} + + +zrtp_status_t zrtp_stream_secure(zrtp_stream_t *stream) +{ + /* + * Wrapper function for going into secure mode. It can be initiated in + * parallel to the main processing loop. The internal stream data has to + * be protected by mutex. + */ + + zrtp_status_t s = zrtp_status_fail; + + ZRTP_LOG(3,(_ZTU_,"SECURE STREAM ID=%u mode=%s state=%s.\n", + stream->id, zrtp_log_mode2str(stream->mode), zrtp_log_state2str(stream->state))); + + zrtp_mutex_lock(stream->stream_protector); + + /* Limit ZRTP Session initiation procedure according to the license */ + if ( (stream->state == ZRTP_STATE_CLEAR) && ZRTP_PASSIVE1_TEST(stream)) { + s = _zrtp_machine_start_initiating_secure(stream); + } else { + ZRTP_LOG(1,(_ZTU_,"\tWARNING! Can't Start Stream from %s state and with %d license mode. ID=%u\n", + zrtp_log_state2str(stream->state), stream->zrtp->lic_mode, stream->id)); + + if (!ZRTP_PASSIVE1_TEST(stream)) { + if (stream->zrtp->cb.event_cb.on_zrtp_protocol_event ) { + stream->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_IS_PASSIVE_RESTRICTION); + } + } + } + + zrtp_mutex_unlock(stream->stream_protector); + + return s; +} + + +/*===========================================================================*/ +/* State handlers */ +/*===========================================================================*/ + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_while_in_start( zrtp_stream_t* stream, + zrtp_rtp_info_t* packet) +{ + zrtp_status_t s = zrtp_status_ok; + + switch (packet->type) + { + case ZRTP_HELLO: + s = _zrtp_machine_process_hello(stream, packet); + if (zrtp_status_ok != s) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! _zrtp_machine_process_hello() failed with status=%d. ID=%u\n", s, stream->id)); + break; /* Just stay in START state. */ + } + + /* Now we have ZIDs for both sides and can upload secrets from the cache */ + s = _zrtp_prepare_secrets(stream->session); + if (zrtp_status_ok != s) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! _zrtp_prepare_secrets() failed with status=%d. ID=%u\n", s, stream->id)); + break; /* Just stay in START state. */ + } + + _send_helloack(stream); + _zrtp_change_state(stream, ZRTP_STATE_WAIT_HELLOACK); + break; + + case ZRTP_HELLOACK: + _zrtp_cancel_send_packet_later(stream, ZRTP_HELLO); + _zrtp_change_state(stream, ZRTP_STATE_WAIT_HELLO); + break; + + default: + break; + } + + return s; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_while_in_wait4hello( zrtp_stream_t* stream, + zrtp_rtp_info_t* packet) +{ + zrtp_status_t s = zrtp_status_ok; + + switch (packet->type) + { + case ZRTP_HELLO: + s = _zrtp_machine_process_hello(stream, packet); + if (zrtp_status_ok != s) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! _zrtp_machine_process_hello()2 failed with status=%d. ID=%u\n", s, stream->id)); + break; /* Just stay in the current state. */ + } + + /* Now we have ZIDs for both sides and can upload secrets from the cache */ + s = _zrtp_prepare_secrets(stream->session); + if (zrtp_status_ok != s) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! _zrtp_prepare_secrets()2 failed with status=%d. ID=%u\n", s, stream->id)); + break; /* Just stay in the current state. */ + } + + /* Start initiating the secure state if "autosecure" is enabled */ + if ((stream->session->profile.autosecure) && ZRTP_PASSIVE1_TEST(stream)) { + if (!stream->session->profile.discovery_optimization) { + _send_helloack(stream); /* Response with HelloAck before start computing DH value */ + } + s = _zrtp_machine_start_initiating_secure(stream); + } else { + _send_helloack(stream); + + if (!ZRTP_PASSIVE1_TEST(stream)) { + if (stream->zrtp->cb.event_cb.on_zrtp_protocol_event) { + stream->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_IS_PASSIVE_RESTRICTION); + } + } + + s = _zrtp_machine_enter_clear(stream); + } + + break; + + default: + break; + } + + return s; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_while_in_wait4helloack( zrtp_stream_t* stream, + zrtp_rtp_info_t* packet) +{ + zrtp_status_t status = zrtp_status_ok; + + switch (packet->type) + { + case ZRTP_HELLO: + _send_helloack(stream); + break; + + case ZRTP_COMMIT: + { + /* Passive Initiator can't talk to anyone */ + if (ZRTP_PASSIVE2_TEST(stream)) + { + zrtp_statemachine_type_t role = _zrtp_machine_preparse_commit(stream, packet); + if (ZRTP_STATEMACHINE_RESPONDER == role) { + _zrtp_cancel_send_packet_later(stream, ZRTP_HELLO); + status = _zrtp_machine_enter_pendingsecure(stream, packet); + } else if (ZRTP_STATEMACHINE_INITIATOR == role) { + _zrtp_cancel_send_packet_later(stream, ZRTP_HELLO); + status = _zrtp_machine_start_initiating_secure(stream); + } else { + status = zrtp_status_fail; + } + } else { + ZRTP_LOG(2,(_ZTU_,"\tERROR: The endpoint is in passive mode and Signaling Initiator -" + " can't handle connections from anyone. ID=%u\n", stream->id)); + if (stream->zrtp->cb.event_cb.on_zrtp_protocol_event) { + stream->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_IS_PASSIVE_RESTRICTION); + } + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_service_unavail, 1); + } + } break; + + case ZRTP_HELLOACK: + _zrtp_cancel_send_packet_later(stream, ZRTP_HELLO); + + /* Start initiating the secure state if "autosecure" is enabled */ + if ((stream->session->profile.autosecure) && ZRTP_PASSIVE1_TEST(stream)) { + status = _zrtp_machine_start_initiating_secure(stream); + } else { + if (!ZRTP_PASSIVE1_TEST(stream)) { + if (stream->zrtp->cb.event_cb.on_zrtp_protocol_event) { + stream->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_IS_PASSIVE_RESTRICTION); + } + } + status = _zrtp_machine_enter_clear(stream); + } + + break; + + default: + break; + } + + return status; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_while_in_clear( zrtp_stream_t* stream, + zrtp_rtp_info_t* packet) +{ + zrtp_status_t s = zrtp_status_ok; + + switch (packet->type) + { + case ZRTP_GOCLEAR: + _send_goclearack(stream); + break; + + case ZRTP_HELLO: + _send_helloack(stream); + break; + + case ZRTP_COMMIT: + { + zrtp_statemachine_type_t role = _zrtp_machine_preparse_commit(stream, packet); + if (ZRTP_STATEMACHINE_RESPONDER == role) { + s = _zrtp_machine_enter_pendingsecure(stream, packet); + } else if (ZRTP_STATEMACHINE_INITIATOR == role) { + s = _zrtp_machine_start_initiating_secure(stream); + } else { + s = zrtp_status_fail; + } + } break; + + default: + break; + } + + return s; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_while_in_initiatingclear( zrtp_stream_t* stream, + zrtp_rtp_info_t* packet) +{ + zrtp_status_t s = zrtp_status_ok; + + switch (packet->type) + { + case ZRTP_GOCLEARACK: + case ZRTP_COMMIT: + s = _zrtp_machine_enter_clear(stream); + break; + + case ZRTP_NONE: + s = zrtp_status_drop; + break; + + default: + break; + } + + return s; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_while_in_pendingclear( zrtp_stream_t* stream, + zrtp_rtp_info_t* packet) +{ + zrtp_status_t s = zrtp_status_ok; + + switch (packet->type) + { + case ZRTP_GOCLEAR: + _send_goclearack(stream); + break; + + case ZRTP_COMMIT: + { + zrtp_statemachine_type_t role = _zrtp_machine_preparse_commit(stream, packet); + if (ZRTP_STATEMACHINE_RESPONDER == role) { + s = _zrtp_machine_enter_pendingsecure(stream, packet); + } else if (ZRTP_STATEMACHINE_INITIATOR == role) { + s = _zrtp_machine_start_initiating_secure(stream); + } else { + s = zrtp_status_fail; + } + } break; + + default: + break; + } + + return s; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_while_in_start_initiatingsecure( zrtp_stream_t* stream, + zrtp_rtp_info_t* packet) +{ + zrtp_status_t s = zrtp_status_ok; + + switch (packet->type) + { + case ZRTP_HELLO: + _send_helloack(stream); + break; + + case ZRTP_COMMIT: + { + zrtp_statemachine_type_t role = _zrtp_machine_preparse_commit(stream, packet); + if (ZRTP_STATEMACHINE_RESPONDER == role) { + _zrtp_cancel_send_packet_later(stream, ZRTP_PROCESS); + s = _zrtp_machine_enter_pendingsecure(stream, packet); + } else { + s = zrtp_status_fail; + } + } break; + + default: + break; + } + + return s; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_while_in_secure( zrtp_stream_t* stream, + zrtp_rtp_info_t* packet) +{ + zrtp_status_t s = zrtp_status_ok; + + switch (packet->type) + { + case ZRTP_CONFIRM2: + _zrtp_packet_send_message(stream, ZRTP_CONFIRM2ACK, NULL); + break; + + case ZRTP_SASRELAY: + /* + * _zrtp_machine_process_sasrelay() updates SAS, sends events and does + * other things if SAS transferring is allowed + */ + s = _zrtp_machine_process_sasrelay(stream, packet); + if (zrtp_status_ok == s) { + _zrtp_packet_send_message(stream, ZRTP_RELAYACK, NULL); + } + break; + + case ZRTP_GOCLEAR: + s = _zrtp_machine_process_goclear(stream, packet); + if (zrtp_status_ok == s) { + s = _zrtp_machine_enter_pendingclear(stream); + _send_goclearack(stream); + } + break; + + case ZRTP_NONE: + s = _zrtp_protocol_decrypt(stream->protocol, packet, 1); + break; + + default: + break; + } + + return s; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_while_in_initiatingerror( zrtp_stream_t* stream, + zrtp_rtp_info_t* packet) +{ + switch (packet->type) + { + case ZRTP_ERROR: + _zrtp_machine_enter_pendingerror(stream, ((zrtp_packet_Error_t*) packet->message)->code ); + break; + + case ZRTP_ERRORACK: + _zrtp_machine_switch_to_error(stream); + break; + + default: + break; + } + + return zrtp_status_ok; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_while_in_nozrtp( zrtp_stream_t* stream, + zrtp_rtp_info_t* packet) +{ + zrtp_status_t s = zrtp_status_ok; + + switch (packet->type) + { + case ZRTP_HELLO: + s = _zrtp_machine_process_hello(stream, packet); + if (zrtp_status_ok != s) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! _zrtp_machine_process_hello()3 failed with status=%d ID=%u.\n", s, stream->id)); + break; + } + + _zrtp_change_state(stream, ZRTP_STATE_START); + _zrtp_machine_start_send_and_resend_hello(stream); + break; + + case ZRTP_COMMIT: /* this logic should be similar to Commit handler in ZRTP_STATE_WAIT_HELLOACK state */ + { + /* Passive Initiator can't talk to anyone */ + if (ZRTP_PASSIVE2_TEST(stream)) + { + zrtp_statemachine_type_t role = _zrtp_machine_preparse_commit(stream, packet); + if (ZRTP_STATEMACHINE_RESPONDER == role) { + s = _zrtp_machine_enter_pendingsecure(stream, packet); + } else if (ZRTP_STATEMACHINE_INITIATOR == role) { + s = _zrtp_machine_start_initiating_secure(stream); + } else { + s = zrtp_status_fail; + } + } else { + ZRTP_LOG(2,(_ZTU_,"\tERROR: The endpoint is in passive mode and Signaling Initiator -" + " can't handle connections from anyone. ID=%u\n", stream->id)); + if (stream->zrtp->cb.event_cb.on_zrtp_protocol_event ) { + stream->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_IS_PASSIVE_RESTRICTION); + } + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_service_unavail, 1); + } + } break; + + default: + break; + } + + return s; +} + + +/* Initiator logic */ +extern zrtp_status_t _zrtp_machine_process_while_in_initiatingsecure(zrtp_stream_t* stream, zrtp_rtp_info_t* packet); +extern zrtp_status_t _zrtp_machine_process_while_in_waitconfirmack(zrtp_stream_t* stream, zrtp_rtp_info_t* packet); +extern zrtp_status_t _zrtp_machine_process_while_in_waitconfirm1(zrtp_stream_t* stream, zrtp_rtp_info_t* packet); + +/* Responder logic */ +extern zrtp_status_t _zrtp_machine_process_while_in_pendingsecure(zrtp_stream_t* stream, zrtp_rtp_info_t* packet); +extern zrtp_status_t _zrtp_machine_process_while_in_waitconfirm2(zrtp_stream_t* stream, zrtp_rtp_info_t* packet); + +/* PBX transferring logic */ +extern zrtp_status_t _zrtp_machine_process_while_in_sasrelaying(zrtp_stream_t* stream, zrtp_rtp_info_t* packet); + +#if (defined(ZRTP_BUILD_FOR_CSD) && (ZRTP_BUILD_FOR_CSD == 1)) +/* Driven Discovery state-machine */ +extern zrtp_status_t _zrtp_machine_process_while_in_driven_initiator(zrtp_stream_t* stream, zrtp_rtp_info_t* packet); +extern zrtp_status_t _zrtp_machine_process_while_in_driven_responder(zrtp_stream_t* stream, zrtp_rtp_info_t* packet); +extern zrtp_status_t _zrtp_machine_process_while_in_driven_pending(zrtp_stream_t* stream, zrtp_rtp_info_t* packet); +#endif + +state_handler_t* state_handler[ZRTP_STATE_COUNT] = +{ + NULL, + NULL, + _zrtp_machine_process_while_in_start, + _zrtp_machine_process_while_in_wait4helloack, + _zrtp_machine_process_while_in_wait4hello, + _zrtp_machine_process_while_in_clear, + _zrtp_machine_process_while_in_start_initiatingsecure, + _zrtp_machine_process_while_in_initiatingsecure, + _zrtp_machine_process_while_in_waitconfirm1, + _zrtp_machine_process_while_in_waitconfirmack, + _zrtp_machine_process_while_in_pendingsecure, + _zrtp_machine_process_while_in_waitconfirm2, + _zrtp_machine_process_while_in_secure, + _zrtp_machine_process_while_in_sasrelaying, + _zrtp_machine_process_while_in_initiatingclear, + _zrtp_machine_process_while_in_pendingclear, + _zrtp_machine_process_while_in_initiatingerror, + NULL, + NULL, +#if (defined(ZRTP_BUILD_FOR_CSD) && (ZRTP_BUILD_FOR_CSD == 1)) + _zrtp_machine_process_while_in_driven_initiator, + _zrtp_machine_process_while_in_driven_responder, + _zrtp_machine_process_while_in_driven_pending, +#endif + _zrtp_machine_process_while_in_nozrtp +}; + + +/*===========================================================================*/ +/* State switchers */ +/*===========================================================================*/ + +static void _zrtp_machine_switch_to_error(zrtp_stream_t* stream) +{ + _zrtp_cancel_send_packet_later(stream, ZRTP_NONE); + _clear_stream_crypto(stream); + + _zrtp_change_state(stream, ZRTP_STATE_ERROR); + + if (stream->zrtp->cb.event_cb.on_zrtp_security_event) { + stream->zrtp->cb.event_cb.on_zrtp_security_event(stream, ZRTP_EVENT_PROTOCOL_ERROR); + } + if (stream->zrtp->cb.event_cb.on_zrtp_not_secure) { + stream->zrtp->cb.event_cb.on_zrtp_not_secure(stream); + } + stream->last_error = 0; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_enter_pendingclear(zrtp_stream_t* stream) +{ + _zrtp_cancel_send_packet_later(stream, ZRTP_NONE); + _zrtp_change_state(stream, ZRTP_STATE_PENDINGCLEAR); + + /* + * We have to destroy the ZRTP Session Key because user may not press "clear + * button", and the remote endpoint may subsequently initiate a new secure + * session. Other secret values will be destroyed in Clear state or + * rewritten with new. + */ + { + zrtp_string64_t new_zrtpsess = ZSTR_INIT_EMPTY(new_zrtpsess); + // TODO: hash + stream->session->hash->hash( stream->session->hash, + ZSTR_GV(stream->session->zrtpsess), + ZSTR_GV(new_zrtpsess)); + zrtp_zstrcpy(ZSTR_GV(stream->session->zrtpsess), ZSTR_GV(new_zrtpsess)); + } + + if (stream->zrtp->cb.event_cb.on_zrtp_protocol_event) { + stream->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_IS_PENDINGCLEAR); + } + + return zrtp_status_ok; +} + +/*---------------------------------------------------------------------------*/ +static zrtp_status_t _zrtp_machine_enter_initiatingclear(zrtp_stream_t* stream) +{ + + _zrtp_cancel_send_packet_later(stream, ZRTP_NONE); + _zrtp_change_state(stream, ZRTP_STATE_INITIATINGCLEAR); + + { + zrtp_string64_t new_zrtpsess = ZSTR_INIT_EMPTY(new_zrtpsess); + // TODO: hash + stream->session->hash->hash( stream->session->hash, + ZSTR_GV(stream->session->zrtpsess), + ZSTR_GV(new_zrtpsess)); + zrtp_zstrcpy(ZSTR_GV(stream->session->zrtpsess), ZSTR_GV(new_zrtpsess)); + } + + return _zrtp_machine_start_send_and_resend_goclear(stream); +} + +/*---------------------------------------------------------------------------*/ +static zrtp_status_t _zrtp_machine_enter_clear(zrtp_stream_t* stream) +{ + _zrtp_cancel_send_packet_later(stream, ZRTP_NONE); + _clear_stream_crypto(stream); + _zrtp_change_state(stream, ZRTP_STATE_CLEAR); + + if (stream->zrtp->cb.event_cb.on_zrtp_protocol_event) { + stream->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_IS_CLEAR); + } + + return zrtp_status_ok; +} + + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_enter_initiatingerror( zrtp_stream_t *stream, + zrtp_protocol_error_t code, + uint8_t notif) +{ + if ( (ZRTP_STATE_ERROR != stream->state) && + (ZRTP_STATE_INITIATINGERROR != stream->state) && + (ZRTP_STATE_PENDINGERROR != stream->state) ) + { + stream->last_error = code; + + ZRTP_LOG(3,(_ZTU_,"\tEnter InitiatingError State with ERROR:<%s>, notification %s. ID=%u\n", + zrtp_log_error2str(stream->last_error), (notif?"Enabled":"Disabled"), stream->id)); + + /* If we can't deliver a ZRTP message, just switch to the ERROR state. */ + if (notif) { + _zrtp_cancel_send_packet_later(stream, ZRTP_NONE); + _zrtp_change_state(stream, ZRTP_STATE_INITIATINGERROR); + _zrtp_machine_start_send_and_resend_error(stream); + } else { + _zrtp_machine_switch_to_error(stream); + } + } + + return zrtp_status_ok; +} + +zrtp_status_t _zrtp_machine_enter_pendingerror(zrtp_stream_t *stream, zrtp_protocol_error_t code) +{ + ZRTP_LOG(3,(_ZTU_,"\tEnter PendingError State with ERROR:<%s>. ID=%u\n", + zrtp_log_error2str(stream->last_error), stream->id)); + + _zrtp_cancel_send_packet_later(stream, ZRTP_NONE); + _zrtp_change_state(stream, ZRTP_STATE_PENDINGERROR); + + stream->last_error = code; + _zrtp_machine_start_send_and_resend_errorack(stream); + return zrtp_status_ok; +} + + +/*===========================================================================*/ +/* Packet handlers */ +/*===========================================================================*/ + +zrtp_status_t _zrtp_machine_process_goclear(zrtp_stream_t* stream, zrtp_rtp_info_t* packet) +{ + zrtp_packet_GoClear_t *goclear = (zrtp_packet_GoClear_t*) packet->message; + zrtp_string128_t clear_hmac = ZSTR_INIT_EMPTY(clear_hmac); + static const zrtp_string16_t clear_hmac_str = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_CLEAR_HMAC_STR); + + if (!stream->allowclear) { + ZRTP_LOG(2, (_ZTU_,"\tWARNING! Allowclear is disabled but GoClear was received. ID=%u.\n", stream->id)); + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_goclear_unsp, 1); + return zrtp_status_fail; + } + + stream->session->hash->hmac( stream->session->hash, + ZSTR_GV(stream->cc.peer_hmackey), + ZSTR_GV(clear_hmac_str), + ZSTR_GV(clear_hmac)); + clear_hmac.length = ZRTP_HMAC_SIZE; + + if (0 != zrtp_memcmp(clear_hmac.buffer, goclear->clear_hmac, ZRTP_HMAC_SIZE)) { + ZRTP_LOG(2, (_ZTU_,"\tWARNING! Wrong GoClear hmac. ID=%u.\n", stream->id)); + return zrtp_status_fail; /* EH: Just ignore malformed packets */ + } + + return zrtp_status_ok; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_hello(zrtp_stream_t* stream, zrtp_rtp_info_t* packet) +{ + zrtp_session_t* session = stream->session; + zrtp_packet_Hello_t* peer_hello = NULL; + uint32_t comp_block_len = 0; + uint8_t id = 0; + + /* Size of HELLO packet must be bigger then . */ + if (*(packet->length) < (ZRTP_MIN_PACKET_LENGTH + ZRTP_HELLO_STATIC_SIZE + ZRTP_HMAC_SIZE)) { + ZRTP_LOG(2,(_ZTU_,"\tWARNING! Wrong HELLO static size=%d must be=%d. ID=%u\n", *packet->length, + ZRTP_MIN_PACKET_LENGTH + ZRTP_HELLO_STATIC_SIZE + ZRTP_HMAC_SIZE, stream->id)); + + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_invalid_packet, 1); + return zrtp_status_fail; + } + + peer_hello = (zrtp_packet_Hello_t*) packet->message; + + /* Now we can verify packet size according to size of its parts */ + comp_block_len = ( peer_hello->hc + peer_hello->cc + + peer_hello->ac + peer_hello->kc + + peer_hello->sc) * ZRTP_COMP_TYPE_SIZE; + + if (*packet->length < (ZRTP_MIN_PACKET_LENGTH + ZRTP_HELLO_STATIC_SIZE + comp_block_len + ZRTP_HMAC_SIZE)) + { + ZRTP_LOG(2,(_ZTU_,"\tWARNING! Wrong HELLO dynamic size=%d must be=%d. ID=%u\n", *packet->length, + comp_block_len+ ZRTP_MIN_PACKET_LENGTH + ZRTP_HELLO_STATIC_SIZE + ZRTP_HMAC_SIZE, stream->id)); + + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_invalid_packet, 1); + return zrtp_status_fail; + } + + /* Every component quantity must be less than or equal to 7 */ + if ( (peer_hello->hc > ZRTP_MAX_COMP_COUNT) || (peer_hello->cc > ZRTP_MAX_COMP_COUNT) || + (peer_hello->ac > ZRTP_MAX_COMP_COUNT) || (peer_hello->kc > ZRTP_MAX_COMP_COUNT) || + (peer_hello->sc > ZRTP_MAX_COMP_COUNT) ) + { + ZRTP_LOG(2,(_ZTU_,"\tWARNING! Wrong HELLO packet data. Components count can't be greater" + " then 7. ID=%u\n", stream->id)); + + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_invalid_packet, 1); + return zrtp_status_fail; + } + + /* Print out ZRTP Hello message for debug purposes */ + { + char print_buffer[ZRTP_MAX_COMP_COUNT*20]; + zrtp_memcpy(print_buffer, peer_hello->comp, comp_block_len); + print_buffer[comp_block_len] = 0; + ZRTP_LOG(3,(_ZTU_,"\tProcessing HELLO from %.16s V=%.4s, P=%d, M=%d.\n", + peer_hello->cliend_id, peer_hello->version, peer_hello->pasive, peer_hello->mitmflag)); + ZRTP_LOG(3,(_ZTU_,"\t\tac=%d cc=%d sc=%d kc=%d\n", + peer_hello->ac, peer_hello->cc, peer_hello->sc, peer_hello->kc)); + ZRTP_LOG(3,(_ZTU_,"\t\t%s\n", print_buffer)); + } + + /* + * Check protocol version. Try to resolve versions missmatch according to ZRTP Draft sec. 5.1 + */ + { + uint32_t peer_version = 0; + peer_version = (char)((*peer_hello->version) - '0') *10; /* only 3 first octets are significant */ + peer_version += (char)(*(peer_hello->version+2) - '0'); + + if ((ZRTP_PROTOCOL_VERSION_VALUE/10) == peer_version) { + ZRTP_LOG(3,(_ZTU_,"\tReceived HELLO had the same protocol V.\n")); + } + else if ((ZRTP_PROTOCOL_VERSION_VALUE/10) < peer_version) { + ZRTP_LOG(2,(_ZTU_,"\tWARNING! Received HELLO greater ZRTP V=%d - wait for other party" + " to resolve this issue. ID=%u.\n", peer_version, stream->id)); + } else { + ZRTP_LOG(2,(_ZTU_,"\tWARNING! Received a ZRTP_HELLO smaller ZRTP V=%d and we don't" + " support it - terminate session. ID=%u\n", peer_version, stream->id)); + + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_version, 1); + return zrtp_status_fail; + } + } + + /* Close session if ZID duplication */ + if (!zrtp_memcmp(stream->messages.hello.zid, peer_hello->zid, sizeof(zrtp_zid_t))) { + ZRTP_LOG(2,(_ZTU_,ZRTP_EQUAL_ZID_WARNING_STR)); + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_equal_zid, 1); + return zrtp_status_fail; + } + + /* All streams within a single session MUST have the same ZID */ + if (session->peer_zid.length > 0) { + if (0 != zrtp_memcmp(session->peer_zid.buffer, peer_hello->zid, sizeof(zrtp_zid_t))) { + ZRTP_LOG(2,(_ZTU_,"\tWARNING! Received HELLO which had a different ZID from that of the" + " previous stream within the same session. sID=%u ID=%u\n", session->id, stream->id)); + + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_wrong_zid, 1); + return zrtp_status_fail; + } + } else { + zrtp_zstrncpyc(ZSTR_GV(session->peer_zid), (const char*) peer_hello->zid, sizeof(zrtp_zid_t)); + } + + /* Remember remote Passive flag */ + stream->peer_passive = peer_hello->pasive; + stream->peer_mitm_flag = peer_hello->mitmflag; + if (stream->peer_mitm_flag) { + stream->mitm_mode = ZRTP_MITM_MODE_CLIENT; + } + + /* Current version doesn't support Digital Signatures. Ignore peer Hello with S flag enabled. */ + if (peer_hello->sigflag) { + ZRTP_LOG(2,(_ZTU_,"\tWARNING! Received a ZRTP_HELLO with S flag enabled. We don't support Digital Signatures - ignore message.\n")); + return zrtp_status_fail; + } + + /* Copy packet for future hashing */ + zrtp_memcpy(&stream->messages.peer_hello, peer_hello, zrtp_ntoh16(peer_hello->hdr.length)*4); + + /* + * Choose PK exchange scheme and PK mode. + * We do this right after receiving Hello to speedup DH calculations. + */ + stream->pubkeyscheme = zrtp_comp_find(ZRTP_CC_PKT, ZRTP_PKTYPE_DH3072, session->zrtp); + id = _zrtp_choose_best_comp(&session->profile, peer_hello, ZRTP_CC_PKT); + if (id != ZRTP_COMP_UNKN) { + stream->pubkeyscheme = zrtp_comp_find(ZRTP_CC_PKT, id, session->zrtp); + } + + ZRTP_LOG(3,(_ZTU_,"\tReceived HELLO Accepted\n")); + + return zrtp_status_ok; +} + + +/*===========================================================================*/ +/* Packet senders */ +/*===========================================================================*/ + +/*---------------------------------------------------------------------------*/ +static void _send_and_resend_hello(zrtp_stream_t* stream, zrtp_retry_task_t* task) +{ + if (task->_retrys == ZRTP_NO_ZRTP_FAST_COUNT) { + ZRTP_LOG(2,(_ZTU_,"WARNING! HELLO have been resent %d times without a response." + " Raising ZRTP_EVENT_NO_ZRTP_QUICK event. ID=%u\n", task->_retrys, stream->id)); + + if (stream->zrtp->cb.event_cb.on_zrtp_protocol_event) { + stream->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_NO_ZRTP_QUICK); + } + } + + if (task->_retrys >= (uint32_t)((ZRTP_STATE_WAIT_HELLOACK==stream->state)?ZRTP_T1_MAX_COUNT_EXT:ZRTP_T1_MAX_COUNT)) { + ZRTP_LOG(2,(_ZTU_,"WARNING! HELLO Max retransmissions count reached (%d retries). ID=%u\n", task->_retrys, stream->id)); + + _zrtp_cancel_send_packet_later(stream, ZRTP_NONE); + _clear_stream_crypto(stream); + _zrtp_change_state(stream, ZRTP_STATE_NO_ZRTP); + + if (stream->zrtp->cb.event_cb.on_zrtp_protocol_event) { + stream->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_NO_ZRTP); + } + } else if (task->_is_enabled) { + zrtp_status_t s = _zrtp_packet_send_message(stream, ZRTP_HELLO, &stream->messages.hello); + task->timeout = _zrtp_get_timeout((uint32_t)task->timeout, ZRTP_HELLO); + if (zrtp_status_ok == s) { + task->_retrys++; + } + + + if (stream->zrtp->cb.sched_cb.on_call_later) { + stream->zrtp->cb.sched_cb.on_call_later(stream, task); + } + } +} + +zrtp_status_t _zrtp_machine_start_send_and_resend_hello(zrtp_stream_t* stream) +{ + zrtp_retry_task_t* task = &stream->messages.hello_task; + + task->_is_enabled = 1; + task->callback = _send_and_resend_hello; + task->_retrys = 0; + + _send_and_resend_hello(stream, task); + + return zrtp_status_ok; +} + +static void _send_helloack(zrtp_stream_t* stream) +{ + _zrtp_packet_send_message(stream, ZRTP_HELLOACK, NULL); +} + + +/*---------------------------------------------------------------------------*/ +static void _send_and_resend_goclear(zrtp_stream_t* stream, zrtp_retry_task_t* task) +{ + if (task->_is_enabled) { + if (task->_retrys > ZRTP_T2_MAX_COUNT) { + ZRTP_LOG(2,(_ZTU_,"\tWARNING!: GOCLEAR Nax retransmissions count reached. ID=%u\n", stream->id)); + _zrtp_machine_enter_clear(stream); + } else { + zrtp_packet_GoClear_t* goclear = (zrtp_packet_GoClear_t*) &stream->messages.goclear; + + _zrtp_packet_send_message(stream, ZRTP_GOCLEAR, goclear); + task->_retrys++; + if (stream->zrtp->cb.sched_cb.on_call_later) { + stream->zrtp->cb.sched_cb.on_call_later(stream, task); + } + } + } +} + +static zrtp_status_t _zrtp_machine_start_send_and_resend_goclear(zrtp_stream_t* stream) +{ + zrtp_retry_task_t* task = &stream->messages.goclear_task; + zrtp_string128_t clear_hmac = ZSTR_INIT_EMPTY(clear_hmac); + static const zrtp_string16_t clear_hmac_str = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_CLEAR_HMAC_STR); + + zrtp_memset(&stream->messages.goclear, 0, sizeof(zrtp_packet_GoClear_t)); + + /* Compute Clear HMAC as: HMAC(hmackey, "Clear hmac") */ + stream->session->hash->hmac( stream->session->hash, + ZSTR_GV(stream->cc.hmackey), + ZSTR_GV(clear_hmac_str), + ZSTR_GV(clear_hmac)); + clear_hmac.length = ZRTP_HMAC_SIZE; + + zrtp_memcpy(stream->messages.goclear.clear_hmac, clear_hmac.buffer, clear_hmac.length); + _zrtp_packet_fill_msg_hdr( stream, + ZRTP_GOCLEAR, + sizeof(zrtp_packet_GoClear_t) - sizeof(zrtp_msg_hdr_t), + &stream->messages.goclear.hdr); + + task->_is_enabled = 1; + task->callback = _send_and_resend_goclear; + task->timeout = ZRTP_T2; + task->_retrys = 0; + + _send_and_resend_goclear(stream, task); + + return zrtp_status_ok; +} + + +static void _send_goclearack(zrtp_stream_t* stream) +{ + _zrtp_packet_send_message(stream, ZRTP_GOCLEARACK, NULL); +} + +/*---------------------------------------------------------------------------*/ +static void _send_and_resend_error(zrtp_stream_t* stream, zrtp_retry_task_t* task) +{ + if (task->_retrys >= ZRTP_ETI_MAX_COUNT) { + ZRTP_LOG(2,(_ZTU_,"\tWARNING! ERROR Max retransmissions count reached. ID=%u\n", stream->id)); + _zrtp_machine_switch_to_error(stream); + } else if (task->_is_enabled) { + if (zrtp_status_ok == _zrtp_packet_send_message(stream, ZRTP_ERROR, &stream->messages.error)) { + task->_retrys++; + } + if (stream->zrtp->cb.sched_cb.on_call_later) { + stream->zrtp->cb.sched_cb.on_call_later(stream, task); + } + } +} + +static zrtp_status_t _zrtp_machine_start_send_and_resend_error(zrtp_stream_t* stream) +{ + zrtp_retry_task_t* task = &stream->messages.error_task; + + zrtp_memset(&stream->messages.error, 0, sizeof(zrtp_packet_Error_t)); + stream->messages.error.code = zrtp_hton32(stream->last_error); + + _zrtp_packet_fill_msg_hdr( stream, + ZRTP_ERROR, + sizeof(zrtp_packet_Error_t) - sizeof(zrtp_msg_hdr_t), + &stream->messages.error.hdr); + + task->_is_enabled = 1; + task->callback = _send_and_resend_error; + task->timeout = ZRTP_ET; + task->_retrys = 0; + + _send_and_resend_error(stream, task); + + return zrtp_status_ok; +} + +/*---------------------------------------------------------------------------*/ +static void _send_and_resend_errorack(zrtp_stream_t* stream, zrtp_retry_task_t* task) +{ + if (task->_retrys >= ZRTP_ETR_MAX_COUNT) { + ZRTP_LOG(2,(_ZTU_,"\tWARNING! ERRORACK Max retransmissions count reached. ID=%u\n", stream->id)); + _zrtp_machine_switch_to_error(stream); + } else if (task->_is_enabled) { + if (zrtp_status_ok == _zrtp_packet_send_message(stream, ZRTP_ERRORACK, NULL)) { + task->_retrys++; + } + if (stream->zrtp->cb.sched_cb.on_call_later) { + stream->zrtp->cb.sched_cb.on_call_later(stream, task); + } + } +} + +static zrtp_status_t _zrtp_machine_start_send_and_resend_errorack(zrtp_stream_t* stream) +{ + zrtp_retry_task_t* task = &stream->messages.errorack_task; + + task->_is_enabled = 1; + task->callback = _send_and_resend_errorack; + task->timeout = ZRTP_ET; + task->_retrys = 0; + + _send_and_resend_errorack(stream, task); + + return zrtp_status_ok; +} + + +void _clear_stream_crypto(zrtp_stream_t* stream) +{ + if (stream->protocol) { + _zrtp_protocol_destroy(stream->protocol); + stream->protocol = 0; + } + + zrtp_wipe_zstring(ZSTR_GV(stream->cc.hmackey)); + zrtp_wipe_zstring(ZSTR_GV(stream->cc.peer_hmackey)); + zrtp_wipe_zstring(ZSTR_GV(&stream->cc.zrtp_key)); + zrtp_wipe_zstring(ZSTR_GV(stream->cc.peer_zrtp_key)); +} diff --git a/src/zrtp_engine_driven.c b/src/zrtp_engine_driven.c new file mode 100644 index 0000000000..cccc06b08d --- /dev/null +++ b/src/zrtp_engine_driven.c @@ -0,0 +1,152 @@ +/* + * 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 + */ + +#include "zrtp.h" + +#define _ZTU_ "zrtp dengine" + + +#if (defined(ZRTP_BUILD_FOR_CSD) && (ZRTP_BUILD_FOR_CSD == 1)) + +extern zrtp_status_t _zrtp_machine_process_hello(zrtp_stream_t* stream, zrtp_rtp_info_t* packet); +extern zrtp_status_t start_send_and_resend_hello(zrtp_stream_t* stream); +extern zrtp_status_t start_initiating_secure(zrtp_stream_t *stream); +extern zrtp_status_t _zrtp_machine_start_send_and_resend_hello(zrtp_stream_t* stream); + + +/*----------------------------------------------------------------------------*/ +void zrtp_driven_stream_start(zrtp_stream_t* stream, zrtp_statemachine_type_t role) +{ + + ZRTP_LOG(3,(_ZTU_,"START Driven %s Stream ID=%u mode=%s state=%s.", + (ZRTP_STATEMACHINE_INITIATOR == role)?"INITIATOR":"RESPONDER", + stream->id, zrtp_log_mode2str(stream->mode), zrtp_log_state2str(stream->state))); + + /* This function can be called in parallel to the main processing loop protect internal stream data. */ + zrtp_mutex_lock(stream->stream_protector); + + if ( (ZRTP_STATE_ACTIVE != stream->state) && + (ZRTP_STATE_ERROR != stream->state) && + (ZRTP_STATE_NO_ZRTP != stream->state)) + { + ZRTP_LOG(1,(_ZTU_,"ERROR! can't start stream ID=%u from state %d.", stream->id, stream->state)); + } + else + { + if (ZRTP_STATEMACHINE_INITIATOR == role) { + _zrtp_change_state(stream, ZRTP_STATE_DRIVEN_INITIATOR); + _zrtp_machine_start_send_and_resend_hello(stream); + } else if (ZRTP_STATEMACHINE_RESPONDER == role) { + _zrtp_change_state(stream, ZRTP_STATE_DRIVEN_RESPONDER); + } + } + + zrtp_mutex_unlock(stream->stream_protector); +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_while_in_driven_initiator( zrtp_stream_t* stream, + zrtp_rtp_info_t* packet) +{ + zrtp_status_t s = zrtp_status_ok; + + switch (packet->type) + { + case ZRTP_HELLO: { + s = _zrtp_machine_process_hello(stream, packet); + if (zrtp_status_ok != s) { + ZRTP_LOG(1,(_ZTU_,"ERROR! _zrtp_machine_process_hello()4 failed with status=%d. ID=%u",s, stream->id)); + break; /* Just stay in DRIVEN_INITIATOR state. */ + } + + /* Now we have ZIDs for both sides and can upload secrets from the cache */ + s = _zrtp_prepare_secrets(stream->session); + if (zrtp_status_ok != s) { + ZRTP_LOG(1,(_ZTU_,"ERROR! _zrtp_prepare_secrets()3 failed with status=%d. ID=%u",s, stream->id)); + break; /* Just stay in START state. */ + } + + // TODO: handle autosecure and licensing modes there + _zrtp_cancel_send_packet_later(stream, ZRTP_HELLO); + stream->mode = _zrtp_define_stream_mode(stream); + s = _zrtp_machine_enter_initiatingsecure(stream); + } break; + + default: + break; + } + + return s; +} + +zrtp_status_t _zrtp_machine_process_while_in_driven_responder( zrtp_stream_t* stream, + zrtp_rtp_info_t* packet) +{ + zrtp_status_t s = zrtp_status_ok; + + switch (packet->type) + { + case ZRTP_HELLO: { + s = _zrtp_machine_process_hello(stream, packet); + if (zrtp_status_ok != s) { + ZRTP_LOG(1,(_ZTU_,"ERROR! _zrtp_machine_process_hello()5 failed with status=%d. ID=%u", s, stream->id)); + break; /* Just stay in DRIVEN_INITIATOR state. */ + } + + /* Now we have ZIDs for both sides and can upload secrets from the cache */ + s = _zrtp_prepare_secrets(stream->session); + if (zrtp_status_ok != s) { + ZRTP_LOG(1,(_ZTU_,"ERROR! _zrtp_prepare_secrets()4 failed with status=%d. ID=%u", s, stream->id)); + break; /* Just stay in START state. */ + } + + // TODO: handle autosecure and licensing modes there + s = _zrtp_packet_send_message(stream, ZRTP_HELLO, &stream->messages.hello); + if (zrtp_status_ok == s) { + _zrtp_change_state(stream, ZRTP_STATE_DRIVEN_PENDING); + } + } break; + + default: + break; + } + + return s; +} + +zrtp_status_t _zrtp_machine_process_while_in_driven_pending( zrtp_stream_t* stream, + zrtp_rtp_info_t* packet) +{ + zrtp_status_t s = zrtp_status_ok; + + switch (packet->type) + { + case ZRTP_HELLO: { + s = _zrtp_packet_send_message(stream, ZRTP_HELLO, &stream->messages.hello); + } break; + + case ZRTP_COMMIT: { + zrtp_statemachine_type_t role = _zrtp_machine_preparse_commit(stream, packet); + if (ZRTP_STATEMACHINE_RESPONDER == role) { + s = _zrtp_machine_enter_pendingsecure(stream, packet); + } else if (ZRTP_STATEMACHINE_INITIATOR == role) { + s = _zrtp_machine_start_initiating_secure(stream); + } else { + s = zrtp_status_fail; + } + } break; + + default: + break; + } + + return s; +} + +#endif /* ZRTP_BUILD_FOR_CSD */ diff --git a/src/zrtp_iface_cache.c b/src/zrtp_iface_cache.c new file mode 100644 index 0000000000..7f7c10484c --- /dev/null +++ b/src/zrtp_iface_cache.c @@ -0,0 +1,771 @@ +/* + * 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 + */ + +#include "zrtp.h" + +#if defined(ZRTP_USE_BUILTIN_CACHE) && (ZRTP_USE_BUILTIN_CACHE == 1) + +#define _ZTU_ "zrtp cache" + + +/* Windows kernel have it's own realization in Windows registry*/ +#if (ZRTP_PLATFORM != ZP_WIN32_KERNEL) + +static mlist_t cache_head; +static mlist_t mitmcache_head; +static uint8_t inited = 0; + +static zrtp_global_t* zrtp; +static zrtp_mutex_t* def_cache_protector = NULL; + + +/* Create cache ID like a pair of ZIDs. ZID with lowest value at the beginning */ +static void cache_create_id( const zrtp_stringn_t* first_ZID, + const zrtp_stringn_t* second_ZID, + zrtp_cache_id_t id); + +/* Searching for cache element by cache ID */ +static zrtp_cache_elem_t* get_elem(const zrtp_cache_id_t id, uint8_t is_mitm); + +/* Allows use cache on system with different byte-order */ +static void cache_make_cross( zrtp_cache_elem_t* from, + zrtp_cache_elem_t* to, + uint8_t is_upload); + +static zrtp_status_t zrtp_cache_user_init(); +static zrtp_status_t zrtp_cache_user_down(); + + +/*===========================================================================*/ +/* libZRTP interface implementation */ +/*===========================================================================*/ + +#define ZRTP_CACHE_CHECK_ZID(a,b) \ + if ( (a->length != b->length) || \ + (a->length != sizeof(zrtp_zid_t)) ) \ + { \ + return zrtp_status_bad_param; \ + } + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_def_cache_init(zrtp_global_t* a_zrtp) +{ + zrtp_status_t s = zrtp_status_ok; + + if (!inited) { + zrtp = a_zrtp; + s = zrtp_mutex_init(&def_cache_protector); + if (zrtp_status_ok != s) { + return s; + } + + init_mlist(&cache_head); + init_mlist(&mitmcache_head); + s = zrtp_cache_user_init(); + + inited = 1; + } + + return s; +} + +void zrtp_def_cache_down() +{ + if (inited) { + mlist_t *node = NULL, *tmp = NULL; + + zrtp_cache_user_down(); + + mlist_for_each_safe(node, tmp, &cache_head) { + zrtp_sys_free(mlist_get_struct(zrtp_cache_elem_t, _mlist, node)); + } + mlist_for_each_safe(node, tmp, &mitmcache_head) { + zrtp_sys_free(mlist_get_struct(zrtp_cache_elem_t, _mlist, node)); + } + + init_mlist(&cache_head); + init_mlist(&mitmcache_head); + + zrtp_mutex_destroy(def_cache_protector); + + inited = 0; + } +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_def_cache_set_verified( const zrtp_stringn_t* one_ZID, + const zrtp_stringn_t* another_ZID, + uint32_t verified) +{ + zrtp_cache_id_t id; + zrtp_cache_elem_t* new_elem = NULL; + + ZRTP_CACHE_CHECK_ZID(one_ZID, another_ZID); + cache_create_id(one_ZID, another_ZID, id); + + zrtp_mutex_lock(def_cache_protector); + new_elem = get_elem(id, 0); + if (new_elem) { + new_elem->verified = verified; + } + zrtp_mutex_unlock(def_cache_protector); + + return (new_elem) ? zrtp_status_ok : zrtp_status_fail; +} + +zrtp_status_t zrtp_def_cache_get_verified( const zrtp_stringn_t* one_ZID, + const zrtp_stringn_t* another_ZID, + uint32_t* verified) + +{ + zrtp_cache_id_t id; + zrtp_cache_elem_t* elem = NULL; + + ZRTP_CACHE_CHECK_ZID(one_ZID, another_ZID); + cache_create_id(one_ZID, another_ZID, id); + + zrtp_mutex_lock(def_cache_protector); + elem = get_elem(id, 0); + if (elem) { + *verified = elem->verified; + } + zrtp_mutex_unlock(def_cache_protector); + + return (elem) ? zrtp_status_ok : zrtp_status_fail; +} + + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t cache_put( const zrtp_stringn_t* one_ZID, + const zrtp_stringn_t* another_ZID, + zrtp_shared_secret_t *rss, + uint8_t is_mitm ) +{ + zrtp_cache_elem_t* new_elem = 0; + zrtp_cache_id_t id; + + ZRTP_CACHE_CHECK_ZID(one_ZID, another_ZID); + cache_create_id(one_ZID, another_ZID, id); + + zrtp_mutex_lock(def_cache_protector); + do { + new_elem = get_elem(id, is_mitm); + if (!new_elem) + { + /* If cache doesn't exist - create ne one */ + if (!( new_elem = (zrtp_cache_elem_t*) zrtp_sys_alloc(sizeof(zrtp_cache_elem_t)) )) { + break; + } + + zrtp_memset(new_elem, 0, sizeof(zrtp_cache_elem_t)); + ZSTR_SET_EMPTY(new_elem->curr_cache); + ZSTR_SET_EMPTY(new_elem->prev_cache); + + new_elem->secure_since = (uint32_t)(zrtp_time_now()/1000); + + mlist_add_tail(is_mitm ? &mitmcache_head : &cache_head, &new_elem->_mlist); + zrtp_memcpy(new_elem->id, id, sizeof(zrtp_cache_id_t)); + } + + /* Save current cache value as previous one and new as a current */ + if (!is_mitm) { + if (new_elem->curr_cache.length > 0) { + zrtp_zstrcpy(ZSTR_GV(new_elem->prev_cache), ZSTR_GV(new_elem->curr_cache)); + } + } + + zrtp_zstrcpy(ZSTR_GV(new_elem->curr_cache), ZSTR_GV(rss->value)); + new_elem->lastused_at = rss->lastused_at; + if (!is_mitm) { + new_elem->ttl = rss->ttl; + } + } while (0); + zrtp_mutex_unlock(def_cache_protector); + + return (new_elem) ? zrtp_status_ok : zrtp_status_fail; +} + +zrtp_status_t zrtp_def_cache_put( const zrtp_stringn_t* one_ZID, + const zrtp_stringn_t* another_ZID, + zrtp_shared_secret_t *rss) { + return cache_put(one_ZID, another_ZID, rss, 0); +} + +zrtp_status_t zrtp_def_cache_put_mitm( const zrtp_stringn_t* one_ZID, + const zrtp_stringn_t* another_ZID, + zrtp_shared_secret_t *rss) { + return cache_put(one_ZID, another_ZID, rss, 1); +} + + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t cache_get( const zrtp_stringn_t* one_ZID, + const zrtp_stringn_t* another_ZID, + zrtp_shared_secret_t *rss, + int prev_requested, + uint8_t is_mitm) +{ + zrtp_cache_elem_t* curr = 0; + zrtp_cache_id_t id; + zrtp_status_t s = zrtp_status_ok; + + ZRTP_CACHE_CHECK_ZID(one_ZID, another_ZID); + cache_create_id(one_ZID, another_ZID, id); + + zrtp_mutex_lock(def_cache_protector); + do { + curr = get_elem(id, is_mitm); + if (!curr || (!curr->prev_cache.length && prev_requested)) { + s = zrtp_status_fail; + break; + } + + zrtp_zstrcpy( ZSTR_GV(rss->value), + prev_requested ? ZSTR_GV(curr->prev_cache) : ZSTR_GV(curr->curr_cache)); + + rss->lastused_at = curr->lastused_at; + if (!is_mitm) { + rss->ttl = curr->ttl; + } + } while (0); + zrtp_mutex_unlock(def_cache_protector); + + return s; +} + +zrtp_status_t zrtp_def_cache_get( const zrtp_stringn_t* one_ZID, + const zrtp_stringn_t* another_ZID, + zrtp_shared_secret_t *rss, + int prev_requested) +{ + return cache_get(one_ZID, another_ZID, rss, prev_requested, 0); +} + +zrtp_status_t zrtp_def_cache_get_mitm( const zrtp_stringn_t* one_ZID, + const zrtp_stringn_t* another_ZID, + zrtp_shared_secret_t *rss) +{ + return cache_get(one_ZID, another_ZID, rss, 0, 1); +} + +/*-----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_def_cache_set_presh_counter( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + uint32_t counter) +{ + zrtp_cache_elem_t* new_elem = 0; + zrtp_cache_id_t id; + + ZRTP_CACHE_CHECK_ZID(one_zid, another_zid); + cache_create_id(one_zid, another_zid, id); + + zrtp_mutex_lock(def_cache_protector); + new_elem = get_elem(id, 0); + if (new_elem) { + ZRTP_LOG(3,(_ZTU_,"\tTEST! Update counter to %u.\n", counter)); + new_elem->presh_counter = counter; + } + zrtp_mutex_unlock(def_cache_protector); + + return (new_elem) ? zrtp_status_ok : zrtp_status_fail; +} + +zrtp_status_t zrtp_def_cache_get_presh_counter( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + uint32_t* counter) +{ + zrtp_cache_elem_t* new_elem = 0; + zrtp_cache_id_t id; + + ZRTP_CACHE_CHECK_ZID(one_zid, another_zid); + cache_create_id(one_zid, another_zid, id); + + zrtp_mutex_lock(def_cache_protector); + new_elem = get_elem(id, 0); + if (new_elem) { + ZRTP_LOG(3,(_ZTU_,"\tTEST! Return counter to %u.\n", new_elem->presh_counter)); + *counter = new_elem->presh_counter; + } + zrtp_mutex_unlock(def_cache_protector); + + return (new_elem) ? zrtp_status_ok : zrtp_status_fail; +} + +/*-----------------------------------------------------------------------------*/ +static void cache_create_id( const zrtp_stringn_t* first_ZID, + const zrtp_stringn_t* second_ZID, + zrtp_cache_id_t id ) +{ + if (0 < zrtp_memcmp(first_ZID->buffer, second_ZID->buffer, sizeof(zrtp_zid_t))) { + const zrtp_stringn_t* tmp_ZID = first_ZID; + first_ZID = second_ZID; + second_ZID = tmp_ZID; + } + + zrtp_memcpy(id, first_ZID->buffer, sizeof(zrtp_zid_t)); + zrtp_memcpy((char*)id+sizeof(zrtp_zid_t), second_ZID->buffer, sizeof(zrtp_zid_t)); +} + +/*-----------------------------------------------------------------------------*/ +zrtp_cache_elem_t* zrtp_def_cache_get2(const zrtp_cache_id_t id, int is_mitm) +{ + return get_elem(id, is_mitm); +} + +/*-----------------------------------------------------------------------------*/ +static zrtp_cache_elem_t* get_elem(const zrtp_cache_id_t id, uint8_t is_mitm) +{ + mlist_t* node = NULL; + mlist_t* head = is_mitm ? &mitmcache_head : &cache_head; + mlist_for_each(node, head) { + zrtp_cache_elem_t* elem = mlist_get_struct(zrtp_cache_elem_t, _mlist, node); + if (!zrtp_memcmp(elem->id, id, sizeof(zrtp_cache_id_t))) { + return elem; + } + } + + return NULL; +} + +/*----------------------------------------------------------------------------*/ +static void cache_make_cross(zrtp_cache_elem_t* from, zrtp_cache_elem_t* to, uint8_t is_upload) +{ + if (!to) { + return; + } + + if (from) { + zrtp_memcpy(to, from, sizeof(zrtp_cache_elem_t)); + } + + if (is_upload) { + to->verified = zrtp_ntoh32(to->verified); + to->secure_since= zrtp_ntoh32(to->secure_since); + to->lastused_at = zrtp_ntoh32(to->lastused_at); + to->ttl = zrtp_ntoh32(to->ttl); + to->name_length = zrtp_ntoh32(to->name_length); + to->curr_cache.length = zrtp_ntoh16(to->curr_cache.length); + to->prev_cache.length = zrtp_ntoh16(to->prev_cache.length); + to->presh_counter = zrtp_ntoh32(to->presh_counter); + } else { + to->verified = zrtp_hton32(to->verified); + to->secure_since= zrtp_hton32(to->secure_since); + to->lastused_at = zrtp_hton32(to->lastused_at); + to->ttl = zrtp_hton32(to->ttl); + to->name_length = zrtp_hton32(to->name_length); + to->curr_cache.length = zrtp_hton16(to->curr_cache.length); + to->prev_cache.length = zrtp_hton16(to->prev_cache.length); + to->presh_counter = zrtp_hton32(to->presh_counter); + } +} + + +/*===========================================================================*/ +/* ZRTP cache realization as a simple binary file */ +/*===========================================================================*/ + + +#if ZRTP_HAVE_STDIO_H == 1 + #include +#endif + +#include + +/*---------------------------------------------------------------------------*/ +#define ZRTP_INT_CACHE_BREAK(s, status) \ +{ \ + if (!s) s = status; \ + break; \ +}\ + +zrtp_status_t zrtp_cache_user_init() +{ + FILE* cache_file = 0; + zrtp_cache_elem_t* new_elem = 0; + zrtp_status_t s = zrtp_status_ok; + uint32_t cache_elems_count = 0; + uint32_t mitmcache_elems_count = 0; + uint32_t i = 0; + unsigned is_unsupported = 0; + + + /* Try to open existing file. If ther is no cache file - start with empty cache */ +#if (ZRTP_PLATFORM == ZP_WIN32) + if (0 != fopen_s(&cache_file, zrtp->def_cache_path.buffer, "rb")) { + return zrtp_status_ok; + } +#else + if (0 == (cache_file = fopen(zrtp->def_cache_path.buffer, "rb"))) { + return zrtp_status_ok; + } +#endif + /* + * Check for the cache file version number. Current version of libzrtp doesn't support + * backward compatibility in zrtp cache file structure, so we just remove the old cache file. + * + * Version field format: $ZRTP_DEF_CACHE_VERSION_STR$ZRTP_DEF_CACHE_VERSION_VAL + */ + do { + char version_buff[256]; + + if (fread(version_buff, strlen(ZRTP_DEF_CACHE_VERSION_STR)+strlen(ZRTP_DEF_CACHE_VERSION_VAL), 1, cache_file) <= 0) { + ZRTP_LOG(3,(_ZTU_,"Cache file is too small.\n")); + is_unsupported = 1; + break; + } + + if (0 != zrtp_memcmp(version_buff, ZRTP_DEF_CACHE_VERSION_STR, strlen(ZRTP_DEF_CACHE_VERSION_STR))) { + ZRTP_LOG(3,(_ZTU_,"Can't find ZRTP Version tag in the cache file.\n")); + is_unsupported = 1; + break; + } + + if (0 != zrtp_memcmp(version_buff+strlen(ZRTP_DEF_CACHE_VERSION_STR), ZRTP_DEF_CACHE_VERSION_VAL, strlen(ZRTP_DEF_CACHE_VERSION_VAL))) { + ZRTP_LOG(3,(_ZTU_,"Usupported ZRTP cache version.\n")); + is_unsupported = 1; + break; + } + } while (0); + + if (is_unsupported) { + ZRTP_LOG(3,(_ZTU_,"Unsupported version of ZRTP cache file detected - white-out the cache.\n")); + fclose(cache_file); + return zrtp_status_ok; + } + + + /* + * Load MitM caches: first 32 bits is a mitm secrets counter. Read it and then + * upload appropriate number of MitM secrets. + */ + do { + if (fread(&mitmcache_elems_count, 4, 1, cache_file) <= 0) { + ZRTP_INT_CACHE_BREAK(s, zrtp_status_read_fail); + } + + mitmcache_elems_count = zrtp_ntoh32(mitmcache_elems_count); + for (i=0; i_mlist); + } + + if (i != mitmcache_elems_count) + ZRTP_INT_CACHE_BREAK(s, zrtp_status_read_fail); + } while(0); + if (s != zrtp_status_ok) { + fclose(cache_file); + zrtp_def_cache_down(); + return s; + } + + /* + * Load regular caches: first 32 bits is a secrets counter. Read it and then + * upload appropriate number of regular secrets. + */ + if (fread(&cache_elems_count, 4, 1, cache_file) <= 0) { + fclose(cache_file); + zrtp_def_cache_down(); + return zrtp_status_read_fail; + } + + cache_elems_count = zrtp_ntoh32(cache_elems_count); + for (i=0; i_mlist); + } + if (i != cache_elems_count) { + s = zrtp_status_read_fail; + } + + if (0 != fclose(cache_file)) { + zrtp_def_cache_down(); + return zrtp_status_fail; + } + + return s; +} + +/*---------------------------------------------------------------------------*/ +#define ZRTP_DOWN_CACHE_RETURN(s, f) \ +{\ + if (zrtp_status_ok != s) { \ + ZRTP_LOG(3,(_ZTU_,"\tERROR! Unable to writing to ZRTP cache file.\n")); \ + } \ + if (f) { \ + fclose(f);\ + } \ + return s;\ +}; + +zrtp_status_t zrtp_cache_user_down() +{ + FILE* cache_file = 0; + zrtp_cache_elem_t tmp_elem; + mlist_t *node = 0; + uint32_t count = 0; + uint32_t pos = 0; + + ZRTP_LOG(3,(_ZTU_,"\tStoring ZRTP cache to the file...\n")); + /* Open/create file for writing */ +#if (ZRTP_PLATFORM == ZP_WIN32) + if (0 != fopen_s(&cache_file, zrtp->def_cache_path.buffer, "wb+")) { + ZRTP_LOG(2,(_ZTU_,"\tERROR! unable to open ZRTP cache file <%s>.\n", zrtp->def_cache_path.buffer)); + return zrtp_status_open_fail; + } +#else + cache_file = fopen(zrtp->def_cache_path.buffer, "wb+"); + if (!cache_file) { + ZRTP_LOG(2,(_ZTU_,"\tERROR! unable to open ZRTP cache file <%s>.\n", zrtp->def_cache_path.buffer)); + return zrtp_status_open_fail; + } +#endif + + /* Store version string first. Format: &ZRTP_DEF_CACHE_VERSION_STR&ZRTP_DEF_CACHE_VERSION_VAL */ + if (1 != fwrite(ZRTP_DEF_CACHE_VERSION_STR, strlen(ZRTP_DEF_CACHE_VERSION_STR), 1, cache_file)) { + ZRTP_DOWN_CACHE_RETURN(zrtp_status_write_fail, cache_file); + } + if (1 != fwrite(ZRTP_DEF_CACHE_VERSION_VAL, strlen(ZRTP_DEF_CACHE_VERSION_VAL), 1, cache_file)) { + ZRTP_DOWN_CACHE_RETURN(zrtp_status_write_fail, cache_file); + } + + /* Store PBX secrets first. Format: , */ + pos = ftell(cache_file); + count = 0; + fwrite(&count, sizeof(count), 1, cache_file); + mlist_for_each(node, &mitmcache_head) { + zrtp_cache_elem_t* elem = mlist_get_struct(zrtp_cache_elem_t, _mlist, node); + cache_make_cross(elem, &tmp_elem, 0); + if (fwrite(&tmp_elem, ZRTP_MITMCACHE_ELEM_LENGTH, 1, cache_file) != 1) { + ZRTP_DOWN_CACHE_RETURN(zrtp_status_write_fail, cache_file); + } + count++; + } + + fseek(cache_file, pos, SEEK_SET); + count = zrtp_hton32(count); + if (fwrite(&count, sizeof(count), 1, cache_file) != 1) { + ZRTP_DOWN_CACHE_RETURN(zrtp_status_write_fail, cache_file); + } + + fseek(cache_file, 0L, SEEK_END); + ZRTP_LOG(3,(_ZTU_,"\t%u MiTM cache entries have been stored sucessfully.\n",zrtp_ntoh32(count))); + + /* Store reqular secrets. Format: , */ + pos = ftell(cache_file); + count = 0; + fwrite(&count, sizeof(count), 1, cache_file); + mlist_for_each(node, &cache_head) { + zrtp_cache_elem_t* elem = mlist_get_struct(zrtp_cache_elem_t, _mlist, node); + cache_make_cross(elem, &tmp_elem, 0); + if (fwrite(&tmp_elem, ZRTP_CACHE_ELEM_LENGTH, 1, cache_file) != 1) { + ZRTP_DOWN_CACHE_RETURN(zrtp_status_write_fail, cache_file); + } + count++; + } + + fseek(cache_file, pos, SEEK_SET); + count = zrtp_hton32(count); + if (fwrite(&count, sizeof(count), 1, cache_file) != 1) { + ZRTP_DOWN_CACHE_RETURN(zrtp_status_write_fail, cache_file); + } + ZRTP_LOG(3,(_ZTU_,"\t%u regular cache entries have been stored sucessfully.\n", zrtp_ntoh32(count))); + + ZRTP_DOWN_CACHE_RETURN(zrtp_status_ok, cache_file); +} + + +/*==========================================================================*/ +/* Utility functions. */ +/* These functions are example how cache can be used for internal needs */ +/*==========================================================================*/ + + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t put_name( const zrtp_stringn_t* one_ZID, + const zrtp_stringn_t* another_ZID, + const zrtp_stringn_t* name, + uint8_t is_mitm) +{ + zrtp_cache_elem_t* new_elem = 0; + zrtp_cache_id_t id; + zrtp_status_t s = zrtp_status_ok; + + ZRTP_CACHE_CHECK_ZID(one_ZID, another_ZID); + cache_create_id(one_ZID, another_ZID, id); + + zrtp_mutex_lock(def_cache_protector); + do { + new_elem = get_elem(id, is_mitm); + if (!new_elem) { + s = zrtp_status_fail; + break; + } + + /* Update regular cache name*/ + new_elem->name_length = ZRTP_MIN(name->length, ZFONE_CACHE_NAME_LENGTH-1); + zrtp_memset(new_elem->name, 0, sizeof(new_elem->name)); + zrtp_memcpy(new_elem->name, name->buffer, new_elem->name_length); + } while (0); + zrtp_mutex_unlock(def_cache_protector); + + return s; +} + + +zrtp_status_t zrtp_def_cache_put_name( const zrtp_stringn_t* one_ZID, + const zrtp_stringn_t* another_ZID, + const zrtp_stringn_t* name) +{ + return put_name(one_ZID, another_ZID, name, 0); +} + + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t get_name( const zrtp_stringn_t* one_ZID, + const zrtp_stringn_t* another_ZID, + zrtp_stringn_t* name, + uint8_t is_mitm) +{ + zrtp_cache_elem_t* new_elem = 0; + zrtp_cache_id_t id; + zrtp_status_t s = zrtp_status_fail; + + ZRTP_CACHE_CHECK_ZID(one_ZID, another_ZID); + cache_create_id(one_ZID, another_ZID, id); + + zrtp_mutex_lock(def_cache_protector); + do { + new_elem = get_elem(id, is_mitm); + if (!new_elem) { + s = zrtp_status_fail; + break; + } + + name->length = new_elem->name_length; + zrtp_memcpy(name->buffer, new_elem->name, name->length); + s = zrtp_status_ok; + } while (0); + zrtp_mutex_unlock(def_cache_protector); + + return s; +} + +zrtp_status_t zrtp_def_cache_get_name( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid, + zrtp_stringn_t* name) +{ + return get_name(one_zid, another_zid, name, 0); +} + + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_def_cache_get_since( const zrtp_stringn_t* one_ZID, + const zrtp_stringn_t* another_ZID, + uint32_t* since) +{ + zrtp_cache_elem_t* new_elem = 0; + zrtp_cache_id_t id; + + ZRTP_CACHE_CHECK_ZID(one_ZID, another_ZID); + cache_create_id(one_ZID, another_ZID, id); + + zrtp_mutex_lock(def_cache_protector); + new_elem = get_elem(id, 0); + if (new_elem) { + *since = new_elem->secure_since; + } + zrtp_mutex_unlock(def_cache_protector); + + return (new_elem) ? zrtp_status_ok : zrtp_status_fail; +} + +zrtp_status_t zrtp_def_cache_reset_since( const zrtp_stringn_t* one_zid, + const zrtp_stringn_t* another_zid) +{ + zrtp_cache_elem_t* new_elem = 0; + zrtp_cache_id_t id; + + ZRTP_CACHE_CHECK_ZID(one_zid, another_zid); + cache_create_id(one_zid, another_zid, id); + + zrtp_mutex_lock(def_cache_protector); + new_elem = get_elem(id, 0); + if (new_elem) { + new_elem->secure_since = (uint32_t)(zrtp_time_now()/1000); + } + zrtp_mutex_unlock(def_cache_protector); + + return (new_elem) ? zrtp_status_ok : zrtp_status_fail; +} + + +/*----------------------------------------------------------------------------*/ +void zrtp_def_cache_foreach( zrtp_global_t *global, + int is_mitm, + zrtp_cache_callback_t callback, + void *data) +{ + int delete, result; + mlist_t* node = NULL, *tmp_node = NULL; + + zrtp_mutex_lock(def_cache_protector); + mlist_for_each_safe(node, tmp_node, (is_mitm ? &mitmcache_head : &cache_head)) + { + zrtp_cache_elem_t* elem = mlist_get_struct(zrtp_cache_elem_t, _mlist, node); + result = callback(elem, is_mitm, data, &delete); + if (delete) { + mlist_del(&elem->_mlist); + } + if (!result) { + break; + } + } + zrtp_mutex_unlock(def_cache_protector); + + return; +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_def_cache_store(zrtp_global_t *zrtp) +{ + ZRTP_LOG(3,(_ZTU_,"Storing ZRTP Cache...\n")); + + zrtp_mutex_lock(def_cache_protector); + zrtp_cache_user_down(); + zrtp_mutex_unlock(def_cache_protector); + + ZRTP_LOG(3,(_ZTU_,"Storing ZRTP Cache - DONE.\n")); + return zrtp_status_ok; +} + +#endif /* ZRTP_PLATFORM != ZP_WIN32_KERNEL */ + +#endif /* ZRTP_USE_BUILTIN_CACHE */ diff --git a/src/zrtp_iface_scheduler.c b/src/zrtp_iface_scheduler.c new file mode 100644 index 0000000000..8fde5d5787 --- /dev/null +++ b/src/zrtp_iface_scheduler.c @@ -0,0 +1,362 @@ +/* + * 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 + */ + +#include "zrtp.h" + +#if (defined(ZRTP_USE_BUILTIN_SCEHDULER) && (ZRTP_USE_BUILTIN_SCEHDULER ==1)) +#if (ZRTP_PLATFORM!=ZP_SYMBIAN) + +#if defined (ZRTP_DEBUG_WITH_PJSIP) && (ZRTP_DEBUG_WITH_PJSIP == 1) +# include +#endif + +/* Windows kernel have it's own realization based on kernel timers */ +#if (ZRTP_PLATFORM != ZP_WIN32_KERNEL) + +#define ZRTP_SCHED_QUEUE_SIZE ZRTP_MAX_STREAMS_PER_SESSION * 1000 +#define ZRTP_SCHED_LOOP_QVANT 20 + +#define ZRTP_SCHED_SLEEP(count) zrtp_sleep(ZRTP_SCHED_LOOP_QVANT*count); + + +/** Schedulling tasks structure */ +typedef struct +{ + zrtp_stream_t *ctx; /** ZRTP stream context associated with the task */ + zrtp_retry_task_t *ztask; /** ZRTP stream associated with the task */ + uint64_t wake_at; /* Wake time in milliseconds */ + mlist_t _mlist; +} zrtp_sched_task_t; + +/** Initiation flag. Protection from reinitialization. (1 if initiated) */ +static uint8_t inited = 0; + +/** Sorted by wake time tasks list. First task to do at the begining */ +static mlist_t tasks_head; + +/** Tasks queue protector againts race conditions on add/remove tasks */ +static zrtp_mutex_t* protector = NULL; + +/** Main queue symaphore */ +static zrtp_sem_t* count = NULL; + +static uint8_t is_running = 0; +#if (ZRTP_PLATFORM == ZP_WIN32 || ZRTP_PLATFORM == ZP_WINCE) +HANDLE scheduler_thread = NULL; +#else +static uint8_t is_working = 0; +#endif + + +/*==========================================================================*/ +/* Platform Dependent Routine */ +/*==========================================================================*/ + +#if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WINCE) +#include + +int zrtp_sleep(unsigned int msec) +{ + Sleep(msec); + return 0; +} + +int zrtp_thread_create(zrtp_thread_routine_t start_routine, void *arg) +{ + DWORD dwThreadId; + + scheduler_thread = CreateThread(NULL, 0, start_routine, 0, 0, &dwThreadId); + if (NULL == scheduler_thread) { + return -1; + } + + return 0; +} + +#elif (ZRTP_PLATFORM == ZP_LINUX) || (ZRTP_PLATFORM == ZP_DARWIN) || (ZRTP_PLATFORM == ZP_BSD) +#if ZRTP_HAVE_UNISTD_H == 1 +#include +#else +#error "Used environment dosn't have - zrtp_scheduler can't be build." +#endif +#if ZRTP_HAVE_PTHREAD_H == 1 +#include +#else +# error "Used environment dosn't have - zrtp_scheduler can't be build." +#endif + +int zrtp_sleep(unsigned int msec) +{ + return usleep(msec*1000); +} + +int zrtp_thread_create(zrtp_thread_routine_t start_routine, void *arg) +{ + pthread_t thread; + return pthread_create(&thread, NULL, start_routine, NULL); +} +#endif + + +/*==========================================================================*/ +/* Scheduler Implementation */ +/*==========================================================================*/ +#if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WIN64) || (ZRTP_PLATFORM == ZP_WINCE) +static DWORD WINAPI sched_loop(void* param) +#elif (ZRTP_PLATFORM == ZP_SYMBIAN) +static int sched_loop(void* param) +#else +static void* sched_loop(void* param) +#endif +{ +#if defined (ZRTP_DEBUG_WITH_PJSIP) && (ZRTP_DEBUG_WITH_PJSIP == 1) + /* + Register current thread if it was created by + external system call(not pj_sip call) + */ + pj_thread_desc desc; + pj_thread_t *sched_loop_thread; + + if (pj_thread_is_registered()==PJ_FALSE){ + pj_thread_register("zrtp_sched_loop_thread", desc, &sched_loop_thread); + } +#endif + +#if (ZRTP_PLATFORM != ZP_WIN32 && ZRTP_PLATFORM != ZP_WINCE) + is_working = 1; +#endif + while (is_running) + { + zrtp_sched_task_t* task = NULL; + zrtp_sched_task_t task2run; + int ready_2_run = 0; + mlist_t* node = 0; + + /* Wait for tasks in queue */ + zrtp_sem_wait(count); + + zrtp_mutex_lock(protector); + + node = mlist_get(&tasks_head); + if (!node) { + zrtp_mutex_unlock(protector); + continue; + } + + task = mlist_get_struct(zrtp_sched_task_t, _mlist, node); + if (task->wake_at <= zrtp_time_now()) + { + task2run.ctx = task->ctx; + task2run.ztask = task->ztask; + mlist_del(node); + zrtp_sys_free(task); + ready_2_run = 1; + } + + zrtp_mutex_unlock(protector); + + if (ready_2_run) { + task2run.ztask->_is_busy = 1; + task2run.ztask->callback(task2run.ctx, task2run.ztask); + task2run.ztask->_is_busy = 0; + } else { + zrtp_sem_post(count); + } + + ZRTP_SCHED_SLEEP(1); + } + +#if (ZRTP_PLATFORM != ZP_WIN32)&& (ZRTP_PLATFORM != ZP_WINCE) + is_working = 0; +#endif + +#if (ZRTP_PLATFORM != ZP_WIN32) && (ZRTP_PLATFORM != ZP_WIN64) && (ZRTP_PLATFORM != ZP_WINCE) + return NULL; +#else + return 0; +#endif +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t zrtp_def_scheduler_init(zrtp_global_t* zrtp) +{ + zrtp_status_t status = zrtp_status_ok; + + if (inited) { + return zrtp_status_ok; + } + + do { + init_mlist(&tasks_head); + + if (zrtp_status_ok != (status = zrtp_mutex_init(&protector))) { + break; + } + if (zrtp_status_ok != (status = zrtp_sem_init(&count, 0, ZRTP_SCHED_QUEUE_SIZE))) { + break; + } + + /* Starting processing loop */ + is_running = 1; + + if (0 != zrtp_thread_create(sched_loop, NULL)) { + zrtp_sem_destroy(count); + zrtp_mutex_destroy(protector); + + status = zrtp_status_fail; + break; + } + + inited = 1; + } while (0); + + return status; +} + +/*---------------------------------------------------------------------------*/ +void zrtp_def_scheduler_down() +{ + mlist_t *node = 0, *tmp = 0; + + if (!inited) { + return; + } + + /* Stop main thread */ + is_running = 0; + zrtp_sem_post(count); +#if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WINCE) + if (NULL != scheduler_thread) + { + WaitForSingleObject(scheduler_thread, INFINITE); + CloseHandle(scheduler_thread); + scheduler_thread = NULL; + } +#else + while (is_working) { + ZRTP_SCHED_SLEEP(1); + } +#endif + + /* Then destroy tasks queue and realease all other resources */ + zrtp_mutex_lock(protector); + + mlist_for_each_safe(node, tmp, &tasks_head) { + zrtp_sched_task_t* task = mlist_get_struct(zrtp_sched_task_t, _mlist, node); + zrtp_sys_free(task); + } + init_mlist(&tasks_head); + + zrtp_mutex_unlock(protector); + + zrtp_mutex_destroy(protector); + zrtp_sem_destroy(count); + + inited = 0; +} + +/*---------------------------------------------------------------------------*/ +void zrtp_def_scheduler_call_later(zrtp_stream_t *ctx, zrtp_retry_task_t* ztask) +{ + mlist_t *node=0, *tmp=0; + mlist_t* last = &tasks_head; + + zrtp_mutex_lock(protector); + + if (!ztask->_is_enabled) { + zrtp_mutex_unlock(protector); + return; + } + + do { + zrtp_sched_task_t* new_task = zrtp_sys_alloc(sizeof(zrtp_sched_task_t)); + if (!new_task) { + break; + } + + new_task->ctx = ctx; + new_task->ztask = ztask; + new_task->wake_at = zrtp_time_now() + ztask->timeout; + + /* Try to find element with later wacked time than we have */ + mlist_for_each_safe(node, tmp, &tasks_head) { + zrtp_sched_task_t* tmp_task = mlist_get_struct(zrtp_sched_task_t, _mlist, node); + if (tmp_task->wake_at >= new_task->wake_at) { + last = node; + break; + } + } + + /* + * If packet wasn't inserted (empty queue or all elements are smaller) + * Put them to the end of the queue. + */ + mlist_insert(last, &new_task->_mlist); + + zrtp_sem_post(count); + } while (0); + + zrtp_mutex_unlock(protector); +} + +/*---------------------------------------------------------------------------*/ +void zrtp_def_scheduler_cancel_call_later(zrtp_stream_t* ctx, zrtp_retry_task_t* ztask) +{ + mlist_t *node=0, *tmp=0; + + zrtp_mutex_lock(protector); + + mlist_for_each_safe(node, tmp, &tasks_head) { + zrtp_sched_task_t* task = mlist_get_struct(zrtp_sched_task_t, _mlist, node); + if ((task->ctx == ctx) && ((task->ztask == ztask) || !ztask)) { + mlist_del(&task->_mlist); + zrtp_sys_free(task); + zrtp_sem_trtwait(count); + if (ztask) { + break; + } + } + } + + zrtp_mutex_unlock(protector); +} + +void zrtp_def_scheduler_wait_call_later(zrtp_stream_t* ctx) +{ + while (ctx->messages.hello_task._is_busy) { + ZRTP_SCHED_SLEEP(1); + } + while (ctx->messages.commit_task._is_busy) { + ZRTP_SCHED_SLEEP(1); + } + while (ctx->messages.dhpart_task._is_busy) { + ZRTP_SCHED_SLEEP(1); + } + while (ctx->messages.confirm_task._is_busy) { + ZRTP_SCHED_SLEEP(1); + } + while (ctx->messages.error_task._is_busy) { + ZRTP_SCHED_SLEEP(1); + } + while (ctx->messages.errorack_task._is_busy) { + ZRTP_SCHED_SLEEP(1); + } + while (ctx->messages.goclear_task._is_busy) { + ZRTP_SCHED_SLEEP(1); + } + while (ctx->messages.dh_task._is_busy) { + ZRTP_SCHED_SLEEP(1); + } +} + +#endif /* not for windows kernel */ + +#endif // ZRTP_PLATFORM==ZP_SYMBIAN + +#endif /*ZRTP_USE_BUILTIN_SCEHDULER*/ diff --git a/src/zrtp_iface_sys.c b/src/zrtp_iface_sys.c new file mode 100644 index 0000000000..81ec38f41e --- /dev/null +++ b/src/zrtp_iface_sys.c @@ -0,0 +1,489 @@ +/* + * 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 + */ + +#include "zrtp.h" + +#if (defined(ZRTP_USE_BUILTIN) && (ZRTP_USE_BUILTIN == 1)) + +/*============================================================================*/ +/* Default realization of Mutexes synchronization routine */ +/*============================================================================*/ + +/*---------------------------------------------------------------------------*/ +#if (ZRTP_PLATFORM == ZP_WIN32_KERNEL) +#include + +struct zrtp_mutex_t +{ + NDIS_SPIN_LOCK mutex; +}; + +zrtp_status_t zrtp_mutex_init(zrtp_mutex_t **mutex) +{ + zrtp_mutex_t* new_mutex = zrtp_sys_alloc(sizeof(zrtp_mutex_t)); + if (!new_mutex) + return zrtp_status_alloc_fail; + NdisAllocateSpinLock(&new_mutex->mutex); + *mutex = new_mutex; + return zrtp_status_ok; +} + +zrtp_status_t zrtp_mutex_destroy(zrtp_mutex_t* mutex) +{ + NdisFreeSpinLock(&mutex->mutex); + zrtp_sys_free(mutex); + return zrtp_status_ok; +} + +zrtp_status_t zrtp_mutex_lock(zrtp_mutex_t* mutex) +{ + NdisAcquireSpinLock(&mutex->mutex); + return zrtp_status_ok; +} + +zrtp_status_t zrtp_mutex_unlock(zrtp_mutex_t* mutex) +{ + NdisReleaseSpinLock(&mutex->mutex); + return zrtp_status_ok; +} + +/*---------------------------------------------------------------------------*/ +#elif (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WIN64) || (ZRTP_PLATFORM == ZP_WINCE) + +#include + +struct zrtp_mutex_t +{ + HANDLE mutex; +}; + +zrtp_status_t zrtp_mutex_init(zrtp_mutex_t** mutex) +{ + zrtp_mutex_t* new_mutex = zrtp_sys_alloc(sizeof(zrtp_mutex_t)); + if (!new_mutex) + return zrtp_status_alloc_fail; + new_mutex->mutex = CreateMutex(NULL, FALSE, NULL); + if (!new_mutex->mutex) { + zrtp_sys_free(new_mutex); + return zrtp_status_fail; + } + *mutex = new_mutex; + return zrtp_status_ok; +} + +zrtp_status_t zrtp_mutex_destroy(zrtp_mutex_t* mutex) +{ + zrtp_status_t s = (0 == CloseHandle(mutex->mutex)) ? zrtp_status_fail : zrtp_status_ok; + zrtp_sys_free(mutex); + return s; +} + +zrtp_status_t zrtp_mutex_lock(zrtp_mutex_t* mutex) +{ + return (WaitForSingleObject(mutex->mutex, INFINITE) == WAIT_FAILED) ? zrtp_status_fail : zrtp_status_ok; +} + +zrtp_status_t zrtp_mutex_unlock(zrtp_mutex_t* mutex) +{ + return (0 == ReleaseMutex(mutex->mutex)) ? zrtp_status_fail : zrtp_status_ok; +} + +/*---------------------------------------------------------------------------*/ +#elif (ZRTP_PLATFORM == ZP_LINUX) || (ZRTP_PLATFORM == ZP_DARWIN) || (ZRTP_PLATFORM == ZP_BSD) + +#if defined ZRTP_HAVE_PTHREAD_H +# include +#endif + +struct zrtp_mutex_t +{ + pthread_mutex_t mutex; +}; + + +zrtp_status_t zrtp_mutex_init(zrtp_mutex_t** mutex) +{ + zrtp_mutex_t* new_mutex = zrtp_sys_alloc(sizeof(zrtp_mutex_t)); + if (new_mutex) { + zrtp_status_t s = pthread_mutex_init(&new_mutex->mutex, NULL) == 0 ? zrtp_status_ok : zrtp_status_fail; + if (s == zrtp_status_fail) + zrtp_sys_free(new_mutex); + else + *mutex = new_mutex; + return s; + } + return zrtp_status_alloc_fail; +} + +zrtp_status_t zrtp_mutex_destroy(zrtp_mutex_t* mutex) +{ + zrtp_status_t s = (pthread_mutex_destroy(&mutex->mutex) == 0) ? zrtp_status_ok : zrtp_status_fail; + zrtp_sys_free(mutex); + return s; +} + +zrtp_status_t zrtp_mutex_lock(zrtp_mutex_t* mutex) +{ + return (pthread_mutex_lock(&mutex->mutex) == 0) ? zrtp_status_ok : zrtp_status_fail; +} + +zrtp_status_t zrtp_mutex_unlock(zrtp_mutex_t* mutex) +{ + return (pthread_mutex_unlock(&mutex->mutex) == 0) ? zrtp_status_ok : zrtp_status_fail; +} + +#endif + + +/*============================================================================*/ +/* Default realization of Semaphores synchronization routine */ +/*============================================================================*/ + +#if (ZRTP_PLATFORM == ZP_WIN32_KERNEL) + +struct zrtp_sem_t +{ + KSEMAPHORE sem; +}; + +zrtp_status_t zrtp_sem_init(zrtp_sem_t** sem, uint32_t val, uint32_t limit) +{ + zrtp_sem_t *new_sem = zrtp_sys_alloc(sizeof(zrtp_sem_t)); + if (NULL == new_sem) { + return zrtp_status_alloc_fail; + } + + KeInitializeSemaphore(&new_sem->sem, val, limit); + *sem = new_sem; + return zrtp_status_ok; +} + +zrtp_status_t zrtp_sem_destroy(zrtp_sem_t* sem) +{ + return zrtp_status_ok; +} + +zrtp_status_t zrtp_sem_wait(zrtp_sem_t* sem) +{ + return KeWaitForSingleObject(&sem->sem, Executive, KernelMode, FALSE, NULL) == STATUS_SUCCESS ? + zrtp_status_ok : zrtp_status_fail; +} + +zrtp_status_t zrtp_sem_trtwait(zrtp_sem_t* sem) +{ + LARGE_INTEGER timeout; + timeout.QuadPart = 0; + + return KeWaitForSingleObject(&sem->sem, Executive, KernelMode, FALSE, &timeout) == STATUS_SUCCESS ? + zrtp_status_ok : zrtp_status_fail; +} + +zrtp_status_t zrtp_sem_post(zrtp_sem_t* sem) +{ + KeReleaseSemaphore(&sem->sem, IO_NO_INCREMENT, 1, FALSE); + return zrtp_status_ok; +} + + +#elif (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WIN64) || (ZRTP_PLATFORM == ZP_WINCE) + +struct zrtp_sem_t +{ + HANDLE sem; +}; + +zrtp_status_t zrtp_sem_init(zrtp_sem_t** sem, uint32_t val, uint32_t limit) +{ + zrtp_sem_t *new_sem = zrtp_sys_alloc(sizeof(zrtp_sem_t)); + if (NULL == new_sem) { + return zrtp_status_alloc_fail; + } + + new_sem->sem = CreateSemaphore(NULL, val, limit, NULL); + if (!new_sem->sem) { + zrtp_sys_free(new_sem); + return zrtp_status_fail; + } + *sem = new_sem; + return zrtp_status_ok; +} + +zrtp_status_t zrtp_sem_destroy(zrtp_sem_t* sem) +{ + zrtp_status_t s = (0 == CloseHandle(sem->sem)) ? zrtp_status_fail : zrtp_status_ok; + zrtp_sys_free(sem); + return s; +} + +zrtp_status_t zrtp_sem_wait(zrtp_sem_t* sem) +{ + return (WaitForSingleObject(sem->sem, INFINITE) == WAIT_FAILED) ? zrtp_status_fail : zrtp_status_ok; +} + +zrtp_status_t zrtp_sem_trtwait(zrtp_sem_t* sem) +{ + return (WaitForSingleObject(sem->sem, 0) == WAIT_OBJECT_0) ? zrtp_status_ok : zrtp_status_fail; +} + +zrtp_status_t zrtp_sem_post(zrtp_sem_t* sem) +{ + return (0 == ReleaseSemaphore(sem->sem, 1, NULL)) ? zrtp_status_fail : zrtp_status_ok; +} + +#elif (ZRTP_PLATFORM == ZP_LINUX) || (ZRTP_PLATFORM == ZP_DARWIN) || (ZRTP_PLATFORM == ZP_BSD) + +#if defined ZRTP_HAVE_STDIO_H +# include +#endif +#if ZRTP_HAVE_SEMAPHORE_H +# include +#endif +#if ZRTP_HAVE_FCNTL_H +# include +#endif +#if ZRTP_HAVE_ERRNO_H +# include +#endif + + +#if (ZRTP_PLATFORM == ZP_DARWIN) + +struct zrtp_sem_t +{ + sem_t* sem; +}; + +zrtp_status_t zrtp_sem_init(zrtp_sem_t** sem, uint32_t value, uint32_t limit) +{ + zrtp_status_t s = zrtp_status_ok; + char name_buff[48]; + zrtp_time_t now = zrtp_time_now(); + + zrtp_sem_t *new_sem = (zrtp_sem_t*)zrtp_sys_alloc(sizeof(zrtp_sem_t)); + if (0 == new_sem) { + return zrtp_status_alloc_fail; + } + + /* + * This bogusness is to follow what appears to be the lowest common + * denominator in Posix semaphore naming: + * - start with '/' + * - be at most 15 chars + * - be unique and not match anything on the filesystem + * We suppose to generate unique name for every semaphore in the system. + */ + + sprintf(name_buff, "/libzrtp.%llxZ%llx", now/1000, now); + new_sem->sem = sem_open(name_buff, O_CREAT | O_EXCL, S_IRUSR|S_IWUSR, value); + if ((sem_t *)SEM_FAILED == new_sem->sem) { + if (errno == ENAMETOOLONG) { + name_buff[13] = '\0'; + } else if (errno == EEXIST) { + sprintf(name_buff, "/libzrtp.%llxZ%llx", now, now/1000); + } else { + s = zrtp_status_fail; + } + new_sem->sem = sem_open(name_buff, O_CREAT | O_EXCL, 0644, value); + } + + if (new_sem->sem == (sem_t *)SEM_FAILED) { + s = zrtp_status_fail; + zrtp_sys_free(new_sem); + } else { + sem_unlink(name_buff); + *sem = new_sem; + } + + return s; +} + +zrtp_status_t zrtp_sem_destroy(zrtp_sem_t* sem) +{ + zrtp_status_t s = sem_close(sem->sem); + zrtp_sys_free(sem); + if (0 != s) { + s = zrtp_status_fail; + } + + return s; +} + +zrtp_status_t zrtp_sem_wait(zrtp_sem_t* sem) +{ + return (sem_wait(sem->sem) == 0) ? zrtp_status_ok : zrtp_status_fail; +} + +zrtp_status_t zrtp_sem_trtwait(zrtp_sem_t* sem) +{ + return (sem_trywait(sem->sem) == 0) ? zrtp_status_ok : zrtp_status_fail; +} + +zrtp_status_t zrtp_sem_post(zrtp_sem_t* sem) +{ + return (sem_post(sem->sem) == 0) ? zrtp_status_ok : zrtp_status_fail; +} + +#else + +struct zrtp_sem_t +{ + sem_t sem; +}; + + +zrtp_status_t zrtp_sem_init(zrtp_sem_t** sem, uint32_t value, uint32_t limit) +{ + zrtp_sem_t *new_sem = (zrtp_sem_t*)zrtp_sys_alloc(sizeof(zrtp_sem_t)); + if (NULL == new_sem) { + return zrtp_status_alloc_fail; + } + + if (sem_init(&new_sem->sem, 0, value) != 0) { + zrtp_sys_free(new_sem); + return zrtp_status_fail; + } + + *sem = new_sem; + return zrtp_status_ok; +} + +zrtp_status_t zrtp_sem_destroy(zrtp_sem_t* sem) +{ + zrtp_status_t s = sem_destroy(&sem->sem) == 0 ? zrtp_status_ok : zrtp_status_fail; + zrtp_sys_free(sem); + return s; +} + +zrtp_status_t zrtp_sem_wait(zrtp_sem_t* sem) +{ + return (sem_wait(&sem->sem) == 0) ? zrtp_status_ok : zrtp_status_fail; +} + +zrtp_status_t zrtp_sem_trtwait(zrtp_sem_t* sem) +{ + return (sem_trywait(&sem->sem) == 0) ? zrtp_status_ok : zrtp_status_fail; +} + +zrtp_status_t zrtp_sem_post(zrtp_sem_t* sem) +{ + return (sem_post(&sem->sem) == 0) ? zrtp_status_ok : zrtp_status_fail; +} + + +#endif + + +#endif + + +/*============================================================================*/ +/* Default realization of general routine */ +/*============================================================================*/ + +#if defined ZRTP_HAVE_STRING_H +# include /* for memset() and memcpy() */ +#endif + +/*----------------------------------------------------------------------------*/ +#if (ZRTP_PLATFORM == ZP_WIN32_KERNEL) + +void* zrtp_sys_alloc(unsigned int size) +{ + void *VA; + return (NDIS_STATUS_SUCCESS != NdisAllocateMemoryWithTag(&VA, size, (ULONG)"zrtp")) ? NULL : VA; +} + +void zrtp_sys_free(void* obj) +{ + /* Length is 0 because memory was allocated with TAG */ + NdisFreeMemory(obj, 0, 0); +} + +void* zrtp_memcpy(void* dest, const void* src, unsigned int length) +{ + return memcpy(dest,src,length); +} + +void *zrtp_memset(void *s, int c, unsigned int n) +{ + return memset(s, c, n); +} + +zrtp_time_t zrtp_time_now() +{ + LARGE_INTEGER ft; + KeQuerySystemTime(&ft); + + ft.QuadPart -= 116444736000000000; + return (zrtp_time_t)(ft.QuadPart) / 10000; +} +#else + +/*---------------------------------------------------------------------------*/ +#if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WIN64) || (ZRTP_PLATFORM == ZP_WINCE) + +zrtp_time_t zrtp_time_now() +{ + LONGLONG ft; + +#if ZRTP_PLATFORM != ZP_WINCE + GetSystemTimeAsFileTime((LPFILETIME)&ft); +#else + SYSTEMTIME SystemTime; + GetSystemTime(&SystemTime); + SystemTimeToFileTime(&SystemTime, (LPFILETIME)&ft); +#endif + + ft -= 116444736000000000; + return (zrtp_time_t)(ft) / 10000; +} + +/*---------------------------------------------------------------------------*/ +#elif (ZRTP_PLATFORM == ZP_LINUX) || (ZRTP_PLATFORM == ZP_DARWIN) || (ZRTP_PLATFORM == ZP_SYMBIAN) || (ZRTP_PLATFORM == ZP_BSD) + +#if defined ZRTP_HAVE_SYS_TIME_H +# include +#endif + +zrtp_time_t zrtp_time_now() +{ + struct timeval tv; + if (0 == gettimeofday(&tv, 0)) { + return (zrtp_time_t)(tv.tv_sec)*1000 + (zrtp_time_t)(tv.tv_usec)/1000; + } + return 0; +} +#endif + + +void *zrtp_memset(void *s, int c, unsigned int n) +{ + memset(s, c, n); + return s; +} + +void* zrtp_memcpy(void* dest, const void* src, unsigned int length) +{ + memcpy(dest, src, (size_t)length); + return dest; +} + +void* zrtp_sys_alloc(unsigned int size) +{ + return malloc((size_t)size); +} + +void zrtp_sys_free(void* obj) +{ + free(obj); +} + +#endif /* default platform-dependent components realizations */ + +#endif /*ZRTP_USE_BUILTIN*/ diff --git a/src/zrtp_initiator.c b/src/zrtp_initiator.c new file mode 100644 index 0000000000..fd55c6c0dc --- /dev/null +++ b/src/zrtp_initiator.c @@ -0,0 +1,555 @@ +/* + * 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 + */ + +#include "zrtp.h" + +#define _ZTU_ "zrtp initiator" + +extern zrtp_status_t _zrtp_machine_start_initiating_secure(zrtp_stream_t *stream); + +/*! These functions set constructs and start ZRTP messages replays */ +static zrtp_status_t _zrtp_machine_start_send_and_resend_commit(zrtp_stream_t *stream); +static zrtp_status_t _zrtp_machine_start_send_and_resend_dhpart2(zrtp_stream_t *stream); +static zrtp_status_t _zrtp_machine_start_send_and_resend_confirm2(zrtp_stream_t *stream); + +/*! + * We need to know the contents of the DH2 packet before we send the Commit to + * compute the hash value. So, we construct DH packet but don't send it till + * WAITING_FOR_CONFIRM1 state. +*/ +static void _prepare_dhpart2(zrtp_stream_t *stream); + +/* + * Parses DH packet: check for MitM1 attack and makes a copy of the packet for + * later. \exception: Handles all exceptions -- informs user and switches to + * CLEAR.(MITM attacks) + */ +static zrtp_status_t _zrtp_machine_process_incoming_dhpart1( zrtp_stream_t *stream, + zrtp_rtp_info_t *packet); +/* + * Just a wrapper over the protocol::_zrtp_machine_process_confirm(). + * \exception: Handles all exceptions -- informs user and switches to + * CLEAR. (SOFTWARE) + */ +static zrtp_status_t _zrtp_machine_process_incoming_confirm1( zrtp_stream_t *stream, + zrtp_rtp_info_t *packet); + + +/*===========================================================================*/ +/* State handlers */ +/*===========================================================================*/ + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_while_in_initiatingsecure( zrtp_stream_t* stream, + zrtp_rtp_info_t* packet) +{ + zrtp_status_t s = zrtp_status_ok; + + switch (packet->type) + { + case ZRTP_COMMIT: + if (ZRTP_STATEMACHINE_RESPONDER == _zrtp_machine_preparse_commit(stream, packet)) { + _zrtp_cancel_send_packet_later(stream, ZRTP_COMMIT); + s = _zrtp_machine_enter_pendingsecure(stream, packet); + } + break; + + case ZRTP_DHPART1: + if (ZRTP_IS_STREAM_DH(stream)) { + _zrtp_cancel_send_packet_later(stream, ZRTP_COMMIT); + + s = _zrtp_machine_process_incoming_dhpart1(stream, packet); + if (zrtp_status_ok != s) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! _zrtp_machine_process_incoming_dhpart1() failed with status=%d ID=%u\n.", s, stream->id)); + break; + } + + s = _zrtp_machine_start_send_and_resend_dhpart2(stream); + + /* Perform Key generation according to draft 5.6 */ + s = _zrtp_set_public_value(stream, 1); + if (zrtp_status_ok != s) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! set_public_value1() failed with status=%d ID=%u.\n", s, stream->id)); + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_software, 1); + break; + } + + _zrtp_change_state(stream, ZRTP_STATE_WAIT_CONFIRM1); + } + break; + + case ZRTP_CONFIRM1: + if (ZRTP_IS_STREAM_FAST(stream)) { + s = _zrtp_set_public_value(stream, 1); + if (zrtp_status_ok != s) { + break; + } + + s = _zrtp_machine_process_incoming_confirm1(stream, packet); + if (zrtp_status_ok != s) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! process_incoming_confirm1() failed with status=%d ID=%u.\n", s, stream->id)); + break; + } + + _zrtp_cancel_send_packet_later(stream, ZRTP_COMMIT); + _zrtp_change_state(stream, ZRTP_STATE_WAIT_CONFIRMACK); + s = _zrtp_machine_start_send_and_resend_confirm2(stream); + } + break; + + case ZRTP_NONE: + s = zrtp_status_drop; + break; + + default: + break; + } + + return s; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_while_in_waitconfirm1( zrtp_stream_t* stream, + zrtp_rtp_info_t* packet) +{ + zrtp_status_t s = zrtp_status_ok; + + switch (packet->type) + { + case ZRTP_CONFIRM1: + s = _zrtp_machine_process_incoming_confirm1(stream, packet); + if (zrtp_status_ok != s) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! process_incoming_confirm1() failed with status=%d ID=%u.\n", s, stream->id)); + break; + } + + _zrtp_change_state(stream, ZRTP_STATE_WAIT_CONFIRMACK); + _zrtp_cancel_send_packet_later(stream, ZRTP_DHPART2); + s = _zrtp_machine_start_send_and_resend_confirm2(stream); + break; + + case ZRTP_NONE: + s = zrtp_status_drop; + break; + + default: + break; + } + + return s; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_while_in_waitconfirmack( zrtp_stream_t* stream, + zrtp_rtp_info_t* packet) +{ + zrtp_status_t s = zrtp_status_ok; + + switch (packet->type) + { + case ZRTP_NONE: + s = _zrtp_protocol_decrypt(stream->protocol, packet, 1); + if (s == zrtp_status_ok) { + /* + * High level functions triggers mutexes for protocol messages only. + * We have manually protect this transaction triggered by media packet, not protocol packet. + */ + zrtp_mutex_lock(stream->stream_protector); + + ZRTP_LOG(3,(_ZTU_, "Received FIRST VALID SRTP packet - switching to SECURE state. ID=%u\n", stream->id)); + _zrtp_cancel_send_packet_later(stream, ZRTP_CONFIRM2); + _zrtp_machine_enter_secure(stream); + + zrtp_mutex_unlock(stream->stream_protector); + } + break; + + case ZRTP_CONFIRM2ACK: + _zrtp_cancel_send_packet_later(stream, ZRTP_CONFIRM2); + s = _zrtp_machine_enter_secure(stream); + break; + + default: + break; + } + + return s; +} + + +/*===========================================================================*/ +/* State switchers */ +/*===========================================================================*/ + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_enter_initiatingsecure(zrtp_stream_t* stream) +{ + zrtp_status_t s = zrtp_status_ok; + + ZRTP_LOG(3,(_ZTU_,"\tENTER STATE INITIATING SECURE for ID=%u mode=%s state=%s.\n", + stream->id, zrtp_log_mode2str(stream->mode), zrtp_log_state2str(stream->state))); + + if (!ZRTP_IS_STREAM_MULT(stream)) { + uint8_t id = ZRTP_COMP_UNKN; + zrtp_session_t *session = stream->session; + zrtp_packet_Hello_t *peer_hello = &stream->messages.peer_hello; + + /* + * ZRTP specification provides that default crypto components may be + * omitted from the Hello message, so we initialize components with + * default values. + */ + session->hash = zrtp_comp_find(ZRTP_CC_HASH, ZRTP_HASH_SHA256, session->zrtp); + session->blockcipher = zrtp_comp_find(ZRTP_CC_CIPHER, ZRTP_CIPHER_AES128, session->zrtp); + session->authtaglength = zrtp_comp_find(ZRTP_CC_ATL, ZRTP_ATL_HS32, session->zrtp); + session->sasscheme = zrtp_comp_find(ZRTP_CC_SAS, ZRTP_SAS_BASE32, session->zrtp); + + id = _zrtp_choose_best_comp(&session->profile, peer_hello, ZRTP_CC_HASH); + if (id != ZRTP_COMP_UNKN) { + session->hash = zrtp_comp_find(ZRTP_CC_HASH, id, session->zrtp); + } + id = _zrtp_choose_best_comp(&session->profile, peer_hello, ZRTP_CC_CIPHER); + if (id != ZRTP_COMP_UNKN) { + session->blockcipher = zrtp_comp_find(ZRTP_CC_CIPHER, id, session->zrtp); + } + id = _zrtp_choose_best_comp(&session->profile, peer_hello, ZRTP_CC_ATL); + if (id != ZRTP_COMP_UNKN) { + session->authtaglength = zrtp_comp_find(ZRTP_CC_ATL, id, session->zrtp); + } + id = _zrtp_choose_best_comp(&session->profile, peer_hello, ZRTP_CC_SAS); + if (id != ZRTP_COMP_UNKN) { + session->sasscheme = zrtp_comp_find(ZRTP_CC_SAS, id, session->zrtp); + } + + ZRTP_LOG(3,(_ZTU_,"\tInitiator selected following options:\n")); + ZRTP_LOG(3,(_ZTU_,"\t Hash: %.4s\n", session->hash->base.type)); + ZRTP_LOG(3,(_ZTU_,"\t Cipher: %.4s\n", session->blockcipher->base.type)); + ZRTP_LOG(3,(_ZTU_,"\t ATL: %.4s\n", session->authtaglength->base.type)); + ZRTP_LOG(3,(_ZTU_,"\tVAD scheme: %.4s\n", session->sasscheme->base.type)); + } + + do{ + /* Allocate resources for Initiator's state-machine */ + s = _zrtp_protocol_init(stream, 1, &stream->protocol); + if (zrtp_status_ok != s) { + break; /* Software error */ + } + + _zrtp_change_state(stream, ZRTP_STATE_INITIATINGSECURE); + + /* Prepare DHPart2 message to compute hvi. For DH and Preshared streams only*/ + if (ZRTP_IS_STREAM_DH(stream)) { + _prepare_dhpart2(stream); + } + + s = _zrtp_machine_start_send_and_resend_commit(stream); + if (zrtp_status_ok != s) { + break; /* EH: Software error */ + } + + if (stream->zrtp->cb.event_cb.on_zrtp_protocol_event) { + stream->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_IS_INITIATINGSECURE); + } + } while (0); + + if (zrtp_status_ok != s) { + if (stream->protocol) { + _zrtp_protocol_destroy(stream->protocol); + stream->protocol = NULL; + } + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_software, 1); + } + + if (ZRTP_IS_STREAM_DH(stream)) { + /* + * If stream->concurrent is set this means that we stopped a concurrent + * DH stream to break a tie. This can happen when Commit messages are + * sent by both ZRTP endpoints at the same time, but are received in + * different media streams. Now current stream has finished DH setup and + * we can resume the other one. + */ + if (stream->concurrent) { + zrtp_stream_t* tctx = stream->concurrent; + stream->concurrent = NULL; + ZRTP_LOG(3,(_ZTU_,"\tRelease Concurrent Stream ID=%u. ID=%u\n", tctx->id, stream->id)); + _zrtp_machine_start_initiating_secure(tctx); + } + } + + + return s; +} + + +/*===========================================================================*/ +/* Packet handlers */ +/*===========================================================================*/ + +/*---------------------------------------------------------------------------*/ +static zrtp_status_t _zrtp_machine_process_incoming_dhpart1( zrtp_stream_t *stream, + zrtp_rtp_info_t *packet) +{ + zrtp_status_t s = zrtp_status_ok; + zrtp_packet_DHPart_t *dhpart1 = (zrtp_packet_DHPart_t*) packet->message; + + /* Validating DH (pvr is 1 or p-1) */ + bnInsertBigBytes(&stream->dh_cc.peer_pv, dhpart1->pv, 0, stream->pubkeyscheme->pv_length); + + s = stream->pubkeyscheme->validate(stream->pubkeyscheme, &stream->dh_cc.peer_pv); + if (zrtp_status_ok != s) { + ZRTP_LOG(2,(_ZTU_,"\tERROR! " ZRTP_MITM1_WARNING_STR " ID=%u\n", stream->id)); + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_possible_mitm1, 1); + return s; + } + + /* Copy DH Part1 packet for further hashing */ + zrtp_memcpy(&stream->messages.peer_dhpart, dhpart1, zrtp_ntoh16(dhpart1->hdr.length)*4); + + return s; +} + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t _zrtp_machine_process_incoming_confirm1( zrtp_stream_t *stream, + zrtp_rtp_info_t *packet) +{ + return _zrtp_machine_process_confirm(stream, (zrtp_packet_Confirm_t*) packet->message); +} + + +/*===========================================================================*/ +/* Packet senders */ +/*===========================================================================*/ + +static void _send_and_resend_commit(zrtp_stream_t *stream, zrtp_retry_task_t* task) +{ + if (task->_retrys >= ZRTP_T2_MAX_COUNT) { + ZRTP_LOG(2,(_ZTU_,"WARNING! COMMIT Max retransmissions count reached. ID=%u\n", stream->id)); + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_timeout, 0); + } else if (task->_is_enabled) { + zrtp_status_t s = zrtp_status_fail; + zrtp_packet_Commit_t* commit = (zrtp_packet_Commit_t*) &stream->messages.commit; + + s = _zrtp_packet_send_message(stream, ZRTP_COMMIT, commit); + task->timeout = _zrtp_get_timeout((uint32_t)task->timeout, ZRTP_COMMIT); + if (s == zrtp_status_ok) { + task->_retrys++; + } + if (stream->zrtp->cb.sched_cb.on_call_later) { + stream->zrtp->cb.sched_cb.on_call_later(stream, task); + } + } +} + +/*---------------------------------------------------------------------------*/ +static zrtp_status_t _zrtp_machine_start_send_and_resend_commit(zrtp_stream_t *stream) +{ + zrtp_proto_crypto_t* cc = stream->protocol->cc; + zrtp_packet_Commit_t* commit = &stream->messages.commit; + zrtp_retry_task_t* task = &stream->messages.commit_task; + uint8_t hmac_offset = ZRTP_COMMIT_STATIC_SIZE; + zrtp_session_t *session = stream->session; + + zrtp_memcpy(commit->zid, stream->messages.hello.zid, sizeof(zrtp_zid_t)); + + zrtp_memcpy(commit->hash_type, session->hash->base.type, ZRTP_COMP_TYPE_SIZE); + zrtp_memcpy(commit->cipher_type, session->blockcipher->base.type, ZRTP_COMP_TYPE_SIZE); + zrtp_memcpy(commit->auth_tag_length, session->authtaglength->base.type, ZRTP_COMP_TYPE_SIZE ); + zrtp_memcpy(commit->public_key_type, stream->pubkeyscheme->base.type, ZRTP_COMP_TYPE_SIZE); + zrtp_memcpy(commit->sas_type, session->sasscheme->base.type, ZRTP_COMP_TYPE_SIZE); + + /* + * According to the last version of the internet draft 08b., hvi should be + * computed as: + * a) hvi=hash(initiator's DHPart2 message | responder's Hello message) for DH stream. + * b) For Multistream it just a 128 bit random nonce. + * c) For Preshared streams it keyID = HMAC(preshared_key, "Prsh") truncated to 64 bits + */ + switch (stream->mode) + { + case ZRTP_STREAM_MODE_DH: + { + void *hash_ctx = session->hash->hash_begin(session->hash); + if (!hash_ctx) { + return zrtp_status_alloc_fail; + } + + session->hash->hash_update( session->hash, + hash_ctx, + (const int8_t*)&stream->messages.dhpart, + zrtp_ntoh16(stream->messages.dhpart.hdr.length)*4); + session->hash->hash_update( session->hash, + hash_ctx, + (const int8_t*)&stream->messages.peer_hello, + zrtp_ntoh16(stream->messages.peer_hello.hdr.length)*4); + + session->hash->hash_end(session->hash, hash_ctx, ZSTR_GV(cc->hv)); + zrtp_memcpy(commit->hv, cc->hv.buffer, ZRTP_HV_SIZE); + hmac_offset += ZRTP_HV_SIZE; + } break; + + case ZRTP_STREAM_MODE_PRESHARED: + { + zrtp_string8_t key_id = ZSTR_INIT_EMPTY(key_id); + zrtp_status_t s = zrtp_status_ok; + + /* Generate random 4 word nonce */ + if (ZRTP_HV_NONCE_SIZE != zrtp_randstr(session->zrtp, (unsigned char*)cc->hv.buffer, ZRTP_HV_NONCE_SIZE)) { + return zrtp_status_rng_fail; + } + cc->hv.length = ZRTP_HV_NONCE_SIZE; + + /* + * Generate Preshared_key: + * hash(len(rs1) | rs1 | len(auxsecret) | auxsecret | len(pbxsecret) | pbxsecret) + */ + s = _zrtp_compute_preshared_key( session, + ZSTR_GV(session->secrets.rs1->value), + (session->secrets.auxs->_cachedflag) ? ZSTR_GV(session->secrets.auxs->value) : NULL, + (session->secrets.pbxs->_cachedflag) ? ZSTR_GV(session->secrets.pbxs->value) : NULL, + NULL, + ZSTR_GV(key_id)); + if (zrtp_status_ok != s) { + return s; + } + + /* Copy 4 word nonce and add 2 word keyID */ + zrtp_memcpy(commit->hv, cc->hv.buffer, ZRTP_HV_NONCE_SIZE); + hmac_offset += ZRTP_HV_NONCE_SIZE; + + zrtp_memcpy(commit->hv+ZRTP_HV_NONCE_SIZE, key_id.buffer, ZRTP_HV_KEY_SIZE); + hmac_offset += ZRTP_HV_KEY_SIZE; + } break; + + case ZRTP_STREAM_MODE_MULT: + { + if(ZRTP_HV_NONCE_SIZE != zrtp_randstr(session->zrtp, (unsigned char*)cc->hv.buffer, ZRTP_HV_NONCE_SIZE)) { + return zrtp_status_rng_fail; + } + + cc->hv.length = ZRTP_HV_NONCE_SIZE; + zrtp_memcpy(commit->hv, cc->hv.buffer, ZRTP_HV_NONCE_SIZE); + hmac_offset += ZRTP_HV_NONCE_SIZE; + }break; + default: break; + } + + _zrtp_packet_fill_msg_hdr(stream, ZRTP_COMMIT, hmac_offset + ZRTP_HMAC_SIZE, &commit->hdr); + + { + char buff[256]; + ZRTP_LOG(3,(_ZTU_,"\tStart Sending COMMIT ID=%u mode=%s state=%s:\n", + stream->id, zrtp_log_mode2str(stream->mode), zrtp_log_state2str(stream->state))); + ZRTP_LOG(3,(_ZTU_,"\t Hash: %.4s\n", commit->hash_type)); + ZRTP_LOG(3,(_ZTU_,"\t Cipher: %.4s\n", commit->cipher_type)); + ZRTP_LOG(3,(_ZTU_,"\t ATL: %.4s\n", commit->auth_tag_length)); + ZRTP_LOG(3,(_ZTU_,"\t PK scheme: %.4s\n", commit->public_key_type)); + ZRTP_LOG(3,(_ZTU_,"\tVAD scheme: %.4s\n", commit->sas_type)); + + ZRTP_LOG(3,(_ZTU_,"\t hv: %s\n", hex2str((const char*)commit->hv, ZRTP_HV_SIZE, (char*)buff, sizeof(buff)))); + } + + task->_is_enabled = 1; + task->callback = _send_and_resend_commit; + task->_retrys = 0; + _send_and_resend_commit(stream, task); + + return zrtp_status_ok; +} + +/*----------------------------------------------------------------------------*/ +static void _send_and_resend_dhpart2(zrtp_stream_t *stream, zrtp_retry_task_t* task) +{ + if (task->_retrys >= ZRTP_T2_MAX_COUNT) + { + ZRTP_LOG(1,(_ZTU_,"WARNING! DH2 Max retransmissions count reached. ID=%u\n", stream->id)); + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_timeout, 0); + } else if (task->_is_enabled) { + zrtp_status_t s = _zrtp_packet_send_message(stream, ZRTP_DHPART2, &stream->messages.dhpart); + task->timeout = _zrtp_get_timeout((uint32_t)task->timeout, ZRTP_DHPART2); + if (zrtp_status_ok == s) { + task->_retrys++; + } + if (stream->zrtp->cb.sched_cb.on_call_later) { + stream->zrtp->cb.sched_cb.on_call_later(stream, task); + } + } +} + +static void _prepare_dhpart2(zrtp_stream_t *stream) +{ + zrtp_proto_crypto_t* cc = stream->protocol->cc; + zrtp_packet_DHPart_t *dh2 = &stream->messages.dhpart; + uint16_t dh_length = (uint16_t)stream->pubkeyscheme->pv_length; + + zrtp_memcpy(dh2->rs1ID, cc->rs1.id.buffer, ZRTP_RSID_SIZE); + zrtp_memcpy(dh2->rs2ID, cc->rs2.id.buffer, ZRTP_RSID_SIZE); + zrtp_memcpy(dh2->auxsID, cc->auxs.id.buffer, ZRTP_RSID_SIZE); + zrtp_memcpy(dh2->pbxsID, cc->pbxs.id.buffer, ZRTP_RSID_SIZE); + + bnExtractBigBytes(&stream->dh_cc.pv, dh2->pv, 0, dh_length); + + _zrtp_packet_fill_msg_hdr( stream, + ZRTP_DHPART2, + dh_length + ZRTP_DH_STATIC_SIZE + ZRTP_HMAC_SIZE, + &dh2->hdr ); +} + +static zrtp_status_t _zrtp_machine_start_send_and_resend_dhpart2(zrtp_stream_t *stream) +{ + zrtp_retry_task_t* task = &stream->messages.dhpart_task; + + task->_is_enabled = 1; + task->callback = _send_and_resend_dhpart2; + task->_retrys = 0; + _send_and_resend_dhpart2(stream, task); + + return zrtp_status_ok; +} + + +/*---------------------------------------------------------------------------*/ +static void _send_and_resend_confirm2(zrtp_stream_t *stream, zrtp_retry_task_t* task) +{ + if (task->_retrys >= ZRTP_T2_MAX_COUNT) { + ZRTP_LOG(1,(_ZTU_,"WARNING! CONFIRM2 Max retransmissions count reached. ID=%u\n", stream->id)); + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_timeout, 0); + } else if (task->_is_enabled) { + zrtp_status_t s = zrtp_status_ok; + s = _zrtp_packet_send_message(stream, ZRTP_CONFIRM2, &stream->messages.confirm); + task->timeout = _zrtp_get_timeout((uint32_t)task->timeout, ZRTP_CONFIRM2); + if (zrtp_status_ok == s) { + task->_retrys++; + } + if (stream->zrtp->cb.sched_cb.on_call_later) { + stream->zrtp->cb.sched_cb.on_call_later(stream, task); + } + } +} + +static zrtp_status_t _zrtp_machine_start_send_and_resend_confirm2(zrtp_stream_t *stream) +{ + zrtp_retry_task_t* task = &stream->messages.confirm_task; + + zrtp_status_t s = _zrtp_machine_create_confirm(stream, &stream->messages.confirm); + if (zrtp_status_ok != s) { + return s; + } + + s = _zrtp_packet_fill_msg_hdr( stream, + ZRTP_CONFIRM2, + sizeof(zrtp_packet_Confirm_t) - sizeof(zrtp_msg_hdr_t), + &stream->messages.confirm.hdr); + + task->_is_enabled = 1; + task->callback = _send_and_resend_confirm2; + task->_retrys = 0; + _send_and_resend_confirm2(stream, task); + + return zrtp_status_ok; +} diff --git a/src/zrtp_legal.c b/src/zrtp_legal.c new file mode 100644 index 0000000000..bd9047cf07 --- /dev/null +++ b/src/zrtp_legal.c @@ -0,0 +1,25 @@ +/* + * libZRTP SDK library, implements the ZRTP secure VoIP protocol. + * Copyright (c) 2006-2009 Philip R. Zimmermann. All rights reserved. + * + * The version of the SDK library that is packaged with this legal notice is + * NOT licensed under the GPL, AGPL, LGPL, or any other open source license. + * For licensing terms or other information, + * contact Philip R. Zimmermann . + * For more contact information, see http://philzimmermann.com + * + * This file must be packaged together with the rest of the libZRTP SDK + * source code. That's why it's in a .c file. + * + * This software may be subject to export controls by the US Commerce + * Department's Bureau of Industry and Security. This software is provided + * "as is," with no warranty expressed or implied. + * + */ + +/* Force inclusion of this copyright string in the linked binary, + * accessible to the unix strings command. */ +#include "zrtp_legal.h" +volatile const char zrtpCopyright[] = + "\0libZRTP Copyright (c) 2006-2009 Philip R. Zimmermann."; + diff --git a/src/zrtp_list.c b/src/zrtp_list.c new file mode 100644 index 0000000000..5cea2fcfdd --- /dev/null +++ b/src/zrtp_list.c @@ -0,0 +1,66 @@ +/* + * 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 + */ + +#include "zrtp.h" + +/*----------------------------------------------------------------------------*/ +void init_mlist(mlist_t* head) { + head->next = head; + head->prev = head; +} + +/*----------------------------------------------------------------------------*/ +static void mlist_insert_node(mlist_t* node, mlist_t* prev, mlist_t* next) { + next->prev = node; + node->next = next; + node->prev = prev; + prev->next = node; +} + +void mlist_insert(mlist_t *prev, mlist_t *node) { + mlist_insert_node(node, prev->prev, prev); +} + +void mlist_add(mlist_t* head, mlist_t* node) { + mlist_insert_node(node, head, head->next); +} + +void mlist_add_tail(mlist_t *head, mlist_t *node) { + mlist_insert_node(node, head->prev, head); +} + +/*----------------------------------------------------------------------------*/ +static void mlist_remove(mlist_t* prev, mlist_t* next) { + next->prev = prev; + prev->next = next; +} + +void mlist_del(mlist_t *node) { + mlist_remove(node->prev, node->next); + node->next = node->prev = 0; +} + +void mlist_del_tail(mlist_t *node) { + mlist_remove(node->prev, node->next); + node->next = node->prev = 0; +} + +/*----------------------------------------------------------------------------*/ +mlist_t* mlist_get(mlist_t *head) { + return (head->next != head) ? head->next : 0; +} + +mlist_t* mlist_get_tail(mlist_t *head) { + return (head->prev != head) ? head->prev : 0; +} + +/*----------------------------------------------------------------------------*/ +int mlist_isempty(mlist_t *head) { + return (head->next == head); +} diff --git a/src/zrtp_log.c b/src/zrtp_log.c new file mode 100644 index 0000000000..0b89583352 --- /dev/null +++ b/src/zrtp_log.c @@ -0,0 +1,481 @@ +/* + * 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 + */ + +#include "zrtp.h" + +#if (ZRTP_PLATFORM == ZP_WIN32_KERNEL) +#include +#include +#endif + +#if ZRTP_LOG_MAX_LEVEL >= 1 + +/*----------------------------------------------------------------------------*/ +#if defined ZRTP_HAVE_STDIO_H +# include +#endif +#if defined ZRTP_HAVE_STRING_H +# include +#endif +#if defined ZRTP_HAVE_STDARG_H +# include +#endif + +static const char* k_unknown = "UNKNOWN"; + +#if ZRTP_PLATFORM != ZP_WIN32_KERNEL +void zrtp_def_log_write(int level, char *buffer, int len, int offset) { + printf("%s", buffer); +} + +static zrtp_log_engine *log_writer = &zrtp_def_log_write; +#else +static zrtp_log_engine *log_writer = NULL; +#endif + +static uint32_t log_max_level = ZRTP_LOG_MAX_LEVEL; + + +/*----------------------------------------------------------------------------*/ +void zrtp_log_set_level(uint32_t level) { + log_max_level = level; +} + +void zrtp_log_set_log_engine(zrtp_log_engine *engine) { + log_writer = engine; +} + +static const uint32_t zrtp_log_header_allign = 16; + +/*----------------------------------------------------------------------------*/ +static void zrtp_log(uint8_t is_clean, const char *sender, uint32_t level, const char *format, va_list marker) +{ +#if (defined(ZRTP_USE_STACK_MINIM) && (ZRTP_USE_STACK_MINIM == 1)) + char *log_buffer = zrtp_sys_alloc(ZRTP_LOG_BUFFER_SIZE); +#else + char log_buffer[ZRTP_LOG_BUFFER_SIZE]; +#endif + char* sline = log_buffer; + uint32_t offset = 0; + int len = 0; + + if (!sline) { + return; + } + + if (!is_clean) { + /* Print sender with left aligment */ + uint32_t sender_len = strlen(sender); + *sline++ = ' '; + *sline++ = '['; + if (sender_len <= ZRTP_LOG_SENDER_MAX_LEN) { + while (sender_len < ZRTP_LOG_SENDER_MAX_LEN) { + *sline++ = ' ', ++sender_len; + } + while (*sender) { + *sline++ = *sender++; + } + } else { + int i = 0; + for (i=0; i= 1400) && (ZRTP_PLATFORM != ZP_WINCE) + len = _vsnprintf_s(sline, ZRTP_LOG_BUFFER_SIZE-offset-1, ZRTP_LOG_BUFFER_SIZE-offset-1, format, marker); +# else + len = _vsnprintf(sline, ZRTP_LOG_BUFFER_SIZE-offset, format, marker); +# endif +#elif (ZRTP_PLATFORM == ZP_WIN32_KERNEL) + RtlStringCchVPrintfA(sline, ZRTP_LOG_BUFFER_SIZE-offset, format, marker); +#elif (ZRTP_PLATFORM == ZP_LINUX) || (ZRTP_PLATFORM == ZP_DARWIN) || (ZRTP_PLATFORM == ZP_BSD) + len = vsnprintf(sline, ZRTP_LOG_BUFFER_SIZE-offset, format, marker); +#elif (ZRTP_PLATFORM == ZP_SYMBIAN) + len = vsprintf(sline, format, marker); +#endif + + if ((len > 0) && log_writer) { + (*log_writer)(level, log_buffer, len+offset, offset); + } + +#if (defined(ZRTP_USE_STACK_MINIM) && (ZRTP_USE_STACK_MINIM == 1)) + zrtp_sys_free(log_buffer); +#endif +} + + +#if ZRTP_LOG_MAX_LEVEL >= 1 +void zrtp_log_1(const char *obj, const char *format, ...) +{ + va_list arg; + va_start(arg, format); + zrtp_log(0, obj, 1, format, arg); + va_end(arg); +} +void zrtp_logc_1(const char *format, ...) +{ + va_list arg; + va_start(arg, format); + zrtp_log(1, NULL, 1, format, arg); + va_end(arg); +} + +#endif + +#if ZRTP_LOG_MAX_LEVEL >= 2 +void zrtp_log_2(const char *obj, const char *format, ...) +{ + va_list arg; + va_start(arg, format); + zrtp_log(0, obj, 2, format, arg); + va_end(arg); +} +void zrtp_logc_2(const char *format, ...) +{ + va_list arg; + va_start(arg, format); + zrtp_log(1, NULL, 2, format, arg); + va_end(arg); +} + +#endif + +#if ZRTP_LOG_MAX_LEVEL >= 3 +void zrtp_log_3(const char *obj, const char *format, ...) +{ + va_list arg; + va_start(arg, format); + zrtp_log(0, obj, 3, format, arg); + va_end(arg); +} +void zrtp_logc_3(const char *format, ...) +{ + va_list arg; + va_start(arg, format); + zrtp_log(1, NULL, 3, format, arg); + va_end(arg); +} + +#endif + +#endif + +/*---------------------------------------------------------------------------*/ +struct _error_strings_t +{ + zrtp_protocol_error_t code; + char* descr; +}; + +static const struct _error_strings_t _error_strings[] = { + {zrtp_error_unknown, "Unknown"}, + {zrtp_error_timeout, "Protocol Packets Retries Timeout"}, + {zrtp_error_invalid_packet, "Malformed packet (CRC OK, but wrong structure)"}, + {zrtp_error_software, "Critical software error: no memory, can't call some system function, etc"}, + {zrtp_error_version, "Unsupported ZRTP version"}, + {zrtp_error_hello_mistmatch,"Hello components mismatch "}, + + {zrtp_error_hash_unsp, "Hash type not supported"}, + {zrtp_error_cipher_unsp, "Cipher type not supported"}, + {zrtp_error_pktype_unsp, "Public key exchange not supported"}, + {zrtp_error_auth_unsp, "SRTP auth. tag not supported"}, + {zrtp_error_sas_unsp, "SAS scheme not supported"}, + {zrtp_error_no_secret, "No shared secret available, DH mode required"}, + + {zrtp_error_possible_mitm1, "Attack DH Error: bad pvi or pvr ( == 1, 0, or p-1)"}, + {zrtp_error_possible_mitm2, "Attack DH Error: hvi != hashed data"}, + {zrtp_error_possible_mitm3, "Attack Received relayed SAS from untrusted MiTM"}, + + {zrtp_error_auth_decrypt, "Auth. Error: Bad Confirm pkt HMAC"}, + {zrtp_error_nonse_reuse, "Nonce reuse"}, + {zrtp_error_equal_zid, "Equal ZIDs in Hello"}, + {zrtp_error_service_unavail,"Service unavailable"}, + {zrtp_error_goclear_unsp, "GoClear packet received, but not allowed"}, + + {zrtp_error_wrong_zid, "ZID received in new Hello doesn't equal to ZID from the previous stream"}, + {zrtp_error_wrong_meshmac, "Message HMAC doesn't match with pre-received one"} +}; + +const char* zrtp_log_error2str(zrtp_protocol_error_t error) +{ + int i=0; + for(i=0; i<22; i++) { + if (error == _error_strings[i].code) { + return _error_strings[i].descr; + } + } + + return k_unknown; +} + +/*---------------------------------------------------------------------------*/ +static char* _status_strings[zrtp_status_count] = +{ + "OK status", + "General, unspecified failure", + "Wrong, unsupported parameter", + "Fail allocate memory", + "SRTP authentication failure", + "Cipher failure on RTP encrypt/decrypt", + "General Crypto Algorithm failure", + "SRTP can't use key any longer", + "Input buffer too small", + "Packet process DROP status", + "Failed to open file/device", + "Unable to read data from the file/stream", + "Unable to write to the file/stream", + "SRTP packet is out of sliding window", + "RTP replay protection failed", + "ZRTP replay protection failed", + "ZRTP packet CRC is wrong", + "Can't generate random value", + "Illegal operation in current state", + "Attack detected", + "Function is not available in current configuration" +}; + +const char* zrtp_log_status2str(zrtp_status_t error) +{ + if (zrtp_status_count > error) { + return _status_strings[error]; + } else { + return k_unknown; + } +} + +/*---------------------------------------------------------------------------*/ +static char* _state_names[ZRTP_STATE_COUNT] = +{ + "NONE", + "ACTIVE", + "START", + "W4HACK", + "W4HELLO", + "CLEAR", + "SINITSEC", + "INITSEC", + "WCONFIRM", + "W4CONFACK", + "PENDSEC", + "W4CONF2", + "SECURE", + "SASRELAY", + "INITCLEAR", + "PENDCLEAR", + "INITERROR", + "PENDERROR", + "ERROR", + #if (defined(ZRTP_BUILD_FOR_CSD) && (ZRTP_BUILD_FOR_CSD == 1)) + "DRIVINIT", + "DRIVRESP", + "DRIVPEND", + #endif + "NOZRTP" +}; + +const char* zrtp_log_state2str(zrtp_state_t state) +{ + if (state < ZRTP_STATE_COUNT) { + return _state_names[state]; + } else { + return k_unknown; + } +}; + +/*---------------------------------------------------------------------------*/ +static char* _stream_mode_name[ZRTP_STREAM_MODE_COUNT] = +{ + "UNKNOWN", + "CLEAR", + "DH", + "PRESHARED", + "MULTI" +}; + +const char* zrtp_log_mode2str(zrtp_stream_mode_t mode) +{ + if (mode < ZRTP_STREAM_MODE_COUNT) { + return _stream_mode_name[mode]; + } else { + return k_unknown; + } +}; + +/*---------------------------------------------------------------------------*/ +static char* _msg_type_names[ZRTP_MSG_TYPE_COUNT] = +{ + "NONE", + "HELLO", + "HELLOACK", + "COMMIT", + "DH1", + "DH2", + "CONFIRM1", + "CONFIRM2", + "CONFIRMACK", + "GOCLEAR", + "CLEARACKE", + "ERROR", + "ERRORACK", + "PROCESS", + "SASRELAY", + "RELAYACK", + "PING", + "PINGACK", +}; + +const char* zrtp_log_pkt2str(zrtp_msg_type_t type) +{ + if (type < ZRTP_MSG_TYPE_COUNT) { + return _msg_type_names[type]; + } else { + return k_unknown; + } +} + +/*---------------------------------------------------------------------------*/ +static char* _event_code_name[] = +{ + "ZRTP_EVENT_UNSUPPORTED", + "ZRTP_EVENT_IS_CLEAR", + "ZRTP_EVENT_IS_INITIATINGSECURE", + "ZRTP_EVENT_IS_PENDINGSECURE", + "ZRTP_EVENT_IS_PENDINGCLEAR", + "ZRTP_EVENT_NO_ZRTP", + "ZRTP_EVENT_NO_ZRTP_QUICK", + "ZRTP_EVENT_IS_CLIENT_ENROLLMENT", + "ZRTP_EVENT_NEW_USER_ENROLLED", + "ZRTP_EVENT_USER_ALREADY_ENROLLED", + "ZRTP_EVENT_USER_UNENROLLED", + "ZRTP_EVENT_LOCAL_SAS_UPDATED", + "ZRTP_EVENT_REMOTE_SAS_UPDATED", + "ZRTP_EVENT_IS_SECURE", + "ZRTP_EVENT_IS_SECURE_DONE", + "ZRTP_EVENT_IS_PASSIVE_RESTRICTION", + "ZRTP_EVENT_PROTOCOL_ERROR", + "ZRTP_EVENT_WRONG_SIGNALING_HASH", + "ZRTP_EVENT_WRONG_MESSAGE_HMAC", + "ZRTP_EVENT_MITM_WARNING" +}; + +const char* zrtp_log_event2str(uint8_t event) +{ + if (event <= ZRTP_EVENT_WRONG_MESSAGE_HMAC) { + return _event_code_name[event]; + } else { + return k_unknown; + } +} + +/*---------------------------------------------------------------------------*/ +typedef struct _zrtp_aling_test +{ + uint_8t c1; + uint_8t c2; + uint_8t c3; +} _zrtp_aling_test; + +void zrtp_print_env_settings(zrtp_config_t* config) +{ +#if (ZRTP_PLATFORM == ZP_WIN32) + char* platform = "Windows 32bit"; +#elif (ZRTP_PLATFORM == ZP_WIN32_KERNEL) + char* platform = "Windows Kernel 32bit"; +#elif (ZRTP_PLATFORM == ZP_WINCE) + char* platform = "Windows CE"; +#elif (ZRTP_PLATFORM == ZP_DARWIN) + char* platform = "Darwin OS X"; +#elif (ZRTP_PLATFORM == ZP_BSD) + char* platform = "BSD"; +#elif (ZRTP_PLATFORM == ZP_LINUX) + char* platform = "Linux OS"; +#elif (ZRTP_PLATFORM == ZP_SYMBIAN) + char* platform = "Symbian OS"; +#endif + + ZRTP_LOG(3,("zrtp","============================================================\n")); + ZRTP_LOG(3,("zrtp","ZRTP Configuration Settings\n")); + ZRTP_LOG(3,("zrtp","============================================================\n")); + ZRTP_LOG(3,("zrtp"," PLATFORM: %s\n", platform)); +#if (ZRTP_BYTE_ORDER == ZBO_BIG_ENDIAN) + ZRTP_LOG(3,("zrtp"," BYTE ORDER: BIG ENDIAN\n")); +#else + ZRTP_LOG(3,("zrtp"," BYTE ORDER: LITTLE ENDIAN\n")); +#endif + ZRTP_LOG(3,("zrtp"," ZRTP_SAS_DIGEST_LENGTH: %d\n", ZRTP_SAS_DIGEST_LENGTH)); + ZRTP_LOG(3,("zrtp"," ZRTP_MAX_STREAMS_PER_SESSION: %d\n", ZRTP_MAX_STREAMS_PER_SESSION)); + ZRTP_LOG(3,("zrtp"," ZRTP_USE_EXTERN_SRTP: %d\n", ZRTP_USE_EXTERN_SRTP)); + ZRTP_LOG(3,("zrtp"," ZRTP_USE_STACK_MINIM: %d\n", ZRTP_USE_STACK_MINIM)); + ZRTP_LOG(3,("zrtp"," ZRTP_BUILD_FOR_CSD: %d\n", ZRTP_BUILD_FOR_CSD)); + ZRTP_LOG(3,("zrtp"," ZRTP_USE_BUILTIN: %d\n", ZRTP_USE_BUILTIN)); + ZRTP_LOG(3,("zrtp"," ZRTP_USE_BUILTIN_SCEHDULER: %d\n", ZRTP_USE_BUILTIN_SCEHDULER)); + ZRTP_LOG(3,("zrtp"," ZRTP_USE_BUILTIN_CACHE: %d\n", ZRTP_USE_BUILTIN_CACHE)); + ZRTP_LOG(3,("zrtp"," ZRTP_LOG_MAX_LEVEL: %d\n", ZRTP_LOG_MAX_LEVEL)); + + ZRTP_LOG(3,("zrtp"," sizeo of unsigned int: %d\n", sizeof(unsigned int))); + ZRTP_LOG(3,("zrtp"," size of unsigned long long: %d\n", sizeof(unsigned long long))); + ZRTP_LOG(3,("zrtp"," sizeo of three chars: %d\n", sizeof(_zrtp_aling_test))); + ZRTP_LOG(3,("zrtp","\n")); + ZRTP_LOG(3,("zrtp","ZRTP Initialization Settings\n")); + ZRTP_LOG(3,("zrtp"," client ID: %s\n", config->client_id)); + ZRTP_LOG(3,("zrtp"," license: %d\n", config->lic_mode)); + ZRTP_LOG(3,("zrtp"," MiTM: %s\n", config->is_mitm?"ENABLED":"DIABLED")); + ZRTP_LOG(3,("zrtp"," cache path: %s\n", config->def_cache_path.length?config->def_cache_path.buffer:"")); +} + +/*---------------------------------------------------------------------------*/ +void zrtp_log_print_streaminfo(zrtp_stream_info_t* info) +{ + ZRTP_LOG(3,("zrtp"," ZRTP Stream ID=%u\n", info->id)); + ZRTP_LOG(3,("zrtp"," mode: %s\n", zrtp_log_mode2str(info->mode))); + ZRTP_LOG(3,("zrtp"," state: %s\n", zrtp_log_state2str(info->state))); + ZRTP_LOG(3,("zrtp"," error: %s\n", zrtp_log_error2str(info->last_error))); + + ZRTP_LOG(3,("zrtp"," peer passive: %s\n", info->peer_passive?"ON":"OFF")); + ZRTP_LOG(3,("zrtp"," peer disclose: %s\n", info->peer_disclose?"ON":"OFF")); + ZRTP_LOG(3,("zrtp"," peer mitm: %s\n", info->peer_mitm?"ON":"OFF")); + ZRTP_LOG(3,("zrtp"," res allowclear: %s\n", info->res_allowclear?"ON":"OFF")); +} + +void zrtp_log_print_sessioninfo(zrtp_session_info_t* info) +{ + char buffer[256]; + + ZRTP_LOG(3,("zrtp"," ZRTP Session sID=%u is ready=%s\n", info->id, info->sas_is_ready?"YES":"NO")); + ZRTP_LOG(3,("zrtp"," peer client: <%s> V=<%s>\n", info->peer_clientid.buffer, info->peer_version.buffer)); + hex2str(info->zid.buffer, info->zid.length, buffer, sizeof(buffer)); + ZRTP_LOG(3,("zrtp"," zid: %s\n", buffer)); + hex2str(info->peer_zid.buffer, info->peer_zid.length, buffer, sizeof(buffer)); + ZRTP_LOG(3,("zrtp"," peer zid: %s\n", buffer)); + hex2str(info->zid.buffer, info->zid.length, buffer, sizeof(buffer)); + + ZRTP_LOG(3,("zrtp"," is base256: %s\n", info->sas_is_base256?"YES":"NO")); + ZRTP_LOG(3,("zrtp"," SAS1: %s\n", info->sas1.buffer)); + ZRTP_LOG(3,("zrtp"," SAS2: %s\n", info->sas2.buffer)); + hex2str(info->sasbin.buffer, info->sasbin.length, buffer, sizeof(buffer)); + ZRTP_LOG(3,("zrtp"," bin SAS: %s\n", buffer)); + ZRTP_LOG(3,("zrtp"," TTL: %u\n", info->secrets_ttl)); + + ZRTP_LOG(3,("zrtp"," hash: %s\n", info->hash_name.buffer)); + ZRTP_LOG(3,("zrtp"," cipher: %s\n", info->cipher_name.buffer)); + ZRTP_LOG(3,("zrtp"," auth: %s\n", info->auth_name.buffer)); + ZRTP_LOG(3,("zrtp"," sas: %s\n", info->sas_name.buffer)); + ZRTP_LOG(3,("zrtp"," pks: %s\n", info->pk_name.buffer)); +} diff --git a/src/zrtp_pbx.c b/src/zrtp_pbx.c new file mode 100644 index 0000000000..a7e399ec39 --- /dev/null +++ b/src/zrtp_pbx.c @@ -0,0 +1,587 @@ +/* + * 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 + */ + +#include "zrtp.h" + +#define _ZTU_ "zrtp mitm" + +extern zrtp_status_t _zrtp_machine_process_goclear(zrtp_stream_t* stream, zrtp_rtp_info_t* packet); + + +/*===========================================================================*/ +/* State-Machine related functions */ +/*===========================================================================*/ + +/*---------------------------------------------------------------------------*/ +static void _send_and_resend_sasrelay(zrtp_stream_t *stream, zrtp_retry_task_t* task) +{ + if (task->_retrys >= ZRTP_T2_MAX_COUNT) { + ZRTP_LOG(1,(_ZTU_,"WARNING! SASRELAY Max retransmissions count reached. ID=%u\n", stream->id)); + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_timeout, 0); + } else if (task->_is_enabled) { + zrtp_status_t s = _zrtp_packet_send_message(stream, ZRTP_SASRELAY, &stream->messages.sasrelay); + task->timeout = _zrtp_get_timeout((uint32_t)task->timeout, ZRTP_SASRELAY); + if (zrtp_status_ok == s) { + task->_retrys++; + } + if (stream->zrtp->cb.sched_cb.on_call_later) { + stream->zrtp->cb.sched_cb.on_call_later(stream, task); + } + } +} + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t _create_sasrelay( zrtp_stream_t *stream, + zrtp_sas_id_t transf_sas_scheme, + zrtp_string32_t* transf_sas_value, + uint8_t transf_ac_flag, + uint8_t transf_d_flag, + zrtp_packet_SASRelay_t* sasrelay ) +{ + zrtp_session_t *session = stream->session; + zrtp_status_t s = zrtp_status_fail; + void* cipher_ctx = NULL; + + /* (padding + sig_len + flags) + SAS scheme and SASHash */ + const uint8_t encrypted_body_size = (2 + 1 + 1) + 4 + 32; + + zrtp_memset(sasrelay, 0, sizeof(zrtp_packet_SASRelay_t)); + + /* generate a random initialization vector for CFB cipher */ + if (ZRTP_CFBIV_SIZE != zrtp_randstr(session->zrtp, sasrelay->iv, ZRTP_CFBIV_SIZE)) { + return zrtp_status_rp_fail; + } + + sasrelay->flags |= (session->profile.disclose_bit || transf_d_flag) ? 0x01 : 0x00; + sasrelay->flags |= (session->profile.allowclear && transf_ac_flag) ? 0x02 : 0x00; + sasrelay->flags |= 0x04; + + zrtp_memcpy( sasrelay->sas_scheme, + zrtp_comp_id2type(ZRTP_CC_SAS, transf_sas_scheme), + ZRTP_COMP_TYPE_SIZE ); + if (transf_sas_value) + zrtp_memcpy(sasrelay->sashash, transf_sas_value->buffer, transf_sas_value->length); + + /* Then we need to encrypt Confirm before computing Hmac. Use AES CFB */ + do { + cipher_ctx = session->blockcipher->start( session->blockcipher, + (uint8_t*)stream->cc.zrtp_key.buffer, + NULL, + ZRTP_CIPHER_MODE_CFB ); + if (!cipher_ctx) { + break; + } + + s = session->blockcipher->set_iv( session->blockcipher, + cipher_ctx, + (zrtp_v128_t*)sasrelay->iv); + if (zrtp_status_ok != s) { + break; + } + + s = session->blockcipher->encrypt( session->blockcipher, + cipher_ctx, + (uint8_t*)&sasrelay->pad, + encrypted_body_size ); + } while(0); + if (cipher_ctx) { + session->blockcipher->stop(session->blockcipher, cipher_ctx); + } + + if (zrtp_status_ok != s) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! Failed to encrypt SASRELAY Message status=%d. ID=%u\n", s, stream->id)); + return s; + } + + /* Compute Hmac over encrypted part of Confirm */ + { + zrtp_string128_t hmac = ZSTR_INIT_EMPTY(hmac); + s = session->hash->hmac_c( session->hash, + stream->cc.hmackey.buffer, + stream->cc.hmackey.length, + (const char*)&sasrelay->pad, + encrypted_body_size, + ZSTR_GV(hmac) ); + if (zrtp_status_ok != s) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! Failed to compute CONFIRM hmac status=%d. ID=%u\n", s, stream->id)); + return s; + } + zrtp_memcpy(sasrelay->hmac, hmac.buffer, ZRTP_HMAC_SIZE); + } + + return s; +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_sasrelay(zrtp_stream_t *stream, zrtp_rtp_info_t *packet) +{ + zrtp_session_t *session = stream->session; + zrtp_packet_SASRelay_t *sasrelay = (zrtp_packet_SASRelay_t*) packet->message; + void* cipher_ctx = NULL; + zrtp_sas_id_t rendering_id = ZRTP_COMP_UNKN; + zrtp_status_t s = zrtp_status_fail; + zrtp_string128_t hmac = ZSTR_INIT_EMPTY(hmac); + char zerosashash[32]; + + /* (padding + sig_len + flags) + SAS scheme and SAS hash */ + const uint8_t encrypted_body_size = (2 + 1 + 1) + 4 + 32; + + zrtp_memset(zerosashash, 0, sizeof(zerosashash)); + + /* Check if the remote endpoint is assiggneed to relay the SAS values */ + if (!stream->peer_mitm_flag) { + ZRTP_LOG(2,(_ZTU_, ZRTP_RELAYED_SAS_FROM_NONMITM_STR)); + return zrtp_status_fail; + } + + /* Check the HMAC */ + s = session->hash->hmac_c( session->hash, + stream->cc.peer_hmackey.buffer, + stream->cc.peer_hmackey.length, + (const char*)&sasrelay->pad, + encrypted_body_size, + ZSTR_GV(hmac) ); + if (zrtp_status_ok != s ) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! Failed to compute CONFIRM hmac. status=%d ID=%u\n", s, stream->id)); + return zrtp_status_fail; + } + + if (0 != zrtp_memcmp(sasrelay->hmac, hmac.buffer, ZRTP_HMAC_SIZE)) { + ZRTP_LOG(2,(_ZTU_, ZRTP_VERIFIED_RESP_WARNING_STR)); + return zrtp_status_fail; + } + + ZRTP_LOG(3,(_ZTU_, "\tHMAC value for the SASRELAY is correct - decryptiong...\n")); + + /* Then we need to decrypt Confirm body */ + do + { + cipher_ctx = session->blockcipher->start( session->blockcipher, + (uint8_t*)stream->cc.peer_zrtp_key.buffer, + NULL, + ZRTP_CIPHER_MODE_CFB ); + if (!cipher_ctx) { + break; + } + + s = session->blockcipher->set_iv(session->blockcipher, cipher_ctx, (zrtp_v128_t*)sasrelay->iv); + if (zrtp_status_ok != s) { + break; + } + + s = session->blockcipher->encrypt( session->blockcipher, + cipher_ctx, + (uint8_t*)&sasrelay->pad, + encrypted_body_size); + } while(0); + if (cipher_ctx) { + session->blockcipher->stop(session->blockcipher, cipher_ctx); + } + + if (zrtp_status_ok != s) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! Failed to decrypt Confirm. status=%d ID=%u\n", s, stream->id)); + return s; + } + + ZRTP_LOG(2,(_ZTU_,"\tSasRelay FLAGS old/new A=%d/%d, D=%d/%d.\n", + stream->allowclear, (uint8_t)(sasrelay->flags & 0x02), + stream->peer_disclose_bit, (uint8_t)(sasrelay->flags & 0x01))); + + /* Set evil bit if other-side disclosed session key */ + stream->peer_disclose_bit = (sasrelay->flags & 0x01); + + /* Enable ALLOWCLEAR option only if both sides support it */ + stream->allowclear = (sasrelay->flags & 0x02) && session->profile.allowclear; + + /* + * We don't handle verified flag in SASRelaying because it makes no + * sense in implementation of the ZRTP Internet Draft. + */ + + /* + * Only enrolled users can do SAS transferring. (Non-enrolled users can + * only change the SAS rendering scheme). + */ + + rendering_id = zrtp_comp_type2id(ZRTP_CC_SAS, (char*)sasrelay->sas_scheme); + if (-1 == zrtp_profile_find(&session->profile, ZRTP_CC_SAS, rendering_id)) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! PBX Confirm packet with transferred SAS have unknown or" + " unsupported rendering scheme %.4s.ID=%u\n", sasrelay->sas_scheme, stream->id)); + + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_invalid_packet, 1); + return zrtp_status_fail; + } + session->sasscheme = zrtp_comp_find(ZRTP_CC_SAS, rendering_id, session->zrtp ); + + ZRTP_LOG(3,(_ZTU_,"\tSasrelay: New Rendering scheme %.4s.\n", session->sasscheme->base.type)); + + if (session->secrets.matches & ZRTP_BIT_PBX) { + if ( ( ((uint32_t) *sasrelay->sas_scheme) != (uint32_t)0x0L ) && + (0 != zrtp_memcmp(sasrelay->sashash, zerosashash, sizeof(sasrelay->sashash))) ) + { + char buff[256]; + session->sasbin.length = ZRTP_MITM_SAS_SIZE; + /* First 32 bits if sashash includes sasvalue */ + zrtp_memcpy(session->sasbin.buffer, sasrelay->sashash, session->sasbin.length); + stream->mitm_mode = ZRTP_MITM_MODE_RECONFIRM_CLIENT; + + ZRTP_LOG(3,(_ZTU_,"\tSasRelay: SAS value was updated bin=%s.\n", + hex2str(buff, sizeof(buff), session->sasbin.buffer, session->sasbin.length))); + } + } else if (0 != zrtp_memcmp(sasrelay->sashash, zerosashash, sizeof(sasrelay->sashash))) { + ZRTP_LOG(1,(_ZTU_,"\tWARNING! SAS Value was received from NOT Trusted MiTM. ID=%u\n", stream->id)); + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_possible_mitm3, 1); + return zrtp_status_fail; + } else { + ZRTP_LOG(1,(_ZTU_, "\rERROR! For SasRelay Other secret doesn't match. ID=%u\n", stream->id)); + } + + s = session->sasscheme->compute(session->sasscheme, stream, session->hash, 1); + if (zrtp_status_ok != s) { + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_software, 1); + return s; + } + + ZRTP_LOG(3,(_ZTU_,"\tSasRelay: Updated SAS is <%s> <%s>.\n", session->sas1.buffer, session->sas2.buffer)); + + if (session->zrtp->cb.event_cb.on_zrtp_protocol_event) { + session->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_LOCAL_SAS_UPDATED); + } + + return zrtp_status_ok; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_while_in_sasrelaying( zrtp_stream_t* stream, + zrtp_rtp_info_t* packet) +{ + zrtp_status_t s = zrtp_status_ok; + + switch (packet->type) + { + case ZRTP_RELAYACK: + _zrtp_cancel_send_packet_later(stream, ZRTP_SASRELAY); + _zrtp_change_state(stream, ZRTP_STATE_SECURE); + if (stream->zrtp->cb.event_cb.on_zrtp_protocol_event) { + stream->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_REMOTE_SAS_UPDATED); + } + break; + + case ZRTP_GOCLEAR: + s = _zrtp_machine_process_goclear(stream, packet); + if (zrtp_status_ok == s) { + s = _zrtp_machine_enter_pendingclear(stream); + } + break; + + case ZRTP_NONE: + s = _zrtp_protocol_decrypt(stream->protocol, packet, 1); + break; + + default: + break; + } + + return s; +} + + +/*===========================================================================*/ +/* ZRTP API for PBX */ +/*===========================================================================*/ + +/*---------------------------------------------------------------------------*/ +zrtp_status_t zrtp_stream_registration_start(zrtp_stream_t* stream, uint32_t ssrc) +{ + ZRTP_LOG(3,(_ZTU_,"START REGISTRATION STREAM ID=%u mode=%s state=%s.\n", + stream->id, zrtp_log_mode2str(stream->mode), zrtp_log_state2str(stream->state))); + + if (NULL == stream->zrtp->cb.cache_cb.on_get_mitm) { + ZRTP_LOG(2,(_ZTU_,"WARNING: Can't use MiTM Functions with no ZRTP Cache.\n")); + return zrtp_status_notavailable; + } + + stream->mitm_mode = ZRTP_MITM_MODE_REG_SERVER; + return zrtp_stream_start(stream, ssrc); +} + +zrtp_status_t zrtp_stream_registration_secure(zrtp_stream_t* stream) +{ + ZRTP_LOG(3,(_ZTU_,"SECURE REGISTRATION STREAM ID=%u mode=%s state=%s.\n", + stream->id, zrtp_log_mode2str(stream->mode), zrtp_log_state2str(stream->state))); + + if (NULL == stream->zrtp->cb.cache_cb.on_get_mitm) { + ZRTP_LOG(2,(_ZTU_,"WARNING: Can't use MiTM Functions with no ZRTP Cache.\n")); + return zrtp_status_notavailable; + } + + stream->mitm_mode = ZRTP_MITM_MODE_REG_SERVER; + return zrtp_stream_secure(stream); +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t zrtp_register_with_trusted_mitm(zrtp_stream_t* stream) +{ + zrtp_session_t *session = stream->session; + zrtp_status_t s = zrtp_status_bad_param; + + ZRTP_LOG(3,(_ZTU_,"MARKING this call as REGISTRATION ID=%u\n", stream->id)); + + if (NULL == stream->zrtp->cb.cache_cb.on_get_mitm) { + ZRTP_LOG(2,(_ZTU_,"WARNING: Can't use MiTM Functions with no ZRTP Cache.\n")); + return zrtp_status_notavailable; + } + + if (!stream->protocol) { + return zrtp_status_bad_param; + } + + /* + * Generate new MitM cache: + * pbxsecret = KDF(ZRTPSess, "Trusted MiTM key", (ZIDi | ZIDr), negotiated hash length) + */ + if ( (stream->state == ZRTP_STATE_SECURE) && + ((stream->mitm_mode == ZRTP_MITM_MODE_REG_CLIENT) || (stream->mitm_mode == ZRTP_MITM_MODE_REG_SERVER)) ) + { + zrtp_string32_t kdf_context = ZSTR_INIT_EMPTY(kdf_context); + static const zrtp_string32_t trusted_mitm_key_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_TRUSTMITMKEY_STR); + zrtp_string16_t *zidi, *zidr; + + if (stream->protocol->type == ZRTP_STATEMACHINE_INITIATOR) { + zidi = &session->zid; + zidr = &session->peer_zid; + } else { + zidi = &session->peer_zid; + zidr = &session->zid; + } + + zrtp_zstrcat(ZSTR_GV(kdf_context), ZSTR_GVP(zidi)); + zrtp_zstrcat(ZSTR_GV(kdf_context), ZSTR_GVP(zidr)); + + _zrtp_kdf( stream, + ZSTR_GV(session->zrtpsess), + ZSTR_GV(trusted_mitm_key_label), + ZSTR_GV(kdf_context), + ZRTP_HASH_SIZE, + ZSTR_GV(session->secrets.pbxs->value)); + + session->secrets.pbxs->_cachedflag = 1; + session->secrets.pbxs->lastused_at = (uint32_t)(zrtp_time_now()/1000); + session->secrets.cached |= ZRTP_BIT_PBX; + session->secrets.matches |= ZRTP_BIT_PBX; + + s = zrtp_status_ok; + if (session->zrtp->cb.cache_cb.on_put_mitm) { + s = session->zrtp->cb.cache_cb.on_put_mitm( ZSTR_GV(session->zid), + ZSTR_GV(session->peer_zid), + session->secrets.pbxs); + } + + ZRTP_LOG(3,(_ZTU_,"Makring this call as REGISTRATION - DONE\n")); + } + + return s; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t zrtp_update_remote_options( zrtp_stream_t* stream, + zrtp_sas_id_t transf_sas_scheme, + zrtp_string32_t* transf_sas_value, + uint8_t transf_ac_flag, + uint8_t transf_d_flag ) +{ + zrtp_retry_task_t* task = &stream->messages.sasrelay_task; + zrtp_status_t s = zrtp_status_ok; + char buff[256]; + + ZRTP_LOG(3,(_ZTU_,"UPDATE REMOTE SAS OPTIONS mode. ID=%u\n", stream->id)); + ZRTP_LOG(3,(_ZTU_,"transf_sas=%s scheme=%d.\n", transf_sas_value ? + hex2str((const char*)transf_sas_value->buffer, transf_sas_value->length, (char*)buff, sizeof(buff)) : "NULL", + transf_sas_scheme)); + + if (NULL == stream->zrtp->cb.cache_cb.on_get_mitm) { + ZRTP_LOG(2,(_ZTU_,"WARNING: Can't use MiTM Functions with no ZRTP Cache.\n")); + return zrtp_status_notavailable; + } + + /* The TRANSFERRING option is only available from the SECURE state. */ + if (stream->state != ZRTP_STATE_SECURE) { + return zrtp_status_bad_param; + } + + /* Don't transfer an SAS to a non-enrolled user */ + if (transf_sas_value && !(stream->session->secrets.matches & ZRTP_BIT_PBX)) { + return zrtp_status_bad_param; + } + + /* Don't allow to transfer the SAS if the library wasn't initalized as MiTM endpoint */ + if (!stream->zrtp->is_mitm) { + ZRTP_LOG(3,(_ZTU_,"\tERROR! The endpoint can't transfer SAS values to other endpoints" + " without introducing itself by M-flag in Hello. see zrtp_init().\n")); + return zrtp_status_wrong_state; + } + + s = _create_sasrelay( stream, + transf_sas_scheme, + transf_sas_value, + transf_ac_flag, + transf_d_flag, + &stream->messages.sasrelay); + if(zrtp_status_ok != s) { + return s; + } + + s = _zrtp_packet_fill_msg_hdr( stream, + ZRTP_SASRELAY, + sizeof(zrtp_packet_SASRelay_t) - sizeof(zrtp_msg_hdr_t), + &stream->messages.sasrelay.hdr); + if(zrtp_status_ok != s) { + return s; + } + + _zrtp_change_state(stream, ZRTP_STATE_SASRELAYING); + + task->_is_enabled = 1; + task->callback = _send_and_resend_sasrelay; + task->_retrys = 0; + _send_and_resend_sasrelay(stream, task); + + return s; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t zrtp_resolve_mitm_call( zrtp_stream_t* stream1, + zrtp_stream_t* stream2) +{ + zrtp_stream_t* enrolled = NULL; + zrtp_stream_t* non_enrolled = NULL; + zrtp_sas_id_t mitm_sas_scheme = ZRTP_COMP_UNKN; + zrtp_status_t s = zrtp_status_ok; + + ZRTP_LOG(3,(_ZTU_,"RESOLVE MITM CALL s1=%u, s2=%u...\n", stream1->id, stream2->id)); + + if (NULL == stream1->zrtp->cb.cache_cb.on_get_mitm) { + ZRTP_LOG(2,(_ZTU_,"WARNING: Can't use MiTM Functions with no ZRTP Cache.\n")); + return zrtp_status_notavailable; + } + + /* + * Both sides must be in the Secure state and at least one should be + * enrolled. + */ + if ((stream1->state != ZRTP_STATE_SECURE) || (stream2->state != ZRTP_STATE_SECURE)) { + return zrtp_status_bad_param; + } + + /* Check the stream enrollment options and choose one for transferring the call. */ + if (zrtp_is_user_enrolled(stream1)) { + if (zrtp_is_user_enrolled(stream2)) { + ZRTP_LOG(3,(_ZTU_,"\tBoth streams are enrolled - choose one with bigger ZID.\n")); + enrolled = zrtp_choose_one_enrolled(stream1, stream2); + } else { + enrolled = stream1; + } + } else if (zrtp_is_user_enrolled(stream2)) { + enrolled = stream2; + } + + if (!enrolled) { + return zrtp_status_bad_param; + } + else { + non_enrolled = (stream1 == enrolled) ? stream2 : stream1; + } + + ZRTP_LOG(3,(_ZTU_,"\tAfter Resolving: S1 is %s and S2 is %s.\n", + (stream1 == enrolled) ? "ENROLLED" : "NON-ENROLLED", + (stream2 == enrolled) ? "ENROLLED" : "NON-ENROLLED")); + + /* + * Choose the best SAS rendering scheme supported by both peers. Find the + * stream that can change it. + */ + { + uint8_t i=0; + + zrtp_packet_Hello_t *enhello = &enrolled->messages.peer_hello; + char *encp = (char*)enhello->comp + (enhello->hc + + enhello->cc + + enhello->ac + + enhello->kc)* ZRTP_COMP_TYPE_SIZE; + + + for (i=0; isc; i++, encp+=ZRTP_COMP_TYPE_SIZE) + { + uint8_t j=0; + zrtp_packet_Hello_t *nonenhello = &non_enrolled->messages.peer_hello; + char *nonencp = (char*)nonenhello->comp + (nonenhello->hc + + nonenhello->cc + + nonenhello->ac + + nonenhello->kc)* ZRTP_COMP_TYPE_SIZE; + + for (j=0; jsc; j++, nonencp+=ZRTP_COMP_TYPE_SIZE) + { + if (0 == zrtp_memcmp(encp, nonencp, ZRTP_COMP_TYPE_SIZE)) { + mitm_sas_scheme = zrtp_comp_type2id(ZRTP_CC_SAS, encp); + ZRTP_LOG(3,(_ZTU_,"\tMITM SAS scheme=%.4s was choosen.\n", encp)); + break; + } + } + if (j != nonenhello->sc) { + break; + } + } + } + if (ZRTP_COMP_UNKN == mitm_sas_scheme) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! Can't find matched SAS schemes on MiTM Resolving.\n" + " s1=%u s2=$u", stream1->id, stream2->id)); + return zrtp_status_algo_fail; + } + + s = zrtp_update_remote_options( enrolled, + mitm_sas_scheme, + &non_enrolled->session->sasbin, + non_enrolled->allowclear, + non_enrolled->peer_disclose_bit ); + if (zrtp_status_ok != s) { + return s; + } + + /* If non-enrolled party has SAS scheme different from chosen one - update */ + if (non_enrolled->session->sasscheme->base.id != mitm_sas_scheme) { + s = zrtp_update_remote_options( non_enrolled, + mitm_sas_scheme, + NULL, + enrolled->allowclear, + enrolled->peer_disclose_bit ); + if (zrtp_status_ok != s) { + return s; + } + } + + return s; +} + +/*---------------------------------------------------------------------------*/ +uint8_t zrtp_is_user_enrolled(zrtp_stream_t* stream) +{ + return ( (stream->session->secrets.cached & ZRTP_BIT_PBX) && + (stream->session->secrets.matches & ZRTP_BIT_PBX) ); +} + +zrtp_stream_t* zrtp_choose_one_enrolled(zrtp_stream_t* stream1, zrtp_stream_t* stream2) +{ + if (zrtp_memcmp( stream1->session->zid.buffer, + stream2->session->zid.buffer, + stream1->session->zid.length) > 0) { + return stream1; + } else { + return stream2; + } +} diff --git a/src/zrtp_protocol.c b/src/zrtp_protocol.c new file mode 100644 index 0000000000..f271309a0a --- /dev/null +++ b/src/zrtp_protocol.c @@ -0,0 +1,1332 @@ +/* + * 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 + */ + +#include "zrtp.h" + +#define _ZTU_ "zrtp protocol" + + +/*===========================================================================*/ +/* PROTOCOL Logic */ +/*===========================================================================*/ + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t _attach_secret( zrtp_session_t *session, + zrtp_proto_secret_t* psec, + zrtp_shared_secret_t* sec, + uint8_t is_initiator) +{ + zrtp_uchar32_t buff; + static const zrtp_string16_t initiator = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_ROLE_INITIATOR); + static const zrtp_string16_t responder = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_ROLE_RESPONDER); + + const zrtp_string16_t* role = is_initiator ? &initiator : &responder; + const zrtp_string16_t* his_role = is_initiator ? &responder : &initiator; + + ZSTR_SET_EMPTY(psec->id); + ZSTR_SET_EMPTY(psec->peer_id); + psec->secret = sec; + + /* + * If secret's value is available (from the cache or from SIP) - use hmac; + * use zero-strings in other case. + */ + if (psec->secret) { + session->hash->hmac_truncated( session->hash, + ZSTR_GV(sec->value), + ZSTR_GVP(role), + ZRTP_RSID_SIZE, + ZSTR_GV(psec->id)); + + session->hash->hmac_truncated( session->hash, + ZSTR_GV(sec->value), + ZSTR_GVP(his_role), + ZRTP_RSID_SIZE, + ZSTR_GV(psec->peer_id)); + } else { + psec->id.length = ZRTP_RSID_SIZE; + zrtp_memset(psec->id.buffer, 0, psec->id.length); + + psec->peer_id.length = ZRTP_RSID_SIZE; + zrtp_memset(psec->peer_id.buffer, 0, psec->peer_id.length); + } + + ZRTP_LOG(3,(_ZTU_,"\tAttach RS id=%s.\n", + hex2str((const char*)psec->id.buffer, psec->id.length, (char*)buff, sizeof(buff)))); + ZRTP_LOG(3,(_ZTU_,"\tAttach RS peer_id=%s.\n", + hex2str((const char*)psec->peer_id.buffer, psec->peer_id.length, (char*)buff, sizeof(buff)))); + + return zrtp_status_ok; +} + +zrtp_status_t _zrtp_protocol_init(zrtp_stream_t *stream, uint8_t is_initiator, zrtp_protocol_t **protocol) +{ + zrtp_protocol_t *new_proto = NULL; + zrtp_status_t s = zrtp_status_ok; + + ZRTP_LOG(3,(_ZTU_,"\tInit %s Protocol ID=%u mode=%s...\n", + is_initiator ? "INITIATOR's" : "RESPONDER's", stream->id, zrtp_log_mode2str(stream->mode))); + + /* Destroy previous protocol structure (Responder or Preshared) */ + if (*protocol) { + _zrtp_protocol_destroy(*protocol); + *protocol = NULL; + } + + /* Allocate memory for all branching structures */ + do + { + new_proto = zrtp_sys_alloc(sizeof(zrtp_protocol_t)); + if (!new_proto) { + s = zrtp_status_alloc_fail; + break; + } + zrtp_memset(new_proto, 0, sizeof(zrtp_protocol_t)); + + new_proto->cc = zrtp_sys_alloc(sizeof(zrtp_proto_crypto_t)); + if (!new_proto->cc) { + s = zrtp_status_alloc_fail; + break; + } + zrtp_memset(new_proto->cc, 0, sizeof(zrtp_proto_crypto_t)); + + /* Create and Initialize DH crypto context (for DH streams only) */ + if (ZRTP_IS_STREAM_DH(stream)) { + if (stream->dh_cc.initialized_with != stream->pubkeyscheme->base.id) { + stream->pubkeyscheme->initialize(stream->pubkeyscheme, &stream->dh_cc); + stream->dh_cc.initialized_with = stream->pubkeyscheme->base.id; + } + } + + /* Initialize main structure at first: functions pointers and generate nonce */ + new_proto->type = is_initiator ? ZRTP_STATEMACHINE_INITIATOR : ZRTP_STATEMACHINE_RESPONDER; + new_proto->context = stream; + + /* Initialize protocol crypto context and prepare it for further usage */ + ZSTR_SET_EMPTY(new_proto->cc->kdf_context); + ZSTR_SET_EMPTY(new_proto->cc->s0); + ZSTR_SET_EMPTY(new_proto->cc->mes_hash); + ZSTR_SET_EMPTY(new_proto->cc->hv); + ZSTR_SET_EMPTY(new_proto->cc->peer_hv); + + if (ZRTP_IS_STREAM_DH(stream)) { + _attach_secret(stream->session, &new_proto->cc->rs1, stream->session->secrets.rs1, is_initiator); + _attach_secret(stream->session, &new_proto->cc->rs2, stream->session->secrets.rs2, is_initiator); + _attach_secret(stream->session, &new_proto->cc->auxs, stream->session->secrets.auxs, is_initiator); + _attach_secret(stream->session, &new_proto->cc->pbxs, stream->session->secrets.pbxs, is_initiator); + } + + s = zrtp_status_ok; + *protocol = new_proto; + } while (0); + + if (s != zrtp_status_ok) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! _zrtp_protocol_attach() with code %s.\n", zrtp_log_status2str(s))); + if (new_proto && new_proto->cc) { + zrtp_sys_free(new_proto->cc); + } + if (new_proto) { + zrtp_sys_free(new_proto); + } + *protocol = NULL; + } + + return s; +} + +/*----------------------------------------------------------------------------*/ +static void clear_crypto_sources(zrtp_stream_t* stream) +{ + zrtp_protocol_t* proto = stream->protocol; + if (proto && proto->cc) { + zrtp_memset(proto->cc, 0, sizeof(zrtp_proto_crypto_t)); + zrtp_sys_free(proto->cc); + proto->cc = 0; + } +} + +void _zrtp_protocol_destroy(zrtp_protocol_t *proto) +{ + /* Clear protocol crypto values, destroy SRTP unit, clear and release memory. */ + if (proto) { + /* if protocol is being destroyed by exception, ->context may be NULL */ + if (proto->context) { + _zrtp_cancel_send_packet_later(proto->context, ZRTP_NONE); + if (proto->_srtp) { + zrtp_srtp_destroy(proto->context->zrtp->srtp_global, proto->_srtp); + } + } + + clear_crypto_sources(proto->context); + zrtp_memset(proto, 0, sizeof(zrtp_protocol_t)); + zrtp_sys_free(proto); + } +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_protocol_encrypt( zrtp_protocol_t *proto, + zrtp_rtp_info_t *packet, + uint8_t is_rtp) +{ + zrtp_status_t s = zrtp_status_ok; + + if (is_rtp) { + s = zrtp_srtp_protect(proto->context->zrtp->srtp_global, proto->_srtp, packet); + } else { + s = zrtp_srtp_protect_rtcp(proto->context->zrtp->srtp_global, proto->_srtp, packet); + } + + if (zrtp_status_ok != s) { + ZRTP_UNALIGNED(zrtp_rtp_hdr_t) *hdr = (zrtp_rtp_hdr_t*) packet->packet; + + ZRTP_LOG(2,(_ZTU_,"ERROR! Encrypt failed. ID=%u:%s s=%s (%s size=%d ssrc=%u seq=%d pt=%d)\n", + proto->context->id, + zrtp_log_mode2str(proto->context->mode), + zrtp_log_status2str(s), + is_rtp ? "RTP" : "RTCP", + *packet->length, + zrtp_ntoh32(hdr->ssrc), + zrtp_ntoh16(hdr->seq), + hdr->pt)); + } + + return s; +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_protocol_decrypt( zrtp_protocol_t *proto, + zrtp_rtp_info_t *packet, + uint8_t is_rtp) +{ + zrtp_status_t s = zrtp_status_ok; + + if (is_rtp) { + s = zrtp_srtp_unprotect(proto->context->zrtp->srtp_global, proto->_srtp, packet); + } else { + s = zrtp_srtp_unprotect_rtcp(proto->context->zrtp->srtp_global, proto->_srtp, packet); + } + + if (zrtp_status_ok != s) { + ZRTP_UNALIGNED(zrtp_rtp_hdr_t) *hdr = (zrtp_rtp_hdr_t*) packet->packet; + ZRTP_LOG(2,(_ZTU_,"ERROR! Decrypt failed. ID=%u:%s s=%s (%s size=%d ssrc=%u seq=%u/%u pt=%d)\n", + proto->context->id, + zrtp_log_mode2str(proto->context->mode), + zrtp_log_status2str(s), + is_rtp ? "RTP" : "RTCP", + *packet->length, + zrtp_ntoh32(hdr->ssrc), + zrtp_ntoh16(hdr->seq), + packet->seq, + hdr->pt)); + } + + return s; +} + + +/*===========================================================================*/ +/* CRYPTO Utilites */ +/*===========================================================================*/ + +/*---------------------------------------------------------------------------*/ +static zrtp_status_t _derive_s0(zrtp_stream_t* stream, int is_initiator) +{ + static const zrtp_string32_t zrtp_kdf_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_KDF_STR); + static const zrtp_string32_t zrtp_sess_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_SESS_STR); + static const zrtp_string32_t zrtp_multi_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_MULTI_STR); + static const zrtp_string32_t zrtp_presh_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_PRESH_STR); + + zrtp_session_t *session = stream->session; + zrtp_secrets_t* secrets = &session->secrets; + zrtp_proto_crypto_t* cc = stream->protocol->cc; + void* hash_ctx = NULL; + char print_buff[256]; + + switch (stream->mode) + { + /* + * S0 computing for FULL DH exchange + * S0 computing. s0 is the master shared secret used for all + * cryptographic operations. In particular, note the inclusion + * of "total_hash", a hash of all packets exchanged up to this + * point. This belatedly detects any tampering with earlier + * packets, e.g. bid-down attacks. + * + * s0 = hash( 1 | DHResult | "ZRTP-HMAC-KDF" | ZIDi | ZIDr | + * total_hash | len(s1) | s1 | len(s2) | s2 | len(s3) | s3 ) + * The constant 1 and all lengths are 32 bits big-endian values. + * The fields without length prefixes are fixed-witdh: + * - DHresult is fixed to the width of the DH prime. + * - The hash type string and ZIDs are fixed width. + * - total_hash is fixed by the hash negotiation. + * The constant 1 is per NIST SP 800-56A section 5.8.1, and is + * a counter which can be incremented to generate more than 256 + * bits of key material. + * ======================================================================== + */ + case ZRTP_STREAM_MODE_DH: + { + zrtp_proto_secret_t *C[3] = { 0, 0, 0}; + int i = 0; + uint32_t comp_length = 0; + zrtp_stringn_t *zidi = NULL, *zidr = NULL; + struct BigNum dhresult; +#if (defined(ZRTP_USE_STACK_MINIM) && (ZRTP_USE_STACK_MINIM == 1)) + zrtp_uchar1024_t* buffer = zrtp_sys_alloc( sizeof(zrtp_uchar1024_t) ); + if (!buffer) { + return zrtp_status_alloc_fail; + } +#else + zrtp_uchar1024_t holder; + zrtp_uchar1024_t* buffer = &holder; +#endif + + ZRTP_LOG(3,(_ZTU_,"\tDERIVE S0 from DH exchange and RS secrets...\n")); + ZRTP_LOG(3,(_ZTU_,"\t my rs1ID:%s\n", hex2str(cc->rs1.id.buffer, cc->rs1.id.length, print_buff, sizeof(print_buff)))); + ZRTP_LOG(3,(_ZTU_,"\t his rs1ID:%s\n", hex2str((const char*)stream->messages.peer_dhpart.rs1ID, ZRTP_RSID_SIZE, print_buff, sizeof(print_buff)))); + ZRTP_LOG(3,(_ZTU_,"\t his rs1ID comp:%s\n", hex2str(cc->rs1.peer_id.buffer, cc->rs1.peer_id.length, print_buff, sizeof(print_buff)))); + + ZRTP_LOG(3,(_ZTU_,"\t my rs2ID:%s\n", hex2str(cc->rs2.id.buffer, cc->rs2.id.length, print_buff, sizeof(print_buff)))); + ZRTP_LOG(3,(_ZTU_,"\t his rs2ID:%s\n", hex2str((const char*)stream->messages.peer_dhpart.rs2ID, ZRTP_RSID_SIZE, print_buff, sizeof(print_buff)))); + ZRTP_LOG(3,(_ZTU_,"\t his rs2ID comp:%s\n", hex2str(cc->rs2.peer_id.buffer, cc->rs2.peer_id.length, print_buff, sizeof(print_buff)))); + + ZRTP_LOG(3,(_ZTU_,"\t my pbxsID:%s\n", hex2str(cc->pbxs.id.buffer, cc->pbxs.id.length, print_buff, sizeof(print_buff)))); + ZRTP_LOG(3,(_ZTU_,"\t his pbxsID:%s\n", hex2str((const char*)stream->messages.peer_dhpart.pbxsID, ZRTP_RSID_SIZE, print_buff, sizeof(print_buff)))); + ZRTP_LOG(3,(_ZTU_,"\this pbxsID comp:%s\n", hex2str(cc->pbxs.peer_id.buffer, cc->pbxs.peer_id.length, print_buff, sizeof(print_buff)))); + + hash_ctx = session->hash->hash_begin(session->hash); + if (0 == hash_ctx) { + ZRTP_LOG(1,(_ZTU_, "\tERROR! can't start hash calculation for S0 computing. ID=%u.\n", stream->id)); + return zrtp_status_fail; + } + + /* + * NIST requires a 32-bit big-endian integer counter to be included + * in the hash each time the hash is computed, which we have set to + * the fixed value of 1, because we only compute the hash once. + */ + comp_length = zrtp_hton32(1L); + session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)&comp_length, 4); + + bnBegin(&dhresult); + stream->pubkeyscheme->compute( stream->pubkeyscheme, + &stream->dh_cc, + &dhresult, + &stream->dh_cc.peer_pv); + comp_length = stream->pubkeyscheme->pv_length; + bnExtractBigBytes(&dhresult, (uint8_t *)buffer, 0, comp_length); + session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)buffer, comp_length); + bnEnd(&dhresult); + +#if (defined(ZRTP_USE_STACK_MINIM) && (ZRTP_USE_STACK_MINIM == 1)) + zrtp_sys_free(buffer); +#endif + + /* Add "ZRTP-HMAC-KDF" to the S0 hash */ + session->hash->hash_update( session->hash, hash_ctx, + (const int8_t*)&zrtp_kdf_label.buffer, + zrtp_kdf_label.length); + + /* Then Initiator's and Responder's ZIDs */ + if (stream->protocol->type == ZRTP_STATEMACHINE_INITIATOR) { + zidi = ZSTR_GV(stream->session->zid); + zidr = ZSTR_GV(stream->session->peer_zid); + } else { + zidr = ZSTR_GV(stream->session->zid); + zidi = ZSTR_GV(stream->session->peer_zid); + } + + session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)&zidi->buffer, zidi->length); + session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)&zidr->buffer, zidr->length); + session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)&cc->mes_hash.buffer, cc->mes_hash.length); + + /* If everything is OK - RS1 should much */ + if (!zrtp_memcmp(cc->rs1.peer_id.buffer, stream->messages.peer_dhpart.rs1ID, ZRTP_RSID_SIZE)) + { + C[0] = &cc->rs1; + secrets->matches |= ZRTP_BIT_RS1; + } + /* If we have lost our RS1 - remote party should use backup (RS2) instead */ + else if (!zrtp_memcmp(cc->rs1.peer_id.buffer, stream->messages.peer_dhpart.rs2ID, ZRTP_RSID_SIZE)) + { + C[0] = &cc->rs1; + secrets->matches |= ZRTP_BIT_RS1; + ZRTP_LOG(2,(_ZTU_,"\tINFO! We have lost our RS1 from previous broken exchange" + " - remote party will use RS2 backup. ID=%u\n", stream->id)); + } + /* If remote party lost it's secret - we will use backup */ + else if (!zrtp_memcmp(cc->rs2.peer_id.buffer, stream->messages.peer_dhpart.rs1ID, ZRTP_RSID_SIZE)) + { + C[0] = &cc->rs2; + cc->rs1 = cc->rs2; + secrets->matches |= ZRTP_BIT_RS1; + secrets->cached |= ZRTP_BIT_RS1; + ZRTP_LOG(2,(_ZTU_,"\tINFO! Remote party has lost it's RS1 - use RS2 backup. ID=%u\n", stream->id)); + } + else + { + secrets->matches &= ~ZRTP_BIT_RS1; + if (session->zrtp->cb.cache_cb.on_set_verified) { + session->zrtp->cb.cache_cb.on_set_verified( ZSTR_GV(session->zid), + ZSTR_GV(session->peer_zid), + 0); + } + + if (session->zrtp->cb.cache_cb.on_reset_since) { + session->zrtp->cb.cache_cb.on_reset_since(ZSTR_GV(session->zid), ZSTR_GV(session->peer_zid)); + } + + ZRTP_LOG(2,(_ZTU_,"\tINFO! Our RS1 doesn't equal to other-side's one %s. ID=%u\n", + cc->rs1.secret->_cachedflag ? " - drop verified!" : "", stream->id)); + } + + if (!zrtp_memcmp(cc->rs2.peer_id.buffer, stream->messages.peer_dhpart.rs2ID, ZRTP_RSID_SIZE)) { + secrets->matches |= ZRTP_BIT_RS2; + if (0 == C[0]) { + C[0] = &cc->rs2; + } + } + + + if (secrets->auxs && + (!zrtp_memcmp(stream->messages.peer_dhpart.auxsID, cc->auxs.peer_id.buffer, ZRTP_RSID_SIZE)) ) { + C[1] =&cc->auxs; + secrets->matches |= ZRTP_BIT_AUX; + } + + if ( secrets->pbxs && + (!zrtp_memcmp(stream->messages.peer_dhpart.pbxsID, cc->pbxs.peer_id.buffer, ZRTP_RSID_SIZE)) ) { + C[2] = &cc->pbxs; + secrets->matches |= ZRTP_BIT_PBX; + } + + /* Finally hashing matched shared secrets */ + for (i=0; i<3; i++) { + /* + * Some of the shared secrets s1 through s5 may have lengths of zero + * if they are null (not shared), and are each preceded by a 4-octet + * length field. For example, if s4 is null, len(s4) is 00 00 00 00, + * and s4 itself would be absent from the hash calculation, which + * means len(s5) would immediately follow len(s4). + */ + comp_length = C[i] ? zrtp_hton32(ZRTP_RS_SIZE) : 0; + session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)&comp_length, 4); + if (C[i]) { + session->hash->hash_update( session->hash, + hash_ctx, + (const int8_t*)C[i]->secret->value.buffer, + C[i]->secret->value.length ); + ZRTP_LOG(3,(_ZTU_,"\tUse S%d in calculations.\n", i+1)); + } + } + + session->hash->hash_end(session->hash, hash_ctx, ZSTR_GV(cc->s0)); + } break; /* S0 for for DH and Preshared streams */ + + /* + * Compute all possible combinations of preshared_key: + * hash(len(rs1) | rs1 | len(auxsecret) | auxsecret | len(pbxsecret) | pbxsecret) + * Find matched preshared_key and derive S0 from it: + * s0 = KDF(preshared_key, "ZRTP Stream Key", KDF_Context, negotiated hash length) + * + * INFO: Take into account that RS1 and RS2 may be swapped. + * If no matched were found - generate DH commit. + * ======================================================================== + */ + case ZRTP_STREAM_MODE_PRESHARED: + { + zrtp_status_t s = zrtp_status_ok; + zrtp_string32_t presh_key = ZSTR_INIT_EMPTY(presh_key); + + ZRTP_LOG(3,(_ZTU_,"\tDERIVE S0 for PRESHARED from cached secret. ID=%u\n", stream->id)); + + /* Use the same hash as we used for Commitment */ + if (is_initiator) + { + s = _zrtp_compute_preshared_key( session, + ZSTR_GV(session->secrets.rs1->value), + (session->secrets.auxs->_cachedflag) ? ZSTR_GV(session->secrets.auxs->value) : NULL, + (session->secrets.pbxs->_cachedflag) ? ZSTR_GV(session->secrets.pbxs->value) : NULL, + ZSTR_GV(presh_key), + NULL); + if (zrtp_status_ok != s) { + return s; + } + + secrets->matches |= ZRTP_BIT_RS1; + if (session->secrets.auxs->_cachedflag) { + secrets->matches |= ZRTP_BIT_AUX; + } + if (session->secrets.pbxs->_cachedflag) { + secrets->matches |= ZRTP_BIT_PBX; + } + } + /* + * Let's find appropriate hv key for Responder: + * , , , . + */ + else + { + int res=-1; + char* peer_key_id = (char*)stream->messages.peer_commit.hv+ZRTP_HV_NONCE_SIZE; + zrtp_string8_t key_id = ZSTR_INIT_EMPTY(key_id); + + do { + /* RS1 MUST be available at this stage.*/ + s = _zrtp_compute_preshared_key( session, + ZSTR_GV(secrets->rs1->value), + NULL, + NULL, + ZSTR_GV(presh_key), + ZSTR_GV(key_id)); + if (zrtp_status_ok == s) { + res = zrtp_memcmp(peer_key_id, key_id.buffer, ZRTP_HV_KEY_SIZE); + if (0 == res) { + secrets->matches |= ZRTP_BIT_RS1; + break; + } + } + + if (session->secrets.pbxs->_cachedflag) + { + s = _zrtp_compute_preshared_key( session, + ZSTR_GV(secrets->rs1->value), + NULL, + ZSTR_GV(secrets->pbxs->value), + ZSTR_GV(presh_key), + ZSTR_GV(key_id)); + if (zrtp_status_ok == s) { + res = zrtp_memcmp(peer_key_id, key_id.buffer, ZRTP_HV_KEY_SIZE); + if (0 == res) { + secrets->matches |= ZRTP_BIT_PBX; + break; + } + } + } + + if (session->secrets.auxs->_cachedflag) + { + s = _zrtp_compute_preshared_key( session, + ZSTR_GV(secrets->rs1->value), + ZSTR_GV(secrets->auxs->value), + NULL, + ZSTR_GV(presh_key), + ZSTR_GV(key_id)); + if (zrtp_status_ok == s) { + res = zrtp_memcmp(peer_key_id, key_id.buffer, ZRTP_HV_KEY_SIZE); + if (0 == res) { + secrets->matches |= ZRTP_BIT_AUX; + break; + } + } + } + + if ((session->secrets.pbxs->_cachedflag) && (session->secrets.auxs->_cachedflag)) + { + s = _zrtp_compute_preshared_key( session, + ZSTR_GV(secrets->rs1->value), + ZSTR_GV(secrets->auxs->value), + ZSTR_GV(secrets->pbxs->value), + ZSTR_GV(presh_key), + ZSTR_GV(key_id)); + if (zrtp_status_ok == s) { + res = zrtp_memcmp(peer_key_id, key_id.buffer, ZRTP_HV_KEY_SIZE); + if (0 == res) { + secrets->matches |= ZRTP_BIT_AUX; + secrets->matches |= ZRTP_BIT_PBX; + break; + } + } + } + + } while (0); + + if (0 != res) { + ZRTP_LOG(3,(_ZTU_,"\tINFO! Matched Key wasn't found - initate DH exchange.\n")); + secrets->cached = 0; + secrets->rs1->_cachedflag = 0; + + _zrtp_machine_start_initiating_secure(stream); + return zrtp_status_ok; + } + } + + ZRTP_LOG(3,(_ZTU_,"\tUse RS1, %s, %s in calculations.\n", + (session->secrets.matches & ZRTP_BIT_AUX) ? "AUX" : "NULL", + (session->secrets.matches & ZRTP_BIT_PBX) ? "PBX" : "NULL")); + + _zrtp_kdf( stream, + ZSTR_GV(presh_key), + ZSTR_GV(zrtp_presh_label), + ZSTR_GV(stream->protocol->cc->kdf_context), + session->hash->digest_length, + ZSTR_GV(cc->s0)); + } break; + + + /* + * For FAST Multistream: + * s0n = KDF(ZRTPSess, "ZRTP Multistream Key", KDF_Context, negotiated hash length) + * ======================================================================== + */ + case ZRTP_STREAM_MODE_MULT: + { + ZRTP_LOG(3,(_ZTU_,"\tDERIVE S0 for MULTISTREAM from ZRTP Session key... ID=%u\n", stream->id)); + _zrtp_kdf( stream, + ZSTR_GV(session->zrtpsess), + ZSTR_GV(zrtp_multi_label), + ZSTR_GV(stream->protocol->cc->kdf_context), + session->hash->digest_length, + ZSTR_GV(cc->s0)); + } break; + + default: break; + } + + + /* + * Compute ZRTP session key for FULL streams only: + * ZRTPSess = KDF(s0, "ZRTP Session Key", KDF_Context, negotiated hash length) + */ + if (!ZRTP_IS_STREAM_MULT(stream)) { + if (session->zrtpsess.length == 0) { + _zrtp_kdf( stream, + ZSTR_GV(cc->s0), + ZSTR_GV(zrtp_sess_label), + ZSTR_GV(stream->protocol->cc->kdf_context), + session->hash->digest_length, + ZSTR_GV(session->zrtpsess)); + } + } + + return zrtp_status_ok; +} + + +/*----------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_set_public_value( zrtp_stream_t *stream, + int is_initiator) +{ + /* + * This function performs the following actions according to ZRTP draft 5.6 + * a) Computes total hash; + * b) Calculates DHResult; + * c) Computes final stream key S0, based on DHSS and retained secrets; + * d) Computes HMAC Key and ZRTP key; + * e) Computes srtp keys and salts and creates srtp session. + */ + + zrtp_session_t *session = stream->session; + zrtp_proto_crypto_t* cc = stream->protocol->cc; + void* hash_ctx = NULL; + + static const zrtp_string32_t hmac_keyi_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_INITIATOR_HMAKKEY_STR); + static const zrtp_string32_t hmac_keyr_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_RESPONDER_HMAKKEY_STR); + + static const zrtp_string32_t srtp_mki_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_INITIATOR_KEY_STR); + static const zrtp_string32_t srtp_msi_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_INITIATOR_SALT_STR); + static const zrtp_string32_t srtp_mkr_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_RESPONDER_KEY_STR); + static const zrtp_string32_t srtp_msr_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_RESPONDER_SALT_STR); + + static const zrtp_string32_t zrtp_keyi_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_INITIATOR_ZRTPKEY_STR); + static const zrtp_string32_t zrtp_keyr_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_RESPONDER_ZRTPKEY_STR); + + uint32_t cipher_key_length = (ZRTP_CIPHER_AES128 == session->blockcipher->base.id) ? 16 : 32; + + const zrtp_string32_t *output_mk_label; + const zrtp_string32_t *output_ms_label; + const zrtp_string32_t *input_mk_label; + const zrtp_string32_t *input_ms_label; + const zrtp_string32_t *hmac_key_label; + const zrtp_string32_t *peer_hmac_key_label; + const zrtp_string32_t *zrtp_key_label; + const zrtp_string32_t *peer_zrtp_key_label; + + /* Define roles and prepare structures */ + if (is_initiator) { + output_mk_label = &srtp_mki_label; + output_ms_label = &srtp_msi_label; + input_mk_label = &srtp_mkr_label; + input_ms_label = &srtp_msr_label; + hmac_key_label = &hmac_keyi_label; + peer_hmac_key_label = &hmac_keyr_label; + zrtp_key_label = &zrtp_keyi_label; + peer_zrtp_key_label = &zrtp_keyr_label; + } else { + output_mk_label = &srtp_mkr_label; + output_ms_label = &srtp_msr_label; + input_mk_label = &srtp_mki_label; + input_ms_label = &srtp_msi_label; + hmac_key_label = &hmac_keyr_label; + peer_hmac_key_label = &hmac_keyi_label; + zrtp_key_label = &zrtp_keyr_label; + peer_zrtp_key_label = &zrtp_keyi_label; + } + + ZRTP_LOG(3, (_ZTU_,"---------------------------------------------------\n")); + ZRTP_LOG(3,(_ZTU_,"\tSWITCHING TO SRTP. ID=%u\n", zrtp_log_mode2str(stream->mode), stream->id)); + ZRTP_LOG(3,(_ZTU_,"\tI %s\n", is_initiator ? "Initiator" : "Responder")); + + /* + * Compute total messages hash: + * total_hash = hash(Hello of responder | Commit | DHPart1 | DHPart2) for DH streams + * total_hash = hash(Hello of responder | Commit ) for Fast modes. + */ + { + uint8_t* tok = NULL; + uint16_t tok_len = 0; + + hash_ctx = session->hash->hash_begin(session->hash); + if (0 == hash_ctx) { + return zrtp_status_fail; + } + + tok = is_initiator ? (uint8_t*)&stream->messages.peer_hello : (uint8_t*) &stream->messages.hello; + tok_len = is_initiator ? stream->messages.peer_hello.hdr.length : stream->messages.hello.hdr.length; + tok_len = zrtp_ntoh16(tok_len)*4; + session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)tok, tok_len); + + tok = is_initiator ? (uint8_t*)&stream->messages.commit : (uint8_t*)&stream->messages.peer_commit; + tok_len = is_initiator ? stream->messages.commit.hdr.length : stream->messages.peer_commit.hdr.length; + tok_len = zrtp_ntoh16(tok_len)*4; + session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)tok, tok_len); + + if (ZRTP_IS_STREAM_DH(stream)) + { + tok = (uint8_t*) (is_initiator ? &stream->messages.peer_dhpart : &stream->messages.dhpart); + tok_len = is_initiator ? stream->messages.peer_dhpart.hdr.length : stream->messages.dhpart.hdr.length; + tok_len = zrtp_ntoh16(tok_len)*4; + session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)tok, tok_len); + + tok = (uint8_t*)(is_initiator ? &stream->messages.dhpart : &stream->messages.peer_dhpart); + tok_len = is_initiator ? stream->messages.dhpart.hdr.length : stream->messages.peer_dhpart.hdr.length; + tok_len = zrtp_ntoh16(tok_len)*4; + session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)tok, tok_len); + } + + session->hash->hash_end(session->hash, hash_ctx, ZSTR_GV(cc->mes_hash)); + hash_ctx = NULL; + } /* total hash computing */ + + /* Total Hash is ready and we can create KDF_Context */ + zrtp_zstrcat(ZSTR_GV(cc->kdf_context), is_initiator ? ZSTR_GV(session->zid) : ZSTR_GV(session->peer_zid)); + zrtp_zstrcat(ZSTR_GV(cc->kdf_context), is_initiator ? ZSTR_GV(session->peer_zid) : ZSTR_GV(session->zid)); + zrtp_zstrcat(ZSTR_GV(cc->kdf_context), ZSTR_GV(cc->mes_hash)); + + /* Derive stream key S0 according to key exchange scheme */ + if (zrtp_status_ok != _derive_s0(stream, is_initiator)) { + return zrtp_status_fail; + } + + /* + * Compute HMAC keys. These values will be used after confirmation: + * hmackeyi = KDF(s0, "Initiator HMAC key", KDF_Context, negotiated hash length) + * hmackeyr = KDF(s0, "Responder HMAC key", KDF_Context, negotiated hash length) + */ + _zrtp_kdf( stream, + ZSTR_GV(cc->s0), + ZSTR_GVP(hmac_key_label), + ZSTR_GV(stream->protocol->cc->kdf_context), + session->hash->digest_length, + ZSTR_GV(stream->cc.hmackey)); + _zrtp_kdf( stream, + ZSTR_GV(cc->s0), + ZSTR_GVP(peer_hmac_key_label), + ZSTR_GV(stream->protocol->cc->kdf_context), + session->hash->digest_length, + ZSTR_GV(stream->cc.peer_hmackey)); + + /* + * Computing ZRTP keys for protection of the Confirm packet: + * zrtpkeyi = KDF(s0, "Initiator ZRTP key", KDF_Context, negotiated AES key length) + * zrtpkeyr = KDF(s0, "Responder ZRTP key", KDF_Context, negotiated AES key length) + */ + _zrtp_kdf( stream, + ZSTR_GV(cc->s0), + ZSTR_GVP(zrtp_key_label), + ZSTR_GV(stream->protocol->cc->kdf_context), + cipher_key_length, + ZSTR_GV(stream->cc.zrtp_key)); + _zrtp_kdf( stream, + ZSTR_GV(cc->s0), + ZSTR_GVP(peer_zrtp_key_label), + ZSTR_GV(stream->protocol->cc->kdf_context), + cipher_key_length, + ZSTR_GV(stream->cc.peer_zrtp_key)); +#if (defined(ZRTP_DEBUG_ZRTP_KEYS) && ZRTP_DEBUG_ZRTP_KEYS == 1) + { + char print_buff[256]; + ZRTP_LOG(3,(_ZTU_,"\t Messages hash:%s\n", hex2str(cc->mes_hash.buffer, cc->mes_hash.length, print_buff, sizeof(print_buff)))); + ZRTP_LOG(3,(_ZTU_,"\t S0:%s\n", hex2str(cc->s0.buffer, cc->s0.length, print_buff, sizeof(print_buff)))); + ZRTP_LOG(3,(_ZTU_,"\t ZRTP Sess:%s\n", hex2str(session->zrtpsess.buffer, session->zrtpsess.length, print_buff, sizeof(print_buff)))); + ZRTP_LOG(3,(_ZTU_,"\t hmackey:%s\n", hex2str(stream->cc.hmackey.buffer, stream->cc.hmackey.length, print_buff, sizeof(print_buff)))); + ZRTP_LOG(3,(_ZTU_,"\t peer_hmackeyr:%s\n", hex2str(stream->cc.peer_hmackey.buffer, stream->cc.peer_hmackey.length, print_buff, sizeof(print_buff)))); + ZRTP_LOG(3,(_ZTU_,"\t ZRTP key:%s\n", hex2str(stream->cc.zrtp_key.buffer, stream->cc.zrtp_key.length, print_buff, sizeof(print_buff)))); + ZRTP_LOG(3,(_ZTU_,"\t Peer ZRTP key:%s\n", hex2str(stream->cc.peer_zrtp_key.buffer, stream->cc.peer_zrtp_key.length, print_buff, sizeof(print_buff)))); + } +#endif + /* + * Preparing SRTP crypto engine: + * srtpkeyi = KDF(s0, "Initiator SRTP master key", KDF_Context, negotiated AES key length) + * srtpsalti = KDF(s0, "Initiator SRTP master salt", KDF_Context, 112) + * srtpkeyr = KDF(s0, "Responder SRTP master key", KDF_Context, negotiated AES key length) + * srtpsaltr = KDF(s0, "Responder SRTP master salt", KDF_Context, 112) + */ + { + zrtp_srtp_profile_t iprof; + zrtp_srtp_profile_t oprof; + + ZSTR_SET_EMPTY(iprof.salt); + ZSTR_SET_EMPTY(iprof.key); + + iprof.rtp_policy.cipher = session->blockcipher; + iprof.rtp_policy.auth_tag_len = session->authtaglength; + iprof.rtp_policy.hash = zrtp_comp_find(ZRTP_CC_HASH, ZRTP_SRTP_HASH_SHA1, session->zrtp); + iprof.rtp_policy.auth_key_len = 20; + iprof.rtp_policy.cipher_key_len = cipher_key_length; + + zrtp_memcpy(&iprof.rtcp_policy, &iprof.rtp_policy, sizeof(iprof.rtcp_policy)); + iprof.dk_cipher = session->blockcipher; + + zrtp_memcpy(&oprof, &iprof, sizeof(iprof)); + + _zrtp_kdf( stream, + ZSTR_GV(cc->s0), + ZSTR_GVP(input_mk_label), + ZSTR_GV(stream->protocol->cc->kdf_context), + cipher_key_length, + ZSTR_GV(iprof.key)); + _zrtp_kdf( stream, + ZSTR_GV(cc->s0), + ZSTR_GVP(input_ms_label), + ZSTR_GV(stream->protocol->cc->kdf_context), + 14, + ZSTR_GV(iprof.salt)); + _zrtp_kdf( stream, + ZSTR_GV(cc->s0), + ZSTR_GVP(output_mk_label), + ZSTR_GV(stream->protocol->cc->kdf_context), + cipher_key_length, + ZSTR_GV(oprof.key)); + _zrtp_kdf( stream, + ZSTR_GV(cc->s0), + ZSTR_GVP(output_ms_label), + ZSTR_GV(stream->protocol->cc->kdf_context), + 14, + ZSTR_GV(oprof.salt)); + + stream->protocol->_srtp = zrtp_srtp_create(session->zrtp->srtp_global, &iprof, &oprof); + + /* Profiles and keys in them are not needed anymore - clear them */ + zrtp_memset(&iprof, 0, sizeof(iprof)); + zrtp_memset(&oprof, 0, sizeof(oprof)); + + if (!stream->protocol->_srtp) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! Can't initialize SRTP engine. ID=%u\n", stream->id)); + return zrtp_status_fail; + } + } /* SRTP initialization */ + + return zrtp_status_ok; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_enter_secure(zrtp_stream_t* stream) +{ + /* + * When switching to SECURE all ZRTP crypto values were already computed by + * state-machine. Then we need to have logic to manage SAS value and shared + * secrets only. So: we compute SAS, refresh secrets flags and save the + * secrets to the cache after RS2 and RS1 swapping. We don't need any + * crypto sources any longer - destroy them. + */ + + zrtp_status_t s = zrtp_status_ok; + zrtp_proto_crypto_t* cc = stream->protocol->cc; + zrtp_session_t *session = stream->session; + zrtp_secrets_t *secrets = &stream->session->secrets; + uint8_t was_exp = 0; + uint64_t exp_date = 0; + + ZRTP_LOG(3,(_ZTU_,"\tEnter state SECURE (%s).\n", zrtp_log_mode2str(stream->mode))); + + _zrtp_cancel_send_packet_later(stream, ZRTP_NONE); + + /* + * Compute the SAS value if it isn't computed yet. If there are several + * streams running in parallel - stream with the biggest hvi should + * generate the SAS. + */ + if (!session->sas1.length) { + s = session->sasscheme->compute(session->sasscheme, stream, session->hash, 0); + if (zrtp_status_ok != s) { + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_software, 1); + return s; + } + + + ZRTP_LOG(3,(_ZTU_,"\tThis is the very first stream in sID GENERATING SAS value.\n", session->id)); + ZRTP_LOG(3,(_ZTU_,"\tSAS computed: <%.16s> <%.16s>.\n", session->sas1.buffer, session->sas2.buffer)); + } + + /* + * Compute a new value for RS1 and store the prevoious one. + * Compute result secrets' flags. + */ + if (ZRTP_IS_STREAM_DH(stream)) + { + ZRTP_LOG(3,(_ZTU_,"\tCheck expiration interval: last_use=%u ttl=%u new_ttl=%u exp=%u now=%u\n", + secrets->rs1->lastused_at, + secrets->rs1->ttl, + stream->cache_ttl, + (secrets->rs1->lastused_at + secrets->rs1->ttl), + zrtp_time_now()/1000)); + + if (secrets->rs1->ttl != 0xFFFFFFFF) { + exp_date = secrets->rs1->lastused_at; + exp_date += secrets->rs1->ttl; + + if (ZRTP_IS_STREAM_DH(stream) && (exp_date < zrtp_time_now()/1000)) { + ZRTP_LOG(3,(_ZTU_,"\tUsing EXPIRED secrets: last_use=%u ttl=%u exp=%u now=%u\n", + secrets->rs1->lastused_at, + secrets->rs1->ttl, + (secrets->rs1->lastused_at + secrets->rs1->ttl), + zrtp_time_now()/1000)); + was_exp = 1; + } + } + + if (!was_exp) { + secrets->wrongs = secrets->matches ^ secrets->cached; + secrets->wrongs &= ~ZRTP_BIT_RS2; + secrets->wrongs &= ~ZRTP_BIT_PBX; + } + } + + /* + * We going to update RS1 and change appropriate secrets flags. Let's back-up current values. + * Back-upped values could be used in debug purposes and in the GUI to reflect current state of the call + */ + if (!ZRTP_IS_STREAM_MULT(stream)) { + secrets->cached_curr = secrets->cached; + secrets->matches_curr = secrets->matches; + secrets->wrongs_curr = secrets->wrongs; + } + + + ZRTP_LOG(3,(_ZTU_,"\tFlags C=%x M=%x W=%x ID=%u\n", + secrets->cached, secrets->matches, secrets->wrongs, stream->id)); + + _zrtp_change_state(stream, ZRTP_STATE_SECURE); + /* + * Alarm user if the following condition is TRUE for both RS1 and RS2: + * "secret is wrong if it has been restored from the cache but hasn't matched + * with the remote one". + */ + if (session->zrtp->cb.event_cb.on_zrtp_protocol_event) { + session->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_IS_SECURE); + } + if (session->zrtp->cb.event_cb.on_zrtp_secure) { + session->zrtp->cb.event_cb.on_zrtp_secure(stream); + } + + /* Alarm user if possible MiTM attack detected */ + if (secrets->wrongs) { + session->mitm_alert_detected = 1; + + if (session->zrtp->cb.event_cb.on_zrtp_security_event) { + session->zrtp->cb.event_cb.on_zrtp_security_event(stream, ZRTP_EVENT_MITM_WARNING); + } + } + + /* Check for unenrollemnt first */ + if ((secrets->cached & ZRTP_BIT_PBX) && !(secrets->matches & ZRTP_BIT_PBX)) { + ZRTP_LOG(2,(_ZTU_,"\tINFO! The user requires new un-enrolment - the nedpint may clear" + " the cache or perform other action. ID=%u\n", stream->id)); + + if (session->zrtp->cb.event_cb.on_zrtp_protocol_event) { + session->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_USER_UNENROLLED); + } + } + + /* + * Handle PBX registration, if required: If PBX already had a shared secret + * for the ZID it leaves the cache entry unmodified. Else, it computes a new + * one. If the PBX detects cache entry for the static shared secret, but the + * phone does not have a matching cache entry - the PBX generates a new one. + */ + if (ZRTP_MITM_MODE_REG_SERVER == stream->mitm_mode) + { + if (secrets->matches & ZRTP_BIT_PBX) { + ZRTP_LOG(2,(_ZTU_,"\tINFO! User have been already registered - skip enrollment ritual. ID=%u\n", stream->id)); + if (session->zrtp->cb.event_cb.on_zrtp_protocol_event) { + session->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_USER_ALREADY_ENROLLED); + } + } else { + ZRTP_LOG(2,(_ZTU_,"\tINFO! The user requires new enrolment - generate new MiTM secret. ID=%u\n", stream->id)); + zrtp_register_with_trusted_mitm(stream); + if (session->zrtp->cb.event_cb.on_zrtp_protocol_event) { + stream->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_NEW_USER_ENROLLED); + } + + } + } + else if (ZRTP_MITM_MODE_REG_CLIENT == stream->mitm_mode) + { + if (session->zrtp->cb.event_cb.on_zrtp_protocol_event) { + session->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_IS_CLIENT_ENROLLMENT); + } + } + + /* + * Compute new RS for FULL DH streams only. Don't update RS1 if cache TTL is 0 + */ + if (ZRTP_IS_STREAM_DH(stream)) + { + static const zrtp_string32_t rss_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_RS_STR); + + if (stream->cache_ttl > 0) { + /* Replace RS2 with RS1 */ + zrtp_sys_free(secrets->rs2); + secrets->rs2 = secrets->rs1; + + secrets->rs1 = _zrtp_alloc_shared_secret(session); + if (!secrets->rs1) { + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_software, 1); + return zrtp_status_fail; + } + + /* + * Compute new RS1 based on previous one and S0: + * rs1 = KDF(s0, "retained secret", KDF_Context, negotiated hash length) + */ + _zrtp_kdf( stream, + ZSTR_GV(cc->s0), + ZSTR_GV(rss_label), + ZSTR_GV(cc->kdf_context), + ZRTP_HASH_SIZE, + ZSTR_GV(secrets->rs1->value)); + + /* + * Mark secrets as cached: RS1 have been just generated and cached; + * RS2 is cached if previous secret was cached as well. + */ + secrets->rs1->_cachedflag = 1; + secrets->cached |= ZRTP_BIT_RS1; + secrets->matches |= ZRTP_BIT_RS1; + if (secrets->rs2->_cachedflag) { + secrets->cached |= ZRTP_BIT_RS2; + } + + /* Let's update the TTL interval for the new secret */ + secrets->rs1->ttl = stream->cache_ttl; + secrets->rs1->lastused_at = (uint32_t)(zrtp_time_now()/1000); + + /* If possible MiTM attach detected - postpone storing the cache until after the user verify the SAS */ + if (!session->mitm_alert_detected) { + if (session->zrtp->cb.cache_cb.on_put) { + session->zrtp->cb.cache_cb.on_put( ZSTR_GV(session->zid), + ZSTR_GV(session->peer_zid), + secrets->rs1); + } + } + + { + uint32_t verifiedflag = 0; + char buff[128]; + if (session->zrtp->cb.cache_cb.on_get_verified) { + session->zrtp->cb.cache_cb.on_get_verified( ZSTR_GV(session->zid), + ZSTR_GV(session->peer_zid), + &verifiedflag); + } + + ZRTP_LOG(3,(_ZTU_,"\tNew secret was generated:\n")); + ZRTP_LOG(3,(_ZTU_,"\t\tRS1 value:<%s>\n", + hex2str(secrets->rs1->value.buffer, secrets->rs1->value.length, buff, sizeof(buff)))); + ZRTP_LOG(3,(_ZTU_,"\t\tTTL=%u, flags C=%x M=%x W=%x V=%d\n", + secrets->rs1->ttl, secrets->cached, secrets->matches, secrets->wrongs, verifiedflag)); + } + } /* for TTL > 0 only */ + else { + if (session->zrtp->cb.cache_cb.on_put) { + secrets->rs1->ttl = 0; + session->zrtp->cb.cache_cb.on_put( ZSTR_GV(session->zid), + ZSTR_GV(session->peer_zid), + secrets->rs1); + } + } + } /* For DH mode only */ + + + if (session->zrtp->cb.event_cb.on_zrtp_protocol_event) { + session->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_IS_SECURE_DONE); + } + + /* We have computed all subkeys from S0 and don't need it anylonger. */ + zrtp_wipe_zstring(ZSTR_GV(cc->s0)); + + /* Clear DH crypto context */ + if (ZRTP_IS_STREAM_DH(stream)) { + bnEnd(&stream->dh_cc.peer_pv); + bnEnd(&stream->dh_cc.pv); + bnEnd(&stream->dh_cc.sv); + zrtp_wipe_zstring(ZSTR_GV(stream->dh_cc.dhss)); + } + + /* + * Increase calls counter for Preshared mode and reset it on DH + */ + if (session->zrtp->cb.cache_cb.on_presh_counter_get && session->zrtp->cb.cache_cb.on_presh_counter_set) { + uint32_t calls_counter = 0; + session->zrtp->cb.cache_cb.on_presh_counter_get( ZSTR_GV(session->zid), + ZSTR_GV(session->peer_zid), + &calls_counter); + if (ZRTP_IS_STREAM_DH(stream)) { + session->zrtp->cb.cache_cb.on_presh_counter_set( ZSTR_GV(session->zid), + ZSTR_GV(session->peer_zid), + 0); + } else if ZRTP_IS_STREAM_PRESH(stream) { + session->zrtp->cb.cache_cb.on_presh_counter_set( ZSTR_GV(session->zid), + ZSTR_GV(session->peer_zid), + ++calls_counter); + } + } + + clear_crypto_sources(stream); + + return zrtp_status_ok; +} + + +/*===========================================================================*/ +/* Shared functions */ +/*===========================================================================*/ + +/*----------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_create_confirm( zrtp_stream_t *stream, + zrtp_packet_Confirm_t* confirm) +{ + void* cipher_ctx = NULL; + zrtp_status_t s = zrtp_status_fail; + zrtp_session_t *session = stream->session; + uint32_t verifiedflag = 0; + + /* hash + (padding + sig_len + flags) + ttl */ + const uint8_t encrypted_body_size = ZRTP_MESSAGE_HASH_SIZE + (2 + 1 + 1) + 4; + + /* + * Create the Confirm packet according to draft 6.7 + * AES CFB vector at first, SIG length and flags octet and cache TTL at the end + * This version doesn't support signatures so sig_length=0 + */ + if (ZRTP_CFBIV_SIZE != zrtp_randstr(session->zrtp, confirm->iv, ZRTP_CFBIV_SIZE)) { + return zrtp_status_fail; + } + + zrtp_memcpy(confirm->hash, stream->messages.h0.buffer, ZRTP_MESSAGE_HASH_SIZE); + + if (session->zrtp->cb.cache_cb.on_get_verified) { + session->zrtp->cb.cache_cb.on_get_verified( ZSTR_GV(session->zid), + ZSTR_GV(session->peer_zid), + &verifiedflag); + } + + confirm->expired_interval = zrtp_hton32(session->profile.cache_ttl); + confirm->flags = 0; + confirm->flags |= session->profile.disclose_bit ? 0x01 : 0x00; + confirm->flags |= session->profile.allowclear ? 0x02 : 0x00; + confirm->flags |= verifiedflag ? 0x04 : 0x00; + confirm->flags |= (ZRTP_MITM_MODE_REG_SERVER == stream->mitm_mode) ? 0x08 : 0x00; + + /* Then we need to encrypt Confirm before Hmac computing. Use AES CFB */ + do + { + cipher_ctx = session->blockcipher->start( session->blockcipher, + (uint8_t*)stream->cc.zrtp_key.buffer, + NULL, + ZRTP_CIPHER_MODE_CFB); + if (!cipher_ctx) { + break; + } + + s = session->blockcipher->set_iv(session->blockcipher, cipher_ctx, (zrtp_v128_t*)confirm->iv); + if (zrtp_status_ok != s) { + break; + } + + s = session->blockcipher->encrypt( session->blockcipher, + cipher_ctx, + (uint8_t*)&confirm->hash, + encrypted_body_size ); + } while(0); + if (cipher_ctx) { + session->blockcipher->stop(session->blockcipher, cipher_ctx); + } + if (zrtp_status_ok != s) { + ZRTP_LOG(1,(_ZTU_,"ERROR! failed to encrypt Confirm. s=%d ID=%u\n", s, stream->id)); + return s; + } + + /* Compute Hmac over encrypted part of Confirm */ + { + zrtp_string128_t hmac = ZSTR_INIT_EMPTY(hmac); + s = session->hash->hmac_c( session->hash, + stream->cc.hmackey.buffer, + stream->cc.hmackey.length, + (const char*)&confirm->hash, + encrypted_body_size, + ZSTR_GV(hmac) ); + if (zrtp_status_ok != s) { + ZRTP_LOG(1,(_ZTU_,"ERROR! failed to compute Confirm hmac. s=%d ID=%u\n", s, stream->id)); + return s; + } + + zrtp_memcpy(confirm->hmac, hmac.buffer, ZRTP_HMAC_SIZE); + } + + return zrtp_status_ok; +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_confirm( zrtp_stream_t *stream, + zrtp_packet_Confirm_t *confirm) +{ + /* Compute Hmac over encrypted part of Confirm and reject malformed packets */ + void* cipher_ctx = NULL; + zrtp_status_t s = zrtp_status_fail; + zrtp_session_t *session = stream->session; + zrtp_string128_t hmac = ZSTR_INIT_EMPTY(hmac); + + /* hash + (padding + sig_len + flags) + ttl */ + const uint8_t encrypted_body_size = ZRTP_MESSAGE_HASH_SIZE + (2 + 1 + 1) + 4; + s = session->hash->hmac_c( session->hash, + stream->cc.peer_hmackey.buffer, + stream->cc.peer_hmackey.length, + (const char*)&confirm->hash, + encrypted_body_size, + ZSTR_GV(hmac) ); + if (zrtp_status_ok != s) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! failed to compute Incoming Confirm hmac. s=%d ID=%u\n", s, stream->id)); + return zrtp_status_fail; + } + + if (0 != zrtp_memcmp(confirm->hmac, hmac.buffer, ZRTP_HMAC_SIZE)) { + /* + * Weird. Perhaps a bug in our code or our peer's code. Or it could be an attacker + * who doesn't realize that Man-In-The-Middling the Diffie-Hellman key generation + * but allowing the correct rsIds to pass through accomplishes nothing more than + * forcing us to fallback to cleartext mode. If this attacker had gone ahead and deleted + * or replaced the rsIds, then he would have been able to stay in the middle (although + * he would of course still face the threat of a Voice Authentication Check). On the + * other hand if this attacker wanted to force us to fallback to cleartext mode, he could + * have done that more simply, for example by intercepting our ZRTP HELLO packet and + * replacing it with a normal non-ZRTP comfort noise packet. In any case, we'll do our + * "switch to cleartext fallback" behavior. + */ + + ZRTP_LOG(2,(_ZTU_,"\tWARNING!" ZRTP_VERIFIED_RESP_WARNING_STR "ID=%u\n", stream->id)); + + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_auth_decrypt, 1); + return zrtp_status_fail; + } + + /* Then we need to decrypt Confirm body */ + do { + cipher_ctx = session->blockcipher->start( session->blockcipher, + (uint8_t*)stream->cc.peer_zrtp_key.buffer, + NULL, + ZRTP_CIPHER_MODE_CFB); + if (!cipher_ctx) { + break; + } + + s = session->blockcipher->set_iv( session->blockcipher, + cipher_ctx, + (zrtp_v128_t*)confirm->iv); + if (zrtp_status_ok != s) { + break; + } + + s = session->blockcipher->decrypt( session->blockcipher, + cipher_ctx, + (uint8_t*)&confirm->hash, + encrypted_body_size); + } while(0); + if (cipher_ctx) { + session->blockcipher->stop(session->blockcipher, cipher_ctx); + } + if (zrtp_status_ok != s) { + ZRTP_LOG(3,(_ZTU_,"\tERROR! failed to decrypt incoming Confirm. s=%d ID=%u\n", s, stream->id)); + return s; + } + + /* We have access to hash field and can check hmac of the previous message */ + { + zrtp_msg_hdr_t *hdr = NULL; + char *key=NULL; + zrtp_string32_t tmphash_str = ZSTR_INIT_EMPTY(tmphash_str); + zrtp_hash_t *hash = zrtp_comp_find( ZRTP_CC_HASH, ZRTP_HASH_SHA256, stream->zrtp); + + if (ZRTP_IS_STREAM_DH(stream)) { + hdr = &stream->messages.peer_dhpart.hdr; + key = (char*)confirm->hash; + } else { + hash->hash_c(hash, (char*)confirm->hash, ZRTP_MESSAGE_HASH_SIZE, ZSTR_GV(tmphash_str)); + + if (ZRTP_STATEMACHINE_INITIATOR == stream->protocol->type) { + hdr = &stream->messages.peer_hello.hdr; + hash->hash_c( hash, + tmphash_str.buffer, + ZRTP_MESSAGE_HASH_SIZE, + ZSTR_GV(tmphash_str) ); + } else { + hdr = &stream->messages.peer_commit.hdr; + } + key = tmphash_str.buffer; + } + + if (0 != _zrtp_validate_message_hmac(stream, hdr, key)) { + return zrtp_status_fail; + } + } + + /* Set evil bit if other-side shared session key */ + stream->peer_disclose_bit = (confirm->flags & 0x01); + + /* Enable ALLOWCLEAR option if only both sides support it */ + stream->allowclear = (confirm->flags & 0x02) && session->profile.allowclear; + + /* Drop RS1 VERIFIED flag if other side didn't verified key exchange */ + if (0 == (confirm->flags & 0x04)) { + ZRTP_LOG(2,(_ZTU_,"\tINFO: Other side Confirm V=0 - set verified to 0! ID=%u\n", stream->id)); + zrtp_verified_set(session->zrtp, &session->zid, &session->peer_zid, 0); + } + + /* Look for Enrollment replay flag */ + if (confirm->flags & 0x08) + { + ZRTP_LOG(2,(_ZTU_,"\tINFO: Confirm PBX Enrolled flag is set - it is a Registration call! ID=%u\n", stream->id)); + + if (stream->mitm_mode != ZRTP_MITM_MODE_CLIENT) { + ZRTP_LOG(2,(_ZTU_,"\tERROR: PBX enrollment flag was received in wrong MiTM mode %s." + " ID=%u\n", zrtp_log_mode2str(stream->mode), stream->id)); + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_invalid_packet, 1); + return zrtp_status_fail; + } + + stream->mitm_mode = ZRTP_MITM_MODE_REG_CLIENT; + } + + stream->cache_ttl = ZRTP_MIN(session->profile.cache_ttl, zrtp_ntoh32(confirm->expired_interval)); + + /* Copy packet for future hashing */ + zrtp_memcpy(&stream->messages.peer_confirm, confirm, zrtp_ntoh16(confirm->hdr.length)*4); + + return zrtp_status_ok; +} diff --git a/src/zrtp_responder.c b/src/zrtp_responder.c new file mode 100644 index 0000000000..73e25f7495 --- /dev/null +++ b/src/zrtp_responder.c @@ -0,0 +1,612 @@ +/* + * 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 + */ + +#include "zrtp.h" + +#define _ZTU_ "zrtp responder" + +extern zrtp_status_t _zrtp_machine_start_initiating_secure(zrtp_stream_t *stream); + +/* These functions construct packets for further replies. */ +static zrtp_status_t _prepare_dhpart1(zrtp_stream_t *stream); +static zrtp_status_t _prepare_confirm1(zrtp_stream_t *stream); + +/* Functions which are used to answer the Initiator's requests */ +static void _send_dhpart1(zrtp_stream_t *stream); +static void _send_confirm1(zrtp_stream_t *stream); + +/* + * Parses crypto-components list chosen by the initiator. doesn't perform any + * tests. Commit was fully checked by previous call of _zrtp_machine_preparse_commit(). + * \exception: Handles all exceptions -- informs user and switches to CLEAR. + * (zrtp_error_XXX_unsp and zrtp_error_software errors.) + */ +static zrtp_status_t _zrtp_machine_process_commit( zrtp_stream_t* stream, + zrtp_rtp_info_t* packet); + +/* + * Parses DH packet: check for MitM1, MitM2 attacks and makes a copy of it for further usage. + * \exception: (MITM attacks, SOFTWARE) Informs user and switches to CLEAR. + */ +static zrtp_status_t _zrtp_machine_process_dhpart2( zrtp_stream_t *stream, + zrtp_rtp_info_t *packet); + +/* + * Just a wrapper over the protocol::_zrtp_machine_process_confirm(). + * \exception: (AUTH attacks, SOFTWARE) Informs user and switches to CLEAR. + */ +static zrtp_status_t _zrtp_machine_process_confirm2( zrtp_stream_t *stream, + zrtp_rtp_info_t *packet); + + +/*===========================================================================*/ +/* State handlers */ +/*===========================================================================*/ + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_while_in_pendingsecure( zrtp_stream_t* stream, + zrtp_rtp_info_t* packet) +{ + zrtp_status_t s = zrtp_status_ok; + + switch (packet->type) + { + case ZRTP_COMMIT: + _send_dhpart1(stream); + break; + + case ZRTP_DHPART2: + s = _zrtp_machine_process_dhpart2(stream, packet); + if (zrtp_status_ok != s) { + break; + } + + /* Perform Keys generation according to draft 5.6 */ + s = _zrtp_set_public_value(stream, 0); + if (zrtp_status_ok != s) { + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_software, 1); + break; + } + + s = _prepare_confirm1(stream); + if (zrtp_status_ok != s) { + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_software, 1); + break; + } + + _zrtp_change_state(stream, ZRTP_STATE_WAIT_CONFIRM2); + _send_confirm1(stream); + break; + + case ZRTP_NONE: + s = zrtp_status_drop; + break; + + default: + break; + } + + return s; +} + + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_while_in_waitconfirm2( zrtp_stream_t* stream, + zrtp_rtp_info_t* packet) +{ + zrtp_status_t status = zrtp_status_ok; + + switch (packet->type) + { + case ZRTP_DHPART2: + if (ZRTP_IS_STREAM_DH(stream)) { + _send_confirm1(stream); + } + break; + + case ZRTP_COMMIT: + if (ZRTP_IS_STREAM_FAST(stream)) { + _send_confirm1(stream); + } + break; + + case ZRTP_CONFIRM2: + status = _zrtp_machine_process_confirm2(stream, packet); + if (zrtp_status_ok == status) { + _zrtp_packet_send_message(stream, ZRTP_CONFIRM2ACK, NULL); + status = _zrtp_machine_enter_secure(stream); + } + break; + + case ZRTP_NONE: + status = zrtp_status_drop; + break; + + default: + break; + } + + return status; +} + + +/*===========================================================================*/ +/* States switchers */ +/*===========================================================================*/ + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_enter_pendingsecure( zrtp_stream_t* stream, + zrtp_rtp_info_t* packet) +{ + zrtp_status_t s = zrtp_status_ok; + + ZRTP_LOG(3,(_ZTU_,"\tENTER STATE PENDING SECURE for ID=%u mode=%s state=%s.\n", + stream->id, zrtp_log_mode2str(stream->mode), zrtp_log_state2str(stream->state))); + + do + { + if (!ZRTP_IS_STREAM_MULT(stream)) { + zrtp_packet_Commit_t *commit = (zrtp_packet_Commit_t*) packet->message; + + stream->session->hash = zrtp_comp_find( ZRTP_CC_HASH, + zrtp_comp_type2id(ZRTP_CC_HASH, (char*)commit->hash_type), + stream->zrtp); + stream->session->blockcipher = zrtp_comp_find( ZRTP_CC_CIPHER, + zrtp_comp_type2id(ZRTP_CC_CIPHER, (char*)commit->cipher_type), + stream->zrtp); + stream->session->authtaglength = zrtp_comp_find( ZRTP_CC_ATL, + zrtp_comp_type2id(ZRTP_CC_ATL, (char*)commit->auth_tag_length), + stream->zrtp); + stream->session->sasscheme = zrtp_comp_find( ZRTP_CC_SAS, + zrtp_comp_type2id(ZRTP_CC_SAS, (char*)commit->sas_type), + stream->zrtp); + + ZRTP_LOG(3,(_ZTU_,"\tRemote COMMIT specified following options:\n")); + ZRTP_LOG(3,(_ZTU_,"\t Hash: %.4s\n", commit->hash_type)); + ZRTP_LOG(3,(_ZTU_,"\t Cipher: %.4s\n", commit->cipher_type)); + ZRTP_LOG(3,(_ZTU_,"\t ATL: %.4s\n", commit->auth_tag_length)); + ZRTP_LOG(3,(_ZTU_,"\t PK scheme: %.4s\n", commit->public_key_type)); + ZRTP_LOG(3,(_ZTU_,"\tVAD scheme: %.4s\n", commit->sas_type)); + } + + if (ZRTP_IS_STREAM_DH(stream)) { + _zrtp_change_state(stream, ZRTP_STATE_PENDINGSECURE); + + /* + * If stream->concurrent is set this means that we stopped a concurrent + * DH stream to break a tie. This can happen when Commit messages are + * sent by both ZRTP endpoints at the same time, but are received in + * different media streams. Now current stream has finished DH setup and + * we can resume the other one. + */ + if (stream->concurrent) { + zrtp_stream_t* tctx = stream->concurrent; + stream->concurrent = NULL; + ZRTP_LOG(3,(_ZTU_,"\tRelease2 Concurrent stream=%u ID=%u\n", tctx->id, stream->id)); + _zrtp_machine_start_initiating_secure(tctx); + } + + s = _zrtp_protocol_init(stream, 0, &stream->protocol); + if (zrtp_status_ok != s) { + break; + } + + s = _zrtp_machine_process_commit(stream, packet); /* doesn't throw exception */ + if (zrtp_status_ok != s) { + break; /* Software error */ + } + + s = _prepare_dhpart1(stream); + if (zrtp_status_ok != s) { + break; /* EH: Always successful */ + } + + _zrtp_machine_process_while_in_pendingsecure(stream, packet); + + if (stream->zrtp->cb.event_cb.on_zrtp_protocol_event) { + stream->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_IS_PENDINGSECURE); + } + } + else + { + _zrtp_change_state(stream, ZRTP_STATE_WAIT_CONFIRM2); + + s = _zrtp_protocol_init(stream, 0, &stream->protocol); + if (zrtp_status_ok != s) { + break; + } + + s = _zrtp_machine_process_commit(stream, packet); /* doesn't throw exception */ + if (zrtp_status_ok != s) { + break; /* Software error */ + } + + s = _zrtp_set_public_value(stream, 0); + if (zrtp_status_ok != s) { + break; /* Software error */ + } + + s = _prepare_confirm1(stream); + if (zrtp_status_ok != s) { + break; /* Software error */ + } + + _send_confirm1(stream); + } + } while (0); + + if (zrtp_status_ok != s) { + if (stream->protocol) { + _zrtp_protocol_destroy(stream->protocol); + stream->protocol = NULL; + } + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_software, 1); + } + + return s; +} + + +/*===========================================================================*/ +/* Packets handlers */ +/*===========================================================================*/ + +/*---------------------------------------------------------------------------*/ +static zrtp_status_t _check_commit(zrtp_stream_t *stream, zrtp_packet_Commit_t *commit) +{ + do { + /* check PUBLIC KEY TYPE */ + if (0 > zrtp_profile_find( &stream->session->profile, + ZRTP_CC_PKT, + zrtp_comp_type2id(ZRTP_CC_PKT, (char*)commit->public_key_type))) + { + /* Can't talk to them. ZRTP public key type not supported by current profile */ + ZRTP_LOG(2,(_ZTU_,"\tINFO: PKExch %.4s isn't supported by profile. ID=%u\n", + commit->public_key_type, stream->id)); + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_pktype_unsp, 1); + break; + } + + /* check HASH scheme */ + if ( 0 > zrtp_profile_find( &stream->session->profile, + ZRTP_CC_HASH, + zrtp_comp_type2id(ZRTP_CC_HASH, (char*)commit->hash_type)) ) + { + /* Can't talk to them. ZRTP hash type not supported by current profile */ + ZRTP_LOG(2,(_ZTU_,"\tINFO: Hash %.4s isn't supported by profile. ID=%u\n", + commit->hash_type, stream->id)); + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_hash_unsp, 1); + break; + } + + /* check CIPHER type */ + if ( 0 > zrtp_profile_find( &stream->session->profile, + ZRTP_CC_CIPHER, + zrtp_comp_type2id(ZRTP_CC_CIPHER, (char*)commit->cipher_type)) ) + { + /* Can't talk to them. ZRTP cipher type not supported by current profile */ + ZRTP_LOG(2,(_ZTU_,"\tINFO: Cipher %.4s isn't supported by profile. ID=%u\n", + commit->cipher_type, stream->id)); + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_cipher_unsp, 1); + break; + } + + /* check AUTH TAG LENGTH */ + if ( 0 > zrtp_profile_find( &stream->session->profile, + ZRTP_CC_ATL, + zrtp_comp_type2id(ZRTP_CC_ATL, (char*)commit->auth_tag_length)) ) + { + /* Can't talk to them. ZRTP auth tag length not supported by current profile */ + ZRTP_LOG(2,(_ZTU_,"\tINFO: Authtag %.4s isn't supported by profile. ID=%u\n", + commit->auth_tag_length, stream->id)); + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_auth_unsp, 1); + break; + } + + /* check SAS scheme */ + if ( 0 > zrtp_profile_find( &stream->session->profile, + ZRTP_CC_SAS, + zrtp_comp_type2id(ZRTP_CC_SAS, (char*)commit->sas_type)) ) + { + /* Can't talk to them. ZRTP SAS scheme not supported by current profile */ + ZRTP_LOG(2,(_ZTU_,"\tINFO: SAS %.4s isn't supported by profile. ID=%u\n", + commit->sas_type, stream->id)); + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_sas_unsp, 1); + break; + } + + return zrtp_status_ok; + } while (0); + + return zrtp_status_fail; +} + +/*---------------------------------------------------------------------------*/ +zrtp_statemachine_type_t _zrtp_machine_preparse_commit( zrtp_stream_t *stream, + zrtp_rtp_info_t* packet) +{ + zrtp_packet_Commit_t *commit = (zrtp_packet_Commit_t*) packet->message; + zrtp_statemachine_type_t res = ZRTP_STATEMACHINE_RESPONDER; + + zrtp_pktype_id_t his_pkt = zrtp_comp_type2id(ZRTP_CC_PKT, (char*)commit->public_key_type); + zrtp_stream_mode_t his_mode = (his_pkt == ZRTP_PKTYPE_PRESH) ? ZRTP_STREAM_MODE_PRESHARED : (his_pkt == ZRTP_PKTYPE_MULT) ? ZRTP_STREAM_MODE_MULT : ZRTP_STREAM_MODE_DH; + + ZRTP_LOG(3,(_ZTU_,"\tPreparse incoming COMMIT. Remote peer wants %.4s:%d mode lic=%d peer M=%d.\n", + commit->public_key_type, his_mode, stream->zrtp->lic_mode, stream->peer_mitm_flag)); + + /* + * Checking crypto components chosen by other peer for stream establishment + */ + if (zrtp_status_ok != _check_commit(stream, commit)) { + return ZRTP_STATEMACHINE_NONE; + } + + /* + * Passive ZRTP endpoint can't talk to ZRTP MiTM endpoints. + */ + if (!ZRTP_PASSIVE3_TEST(stream)) { + ZRTP_LOG(2,(_ZTU_,"\tERROR: The endpoint is in passive mode and can't handle" + " connections with MiTM endpoints. ID=%u\n", stream->id)); + if (stream->zrtp->cb.event_cb.on_zrtp_protocol_event ) { + stream->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_IS_PASSIVE_RESTRICTION); + } + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_service_unavail, 1); + return ZRTP_STATEMACHINE_NONE; + } + + /* + * Both sides are in "Initiating" state we need to break the tie: + * - if both sides wants to use the same scheme - side with lower vh switches to + * "Responder" state. + * - if both sides wants to use Preshared scheme and one of the sides are in MiTM mode it + * should switch to Responder state + * - if one side wants Preshared and onother one DH - DH should win. + * - rest of the combinations (DH - Multistream, Preshared - Multistream) are deperecated by the RFC + */ + if (ZRTP_STATE_INITIATINGSECURE == stream->state) + { + zrtp_pktype_id_t my_pkt = stream->pubkeyscheme->base.id; + zrtp_stream_mode_t my_mode = (my_pkt == ZRTP_PKTYPE_PRESH) ? ZRTP_STREAM_MODE_PRESHARED : (my_pkt == ZRTP_PKTYPE_MULT) ? ZRTP_STREAM_MODE_MULT : ZRTP_STREAM_MODE_DH; + + ZRTP_LOG(2,(_ZTU_,"\tBoth sides are in INITIATINGSECURE State - BREACK the TIE. ID=%u\n", stream->id)); + + if (his_mode == my_mode) { + if ( (his_mode == ZRTP_STREAM_MODE_PRESHARED) && (stream->peer_mitm_flag || stream->zrtp->is_mitm)) { + if (stream->peer_mitm_flag) { + ZRTP_LOG(3,(_ZTU_,"\tWe running in Gneral ZRTP Endpoint mode, but the" + " remote side is in MiTM - stay Initiating state.\n")); + res = ZRTP_STATEMACHINE_INITIATOR; + } + } else { + if (zrtp_memcmp( stream->protocol->cc->hv.buffer, + commit->hv, + (his_mode == ZRTP_STREAM_MODE_DH) ? ZRTP_HV_SIZE : ZRTP_HV_NONCE_SIZE) > 0) { + ZRTP_LOG(3,(_ZTU_,"\tWe have Commit with greater HV so stay Initiating state.\n")); + res = ZRTP_STATEMACHINE_INITIATOR; + } + } + } else { + if (my_mode == ZRTP_STREAM_MODE_DH) { + ZRTP_LOG(3,(_ZTU_,"\tOther peer sent Non DH Commit but we want DH - stay Initiating state.\n")); + res = ZRTP_STATEMACHINE_INITIATOR; + } + } + } + + if (res == ZRTP_STATEMACHINE_RESPONDER) + { + /* + * If other peer wants to switch "Preshared" we must be ready for this. Check + * for secrets availability and if we can't use "Preshared" we should force other + * peer to switch to "DH" mode. For this purpose we use our own Commit with DHxK + * in it. Such Commit should win competition in any case. + */ + if ((his_mode == ZRTP_STREAM_MODE_PRESHARED) && !stream->session->secrets.rs1->_cachedflag) { + ZRTP_LOG(3,(_ZTU_, "\tOther peer wants Preshared mode but we have no secrets.\n")); + res = ZRTP_STATEMACHINE_INITIATOR; + } + + /* + * If other peer wants to switch "Multistream" we must be ready for this. Check + * for ZRTPSess key availability. If we can't use "Multistream" we should force other + * peer to switch to "DH" mode. For this purpose we use our own Commit with DHxK + * in it. Such Commit should win competition in any case. + */ + if ((his_mode == ZRTP_STREAM_MODE_MULT) && !stream->session->zrtpsess.length) { + ZRTP_LOG(3,(_ZTU_,"\tOther peer wants Preshared mode but we have no secrets.\n")); + res = ZRTP_STATEMACHINE_INITIATOR; + } + + /* + * If other peer wants "Full DH" exchange but ZRTP Session key have been already + * computed - there is no sense in doing this. What is more, ZRTP Specification + * doesn't allow doing this. + */ + if ((his_mode == ZRTP_STREAM_MODE_DH) && (stream->session->zrtpsess.length > 0)) { + ZRTP_LOG(3,(_ZTU_,"\tOther peer wants DH mode but we have ZRTP session and ready for Multistream.\n")); + res = ZRTP_STATEMACHINE_NONE; + } + } + + /* + * If we decided to use Responder's state-machine - only one DH or Preshared stream + * can be run at the moment so check states. + */ + if ((res == ZRTP_STATEMACHINE_RESPONDER) && !_zrtp_can_start_stream(stream, &stream->concurrent, his_mode)) + { + ZRTP_LOG(3,(_ZTU_,"\tCan't handle COMMIT another DH with ID=%u is in progress.\n", stream->concurrent->id)); + + if ( (stream->concurrent->state <= ZRTP_STATE_INITIATINGSECURE) && + (zrtp_memcmp(stream->concurrent->protocol->cc->hv.buffer, commit->hv, ZRTP_HV_SIZE) < 0) ) + { + ZRTP_LOG(3,(_ZTU_,"\tPossible DEADLOCK Resolving. STOP CONCURRENT" + " Stream with ID=%u\n",stream->concurrent->id)); + _zrtp_cancel_send_packet_later(stream->concurrent, ZRTP_NONE); + } else { + res = ZRTP_STATEMACHINE_NONE; + } + } + + if (res == ZRTP_STATEMACHINE_RESPONDER) { + ZRTP_LOG(3,(_ZTU_,"\tChosen Responder State-Machine. Change Mode to %s," + " pkt to %.4s\n", zrtp_log_mode2str(his_mode), commit->public_key_type)); + stream->mode = his_mode; + stream->pubkeyscheme = zrtp_comp_find(ZRTP_CC_PKT, his_pkt, stream->zrtp); + } else { + ZRTP_LOG(3,(_ZTU_,"\tChosen Initiator State-Machine. Stay in current Mode\n")); + } + + return res; +} + +/*---------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_commit(zrtp_stream_t* stream, zrtp_rtp_info_t* packet) +{ + zrtp_packet_Commit_t *commit = (zrtp_packet_Commit_t*) packet->message; + + switch (stream->mode) + { + case ZRTP_STREAM_MODE_DH: + zrtp_zstrncpyc( ZSTR_GV(stream->protocol->cc->peer_hv), + (const char*)commit->hv, + ZRTP_HV_SIZE); + break; + case ZRTP_STREAM_MODE_PRESHARED: + zrtp_zstrncpyc( ZSTR_GV(stream->protocol->cc->peer_hv), + (const char*)commit->hv + ZRTP_HV_NONCE_SIZE, + ZRTP_HV_NONCE_SIZE); + case ZRTP_STREAM_MODE_MULT: + zrtp_zstrncpyc( ZSTR_GV(stream->protocol->cc->peer_hv), + (const char*)commit->hv, + ZRTP_HV_NONCE_SIZE); + break; + default: break; + } + + /* Copy Commit packet for further hashing */ + zrtp_memcpy(&stream->messages.peer_commit, commit, zrtp_ntoh16(commit->hdr.length)*4); + + return zrtp_status_ok; +} + + +/*----------------------------------------------------------------------------*/ +static zrtp_status_t _zrtp_machine_process_dhpart2( zrtp_stream_t *stream, + zrtp_rtp_info_t *packet) +{ + zrtp_status_t s = zrtp_status_ok; + zrtp_proto_crypto_t* cc = stream->protocol->cc; + zrtp_packet_DHPart_t *dhpart2 = (zrtp_packet_DHPart_t*) packet->message; + void *hash_ctx = NULL; + + /* + * Verify hash commitment. (Compare hvi calculated from DH with peer hvi from COMMIT) + * According to the last version of the internet draft 04a. Hvi should be + * computed as: hvi=hash(initiator's DHPart2 message | responder's Hello message) + */ + hash_ctx = stream->session->hash->hash_begin(stream->session->hash); + if (!hash_ctx) { + return zrtp_status_fail; + } + + stream->session->hash->hash_update( stream->session->hash, + hash_ctx, + (const int8_t*)dhpart2, + zrtp_ntoh16(dhpart2->hdr.length)*4); + stream->session->hash->hash_update( stream->session->hash, + hash_ctx, + (const int8_t*)&stream->messages.hello, + zrtp_ntoh16(stream->messages.hello.hdr.length)*4); + stream->session->hash->hash_end( stream->session->hash, + hash_ctx, + ZSTR_GV(cc->hv)); + + /* Truncate comuted hvi to 256 bit. The same length as transferred in Commit message.*/ + cc->hv.length = ZRTP_HASH_SIZE; + + if (0 != zrtp_zstrcmp(ZSTR_GV(cc->hv), ZSTR_GV(cc->peer_hv))) { + ZRTP_LOG(1,(_ZTU_,"\tERROR!" ZRTP_MIM2_WARNING_STR " ID=%u\n", stream->id)); + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_possible_mitm2, 1); + return zrtp_status_fail; + } + + /* Validate DH exchange (pvi is 1 or p-1). For DH streams only */ + bnInsertBigBytes(&stream->dh_cc.peer_pv, dhpart2->pv, 0, stream->pubkeyscheme->pv_length); + + s = stream->pubkeyscheme->validate(stream->pubkeyscheme, &stream->dh_cc.peer_pv); + if (zrtp_status_ok != s) { + ZRTP_LOG(1,(_ZTU_,"\tERROR!" ZRTP_MITM1_WARNING_STR " ID=%u\n", stream->id)); + _zrtp_machine_enter_initiatingerror(stream, zrtp_error_possible_mitm1, 1); + return s; + } + + /* Copy DH Part2 packet for future hashing */ + zrtp_memcpy(&stream->messages.peer_dhpart, dhpart2, zrtp_ntoh16(dhpart2->hdr.length)*4); + + return s; +} + +/*----------------------------------------------------------------------------*/ +zrtp_status_t _zrtp_machine_process_confirm2( zrtp_stream_t *stream, + zrtp_rtp_info_t *packet) +{ + zrtp_packet_Confirm_t *confirm2 = (zrtp_packet_Confirm_t*) packet->message; + return _zrtp_machine_process_confirm(stream, confirm2); +} + + +/*===========================================================================*/ +/* Packets senders */ +/*===========================================================================*/ + +/*----------------------------------------------------------------------------*/ +static void _send_dhpart1(zrtp_stream_t *stream) +{ + _zrtp_packet_send_message(stream, ZRTP_DHPART1, &stream->messages.dhpart); +} + +static zrtp_status_t _prepare_dhpart1(zrtp_stream_t *stream) +{ + zrtp_proto_crypto_t* cc = stream->protocol->cc; + zrtp_packet_DHPart_t *dh1 = &stream->messages.dhpart; + uint16_t dh_length = (uint16_t)stream->pubkeyscheme->pv_length; + + zrtp_memcpy(dh1->rs1ID, cc->rs1.id.buffer, ZRTP_RSID_SIZE); + zrtp_memcpy(dh1->rs2ID, cc->rs2.id.buffer, ZRTP_RSID_SIZE); + zrtp_memcpy(dh1->auxsID, cc->auxs.id.buffer, ZRTP_RSID_SIZE); + zrtp_memcpy(dh1->pbxsID, cc->pbxs.id.buffer, ZRTP_RSID_SIZE); + + bnExtractBigBytes(&stream->dh_cc.pv, dh1->pv, 0, dh_length); + + _zrtp_packet_fill_msg_hdr( stream, + ZRTP_DHPART1, + dh_length + ZRTP_DH_STATIC_SIZE + ZRTP_HMAC_SIZE, + &dh1->hdr); + + return zrtp_status_ok; +} + +/*----------------------------------------------------------------------------*/ +static void _send_confirm1(zrtp_stream_t *stream) +{ + _zrtp_packet_send_message(stream, ZRTP_CONFIRM1, &stream->messages.confirm); +} + +static zrtp_status_t _prepare_confirm1(zrtp_stream_t *stream) +{ + zrtp_status_t s = _zrtp_machine_create_confirm(stream, &stream->messages.confirm); + if (zrtp_status_ok == s) { + s = _zrtp_packet_fill_msg_hdr( stream, + ZRTP_CONFIRM1, + sizeof(zrtp_packet_Confirm_t) - sizeof(zrtp_msg_hdr_t), + &stream->messages.confirm.hdr); + } + + return s; +} diff --git a/src/zrtp_rng.c b/src/zrtp_rng.c new file mode 100644 index 0000000000..aea1f39a79 --- /dev/null +++ b/src/zrtp_rng.c @@ -0,0 +1,345 @@ +/* + * 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. + */ + +#include "zrtp.h" + +#define _ZTU_ "zrtp rng" + +#define MD_DIGEST_LENGTH SHA512_DIGEST_SIZE +#define MD_CTX_init(a) +#define MD_Init(a) sha512_begin(a) +#define MD_Final(a,b) sha512_end(b,a) +#define MD_Cleanup(a) zrtp_memset(a,0,sizeof(*a)); + + +#if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WIN64) || (ZRTP_PLATFORM == ZP_WINCE) + +#include + +HCRYPTPROV g_hCryptProv; + +zrtp_status_t NtLmInitializeRNG(VOID) +{ + BOOL fSuccess; + + if (g_hCryptProv != 0) { + return zrtp_status_ok; + } + + fSuccess = CryptAcquireContext( &g_hCryptProv, + NULL, + NULL, + PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT); + + return (TRUE == fSuccess) ? zrtp_status_ok : zrtp_status_fail; +} + +void NtLmCleanupRNG(VOID) +{ + if (g_hCryptProv) { + CryptReleaseContext(g_hCryptProv, 0); + g_hCryptProv = 0; + } +} + +int zrtp_add_system_state(zrtp_global_t* zrtp, MD_CTX *ctx) +{ + uint8_t buffer[64]; + + if(!CryptGenRandom(g_hCryptProv, sizeof(buffer), buffer)) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! Error during CryptGenRandom.\n")); + return 0; + } + + MD_Update(ctx, buffer, sizeof(buffer)); + ZeroMemory((PVOID)buffer, sizeof(buffer)); + + return sizeof(buffer); +} + +#elif (ZRTP_PLATFORM == ZP_WIN32_KERNEL) + +#include + +/*----------------------------------------------------------------------------*/ +int zrtp_add_system_state(zrtp_global_t* zrtp, MD_CTX *ctx) +{ + LARGE_INTEGER li1; + LARGE_INTEGER li2; + ULONG ul1; + ULONG ul2; + ULONGLONG ull; + PKTHREAD thread; + static int tsc_ok = 1; + /* + * WARNING! + * Of course it's not a real size of entropy added to the context. It's very + * difficult to compute the size of real random data and estimate its quality. + * This value means: size of maximum possible random data which this function can provide. + */ + static int entropy_length = sizeof(LARGE_INTEGER)*2 + sizeof(PKTHREAD) + + sizeof(ULONG)*2 + sizeof(LARGE_INTEGER)*2 + sizeof(ULONG)*2; + + li2 = KeQueryPerformanceCounter(&li1); + MD_Update(ctx, &li1, sizeof(LARGE_INTEGER)); + MD_Update(ctx, &li2, sizeof(LARGE_INTEGER)); + + ull = KeQueryInterruptTime(); + MD_Update(ctx, &ull, sizeof(ULONGLONG)); + + thread = KeGetCurrentThread(); + MD_Update(ctx, &thread, sizeof(PKTHREAD)); + ul2 = KeQueryRuntimeThread(thread, &ul1); + MD_Update(ctx, &ul1, sizeof(ULONG)); + MD_Update(ctx, &ul2, sizeof(ULONG)); + + KeQuerySystemTime(&li1); + MD_Update(ctx, &li1, sizeof(LARGE_INTEGER)); + + KeQueryTickCount(&li1); + MD_Update(ctx, &li1, sizeof(LARGE_INTEGER)); + + if (tsc_ok) { + __try { + ull = _RDTSC(); + MD_Update(ctx, &ull, sizeof(ULONGLONG)); + } __except(EXCEPTION_EXECUTE_HANDLER) { + tsc_ok = 0; + } + } + + return entropy_length; +} + +#elif ((ZRTP_PLATFORM == ZP_SYMBIAN)) +/* + * WARNING! + * This is just a stub to let you start with something little bit better then zero. + * We have no possibility to implement entropy collection in this abstract cross-platform + * application. This function MUST NOT be used as example in real applications. For more + * information read \ref RNG in developers guide + * + * To add real entropy - capture random data from microphone and camera. + */ +extern uint32_t zrtp_symbian_kernel_random(); +extern uint32_t zrtp_sum_of_pid_and_number_of_poccesses(); +extern uint64_t zrtp_get_system_time_crazy(); +extern unsigned int zrtp_get_pid(); +extern uint32_t zrtp_get_availible_heap(); + + +int zrtp_add_system_state(zrtp_global_t* zrtp, MD_CTX *ctx) { + uint64_t sysdate; + unsigned int pid; + uint32_t crazy_pid_sum; + + uint32_t heap_size; + + static int entropy_length = sizeof(sysdate) + sizeof(pid) + + sizeof(crazy_pid_sum) + sizeof(heap_size); + sysdate = zrtp_get_system_time_crazy(); + MD_Update(ctx,&sysdate,sizeof(sysdate)); + + pid = zrtp_get_pid(); + + MD_Update(ctx,&pid,sizeof(pid)); + + crazy_pid_sum = zrtp_sum_of_pid_and_number_of_poccesses(); + MD_Update(ctx,&crazy_pid_sum,sizeof(crazy_pid_sum)); + + heap_size = zrtp_get_availible_heap(); + MD_Update(ctx,&heap_size,sizeof(heap_size)); + + return entropy_length; +} + +#elif ( (ZRTP_PLATFORM == ZP_LINUX) || (ZRTP_PLATFORM == ZP_DARWIN) || (ZRTP_PLATFORM == ZP_BSD) ) + +#if ZRTP_HAVE_STDIO_H == 1 +# include +#else +# error "Used environment dosn't have - zrtp_rng.c can't be build." +#endif + +/*----------------------------------------------------------------------------*/ +int zrtp_add_system_state(zrtp_global_t* zrtp, MD_CTX *ctx) +{ + uint8_t buffer[64]; + size_t bytes_read = 0; + static size_t length= sizeof(buffer); + FILE *fp = NULL; + + fp = fopen("/dev/urandom", "rb"); + if (!fp) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! can't get access to /dev/urandom - trying /dev/random.\n")); + fp = fopen("/dev/random", "rb"); + } + + if (fp) { + int number_of_retries = 1024; + while ((bytes_read < length) && (number_of_retries-- > 0)) { + setbuf(fp, NULL); /* Otherwise fread() tries to read() 4096 bytes or other default value */ + bytes_read += fread(buffer+bytes_read, 1, length-bytes_read, fp); + } + + if (0 != fclose(fp)) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! unable to cloas /dev/random\n")); + } + } else { + ZRTP_LOG(1,(_ZTU_,"\tERROR! RNG Can't open /dev/random\n")); + } + + if (bytes_read < length) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! can't read random string! Current session have to be closed.\n")); + return -1; + } + + MD_Update(ctx, buffer, length); + zrtp_memset(buffer, 0, sizeof(buffer)); + + return bytes_read; +} + +#endif + +/*----------------------------------------------------------------------------*/ +zrtp_status_t zrtp_init_rng(zrtp_global_t* zrtp) +{ + if (!zrtp->rand_initialized) { + zrtp_mutex_init(&zrtp->rng_protector); + MD_Init(&zrtp->rand_ctx); +#if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WIN64) || (ZRTP_PLATFORM == ZP_WINCE) + if (zrtp_status_ok != NtLmInitializeRNG()) { + ZRTP_LOG(1,(_ZTU_,"\tERROR! during CryptAcquireContext!\n")); + return zrtp_status_fail; + } +#endif + zrtp->rand_initialized = 1; + } + + return zrtp_status_ok; +} + +void zrtp_down_rng(zrtp_global_t* zrtp) +{ + if (zrtp->rand_initialized) { + zrtp_mutex_destroy(zrtp->rng_protector); +#if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WIN64) || (ZRTP_PLATFORM == ZP_WINCE) + NtLmCleanupRNG(); +#endif + zrtp->rand_initialized = 0; + } +} + + +/* + * Call this to add entropy to the system from the given buffer, + * and also from the system state. It's OK to pass a null buffer + * with a length of zero, then we will just use the system entropy. + */ +/*----------------------------------------------------------------------------*/ +int zrtp_entropy_add(zrtp_global_t* zrtp, const unsigned char *buffer, uint32_t length) +{ + if (buffer && length) { + MD_Update(&zrtp->rand_ctx, buffer, length); + } + + return zrtp_add_system_state(zrtp, &zrtp->rand_ctx); +} + + +/* + * Random bits are produced as follows. + * First stir new entropy into the random state (zrtp->rand_ctx). + * Then make a copy of the random context and finalize it. + * Use the digest to seed an AES-256 context and, if space remains, to + * initialize a counter. + * Then encrypt the counter with the AES-256 context, incrementing it + * per block, until we have produced the desired quantity of data. + */ +/*----------------------------------------------------------------------------*/ +int zrtp_randstr(zrtp_global_t* zrtp, unsigned char *buffer, uint32_t length) +{ + //TODO: replace bg_aes_xxx() with our own block cipher component. + //TODO: Do the same with the hash functions. + + aes_encrypt_ctx aes_ctx; + MD_CTX rand_ctx2; + unsigned char md[MD_DIGEST_LENGTH]; + unsigned char ctr[AES_BLOCK_SIZE]; + unsigned char rdata[AES_BLOCK_SIZE]; + uint32_t generated = length; + + /* + * In few cases we need to gerate random value before initializing libzrtp engine. + * Following trick makes it possible. + */ + if (!zrtp->rand_initialized) { + if (zrtp_status_ok != zrtp_init_rng(zrtp)) { + return -1; + } + } + + zrtp_mutex_lock(zrtp->rng_protector); + + /* + * Add entropy from system state + * We will include whatever happens to be in the buffer, it can't hurt + */ + if ( 0 > zrtp_entropy_add(zrtp, buffer, length) ) { + zrtp_mutex_unlock(zrtp->rng_protector); + return -1; + } + + /* Copy the zrtp->rand_ctx and finalize it into the md buffer */ + rand_ctx2 = zrtp->rand_ctx; + MD_Final(&rand_ctx2, md); + + zrtp_mutex_unlock(zrtp->rng_protector); + + /* Key an AES context from this buffer */ + zrtp_bg_aes_encrypt_key256(md, &aes_ctx); + + /* Initialize counter, using excess from md if available */ + zrtp_memset (ctr, 0, sizeof(ctr)); + if (MD_DIGEST_LENGTH > (256/8)) { + uint32_t ctrbytes = MD_DIGEST_LENGTH - (256/8); + if (ctrbytes > AES_BLOCK_SIZE) + ctrbytes = AES_BLOCK_SIZE; + zrtp_memcpy(ctr + sizeof(ctr) - ctrbytes, md + (256/8), ctrbytes); + } + + /* Encrypt counter, copy to destination buffer, increment counter */ + while (length) + { + unsigned char *ctrptr; + uint32_t copied; + zrtp_bg_aes_encrypt(ctr, rdata, &aes_ctx); + copied = (sizeof(rdata) < length) ? sizeof(rdata) : length; + zrtp_memcpy (buffer, rdata, copied); + buffer += copied; + length -= copied; + + /* Increment counter */ + ctrptr = ctr + sizeof(ctr) - 1; + while (ctrptr >= ctr) { + if ((*ctrptr-- += 1) != 0) { + break; + } + } + } + + /* Done! Cleanup and exit */ + MD_Cleanup (&rand_ctx2); + MD_Cleanup (md); + MD_Cleanup (&aes_ctx); + MD_Cleanup (ctr); + MD_Cleanup (rdata); + + return generated; +} diff --git a/src/zrtp_srtp_builtin.c b/src/zrtp_srtp_builtin.c new file mode 100644 index 0000000000..1d19e434bd --- /dev/null +++ b/src/zrtp_srtp_builtin.c @@ -0,0 +1,1469 @@ +/* + * 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. + * + * Vitaly Rozhkov + */ + +#include "zrtp.h" + +#define _ZTU_ "zrtp srtp" + +#if (!defined(ZRTP_USE_EXTERN_SRTP)) || (ZRTP_USE_EXTERN_SRTP == 0) + + +/* constants that are used for packet's parsing */ +#define octets_in_rtp_header 12 +#define uint32s_in_rtp_header 3 +#define octets_in_rtcp_header 8 +#define uint32s_in_rtcp_header 2 + + +/* + defines to make work with cipher component little bit easy +*/ +#define zrtp_cipher_init(self) \ + ( ((self)->cipher)->init(((self)->cipher)) ) + +#define zrtp_cipher_start(self, key, extra_data, mode) \ + ( ((self)->cipher)->start(((self)->cipher), (key), (extra_data), (mode)) ) + +#define zrtp_cipher_set_iv(self, iv) \ + ( ((self)->cipher)->set_iv( ((self)->cipher), ((self)->ctx), (iv)) ) + +#define zrtp_cipher_encrypt(self, buf, len) \ + ( ((self)->cipher)->encrypt( ((self)->cipher), ((self)->ctx), (buf), (len)) ) + +#define zrtp_cipher_decrypt(self, buf, len) \ + ( ((self)->cipher)->decrypt( ((self)->cipher), ((self)->ctx), (buf), (len)) ) + +#define zrtp_cipher_self_test(self) \ + ( ((self)->cipher)->self_test(((self)->cipher)) ) + +#define zrtp_cipher_stop(self) \ + ( ((self)->cipher)->stop(((self)->cipher), ((self)->ctx)) ) + +#define zrtp_cipher_free(self) \ + ( ((self)->cipher)->free(((self)->cipher)) ) + + + + +/*===========================================================================*/ +/* Replay protection serve functions set */ +/*===========================================================================*/ + + +/*! \brief Allocates and initializes replay protection context. Initialize + * mutexes and linked lists. + * \return + * - allocated replay protection context + * - NULL if error + */ +/*---------------------------------------------------------------------------*/ +zrtp_rp_ctx_t* rp_init() +{ + zrtp_rp_ctx_t *ctx = zrtp_sys_alloc(sizeof(zrtp_rp_ctx_t)); + if(NULL == ctx){ + return NULL; + } + + if(zrtp_status_ok != zrtp_mutex_init(&ctx->inc_sync)){ + zrtp_sys_free(ctx); + return NULL; + } + + if(zrtp_status_ok != zrtp_mutex_init(&ctx->out_sync)){ + zrtp_mutex_destroy(ctx->inc_sync); + zrtp_sys_free(ctx); + return NULL; + } + + init_mlist(&ctx->inc_head.mlist); + init_mlist(&ctx->out_head.mlist); + + return ctx; +} + + +/*! \brief Deinitializes and deallocates replay protection context. + * \param ctx - replay protection context + * \return + * - zrtp_status_ok + */ +/*---------------------------------------------------------------------------*/ +zrtp_status_t rp_destroy(zrtp_rp_ctx_t *ctx) +{ + mlist_t *pos, *n; + zrtp_rp_node_t *node = NULL; + + /*free all existing replay protection nodes in the incoming list*/ + zrtp_mutex_lock(ctx->inc_sync); + mlist_for_each_safe(pos, n, &ctx->inc_head.mlist){ + node = mlist_get_struct(zrtp_rp_node_t, mlist, pos); + mlist_del(&node->mlist); + zrtp_sys_free(node); + } + zrtp_mutex_unlock(ctx->inc_sync); + + zrtp_mutex_destroy(ctx->inc_sync); + + /*free all existing replay protection nodes in the outgoing list*/ + zrtp_mutex_lock(ctx->out_sync); + mlist_for_each_safe(pos, n, &ctx->out_head.mlist){ + node = mlist_get_struct(zrtp_rp_node_t, mlist, pos); + mlist_del(&node->mlist); + zrtp_sys_free(node); + } + zrtp_mutex_unlock(ctx->out_sync); + + zrtp_mutex_destroy(ctx->out_sync); + + zrtp_sys_free(ctx); + return zrtp_status_ok; +} + + +/*! \brief Finds replay protection node by given ssrc. Which linked list to search is + * determined by the direction param. + * \warning This function doesn't lock the linked list before search and is for internal usage. + * To find necessary replay protection node use get_rp_node() function. + * \param ctx - pointer to replay protection context + * \param direction - defines what list to search. It may have values: + * - RP_INCOMING_DIRECTION + * - RP_OUTGOING_DIRECTION + * \return + * - pointer to found replay protection node + * - NULL if node hasn't been found or if error + */ +/*---------------------------------------------------------------------------*/ +zrtp_rp_node_t *get_rp_node_non_lock( zrtp_rp_ctx_t *ctx, + uint8_t direction, + uint32_t ssrc) +{ + zrtp_rp_node_t *node = NULL; + mlist_t *pos; + mlist_t *head = NULL; + + switch(direction){ + case RP_INCOMING_DIRECTION: + head = &ctx->inc_head.mlist; + break; + case RP_OUTGOING_DIRECTION: + head = &ctx->out_head.mlist; + break; + default: + head = NULL; + break; + }; + + if(NULL != head){ + mlist_for_each(pos, head){ + node = mlist_get_struct(zrtp_rp_node_t, mlist, pos); + if(ssrc == node->ssrc){ + break; + }else{ + node = NULL; + } + } + } + + return node; +} + + +///*! \brief Finds replay protection node by given ssrc. Linked list to search is +// * determined by direction param. This function locks the linked list to +// * ensure exclusive access. +// * +// * \param ctx - pointer to replay protection context +// * \param direction - defines what list to search. It may have values: +// * - RP_INCOMING_DIRECTION +// * - RP_OUTGOING_DIRECTION +// * \param ssrc - value by which search will be made +// * \return +// * - pointer to found replay protection node +// * - NULL if node hasn't been found or if error +// */ +///*---------------------------------------------------------------------------*/ +//zrtp_rp_node_t *get_rp_node(zrtp_rp_ctx_t *ctx, uint8_t direction, uint32_t ssrc) +//{ +// zrtp_rp_node_t *node = NULL; +// zrtp_mutex_t *sync = NULL; +// +// switch(direction){ +// case RP_INCOMING_DIRECTION: +// sync = ctx->inc_sync; +// break; +// case RP_OUTGOING_DIRECTION: +// sync = ctx->out_sync; +// break; +// default: +// sync = NULL; +// break; +// }; +// +// if(NULL != sync){ +// zrtp_mutex_lock(sync); +// node = get_rp_node_non_lock(ctx, direction, ssrc); +// zrtp_mutex_unlock(sync); +// } +// +// return node; +//} + +/*! \brief Allocates new replay protection node for given direction and ssrc and adds it into + * appropriate linked list. + * \warning This function is for internal usage. Use add_rp_node() and add_rp_node_unique(). + * \param srtp_ctx - pointer to SRTP ctx related with created node. Used for removing node on SRTP session destruction. + * \param ctx - pointer to replay protection context + * \param direction - defines in which list newly created node will be inserted. It may have values: + * - RP_INCOMING_DIRECTION + * - RP_OUTGOING_DIRECTION + * \param ssrc - newly created replay protection node key value. + * \param is_unique - defines what should be returned when replay protection node + * with given direction and ssrc values already exists: + * - pointer to existing node if is_unique == 0 + * - NULL if is_unique == 1 + * \return + * - pointer to newly created replay protection node + * - pointer to existing replay protection node + * - NULL if is_unique == 1 and needed replay protection node already exists or if error + */ +/*---------------------------------------------------------------------------*/ +zrtp_rp_node_t *add_rp_node_ex( zrtp_srtp_ctx_t *srtp_ctx, + zrtp_rp_ctx_t *ctx, + uint8_t direction, + uint32_t ssrc, + uint8_t is_unique) +{ + zrtp_rp_node_t *node = NULL; + zrtp_mutex_t *sync = NULL; + mlist_t *head = NULL; + + switch(direction){ + case RP_INCOMING_DIRECTION: + sync = ctx->inc_sync; + head = &ctx->inc_head.mlist; + break; + case RP_OUTGOING_DIRECTION: + sync = ctx->out_sync; + head = &ctx->out_head.mlist; + break; + default: + sync = NULL; + head = NULL; + break; + }; + + if(NULL != sync && NULL != head){ + zrtp_mutex_lock(sync); + do{ + node = get_rp_node_non_lock(ctx, direction, ssrc); + + /*create new node if not found*/ + if(NULL == node){ + node = zrtp_sys_alloc(sizeof(zrtp_rp_node_t)); + if(NULL == node){ + break; + } + /*clean sliding window and on-top sequence number value*/ + zrtp_memset(node, 0, sizeof(zrtp_rp_node_t)); + node->ssrc = ssrc; + node->srtp_ctx = srtp_ctx; + mlist_add_tail(head, &node->mlist); +#if ZRTP_DEBUG_SRTP_KEYS + ZRTP_LOG(3,(_ZTU_,"\tadd %s rp node. ssrc[%u] srtp_ctx[0x%08x]", + direction==RP_INCOMING_DIRECTION?"incoming":"outgoing\n", + zrtp_ntoh32(node->ssrc), node->srtp_ctx)); +#endif + }else if(is_unique){ + // ???: why do we need unique mode at all? + node = NULL; + } + + }while(0); + zrtp_mutex_unlock(sync); + } + + return node; +} + +/*! \brief Allocates new replay protection node for given direction and ssrc and adds it into + * appropriate linked list. This function is based on add_rp_node_ex(). + * \param srtp_ctx - pointer to SRTP ctx related with created node. Used for removing node on SRTP session destruction. + * \param ctx - pointer to replay protection context + * \param direction - defines in which list newly created node will be inserted. It may have values: + * - RP_INCOMING_DIRECTION + * - RP_OUTGOING_DIRECTION + * \param ssrc - newly created replay protection node key value. + * \return + * - pointer to newly created replay protection node + * - pointer to existing replay protection node + * - NULL if error + */ +zrtp_rp_node_t *add_rp_node(zrtp_srtp_ctx_t *srtp_ctx, zrtp_rp_ctx_t *ctx, uint8_t direction, uint32_t ssrc){ + /*not-unique mode*/ + // ???: why do we need unique mode at all? + return add_rp_node_ex(srtp_ctx, ctx, direction, ssrc, 0); +} + +///*! \brief Allocates new replay protection node for given direction and ssrc and adds it into +// * appropriate linked list. This function is based on add_rp_node_ex(). +// * \param srtp_ctx - pointer to SRTP ctx related with created node. Used for removing node on SRTP session destruction. +// * \param ctx - pointer to replay protection context +// * \param direction - defines in which list newly created node will be inserted. It may have values: +// * - RP_INCOMING_DIRECTION +// * - RP_OUTGOING_DIRECTION +// * \param ssrc - newly created replay protection node key value. +// * \return +// * - pointer to newly created replay protection node +// * - NULL if error or if needed node already exists +// */ +//zrtp_rp_node_t *add_rp_node_unique(zrtp_srtp_ctx_t *srtp_ctx, zrtp_rp_ctx_t *ctx, uint8_t direction, uint32_t ssrc){ +// /*unique mode*/ +// return add_rp_node_ex(srtp_ctx, ctx, direction, ssrc, 1); +//} + +/*! \brief Removes replay protection node with given ssrc from linked list defined by direction value. + * \param ctx - pointer to replay protection context + * \param direction - defines from which list replay protection node will be removed. It may have values: + * - RP_INCOMING_DIRECTION + * - RP_OUTGOING_DIRECTION + * \param ssrc - key value of replay protection node to remove + * \return + * - zrtp_status_ok if replay protection node has been removed successfully + * - zrtp_status_fail if node hasn't been found + */ +/*---------------------------------------------------------------------------*/ +zrtp_status_t remove_rp_node(zrtp_rp_ctx_t *ctx, uint8_t direction, uint32_t ssrc){ + zrtp_rp_node_t *node = NULL; + zrtp_mutex_t *sync = NULL; + zrtp_status_t res = zrtp_status_fail; + + switch(direction){ + case RP_INCOMING_DIRECTION: + sync = ctx->inc_sync; + break; + case RP_OUTGOING_DIRECTION: + sync = ctx->out_sync; + break; + default: + sync = NULL; + break; + }; + + if(NULL != sync){ + zrtp_mutex_lock(sync); + node = get_rp_node_non_lock(ctx, direction, ssrc); + if(NULL != node){ + mlist_del(&node->mlist); + zrtp_sys_free(node); + res = zrtp_status_ok; + } + zrtp_mutex_unlock(sync); + } + + return res; +} + + +zrtp_status_t remove_rp_nodes_by_srtp_ctx(zrtp_srtp_ctx_t *srtp_ctx, zrtp_rp_ctx_t *ctx){ + zrtp_status_t res = zrtp_status_ok; + zrtp_rp_node_t *node = NULL; + mlist_t *pos, *n; + + if((NULL == srtp_ctx) || (NULL == ctx)){ + return zrtp_status_bad_param; + } + + /* Walk over incoming nodes list */ + zrtp_mutex_lock(ctx->inc_sync); + mlist_for_each_safe(pos, n, &ctx->inc_head.mlist){ + node = mlist_get_struct(zrtp_rp_node_t, mlist, pos); + if((NULL != node->srtp_ctx) && (node->srtp_ctx == srtp_ctx)){ +#if ZRTP_DEBUG_SRTP_KEYS + ZRTP_LOG(3,(_ZTU_,"\tremove incoming rp node. ssrc[%u] srtp_ctx[0x%08x]\n", + zrtp_ntoh32(node->ssrc), node->srtp_ctx)); +#endif + mlist_del(&node->mlist); + zrtp_sys_free(node); + } + } + zrtp_mutex_unlock(ctx->inc_sync); + + /* Walk over outgoing nodes list */ + zrtp_mutex_lock(ctx->out_sync); + mlist_for_each_safe(pos, n, &ctx->out_head.mlist){ + node = mlist_get_struct(zrtp_rp_node_t, mlist, pos); + if((NULL != node->srtp_ctx) && (node->srtp_ctx == srtp_ctx)){ +#if ZRTP_DEBUG_SRTP_KEYS + ZRTP_LOG(3,(_ZTU_,"\tremove outgoing rp node. ssrc[%u] srtp_ctx[0x%08x]\n", + zrtp_ntoh32(node->ssrc), node->srtp_ctx)); +#endif + mlist_del(&node->mlist); + zrtp_sys_free(node); + } + } + zrtp_mutex_unlock(ctx->out_sync); + + return res; +} + + +/*===========================================================================*/ +/* Replay protection mechanism functions set */ +/*===========================================================================*/ + + +/*! \brief This function is used for RTCP replay protection to generate next sequence number + * of outgoing RTCP packet. If the sequence number is too large it returns zrtp_status_key_expired. + * See RFC3711 for more details. + * \param srtp_rp - pointer to replay protection engine data + * \return + * - zrtp_status_key_expired if next sequence number is too large + * - zrtp_status_ok otherwise + */ +zrtp_status_t zrtp_srtp_rp_increment(zrtp_srtp_rp_t *srtp_rp){ + + if(srtp_rp->seq++ > 0x7fffffff){ + return zrtp_status_key_expired; + }else{ + return zrtp_status_ok; + } +} + +/*! \brief Returns current on-top sequence number. This function is used for RTCP + * replay protection. + * \param srtp_rp - pointer to replay protection engine data + * \return current on-top sequence number + */ +uint32_t zrtp_srtp_rp_get_value(zrtp_srtp_rp_t *srtp_rp){ + return srtp_rp->seq; +} + + +/*! \brief This function checks packet sequence number position relative to + * sliding window current position and makes the decision to accept or discard packet. + * \param srtp_rp - pointer to replay protection engine data + * \param packet - pointer to packet structure + * \return + * - zrtp_status_ok if packet must be accepted + * - zrtp_status_old_pkt if packet sequence number is lower than lowest sequence number + * which can be into the sliding window at the current time. In this case packet must be discarded. + * - zrtp_status_fail if packet must be discarded + */ +/*---------------------------------------------------------------------------*/ +zrtp_status_t zrtp_srtp_rp_check(zrtp_srtp_rp_t *srtp_rp, zrtp_rtp_info_t *packet) +{ + int32_t delta = packet->seq - srtp_rp->seq; + if(delta > 0){ + /*if delta is positive, it's good*/ + return zrtp_status_ok; + }else if(ZRTP_SRTP_WINDOW_WIDTH-1 + delta < 0){ + /*if delta is lower than the bitmask, it's bad*/ + return zrtp_status_old_pkt; + }else{ + if(1 == zrtp_bitmap_get_bit(srtp_rp->window, ZRTP_SRTP_WINDOW_WIDTH-1 + delta)){ + /*delta is within the window, so check the bitmask*/ + return zrtp_status_fail; + } + } + return zrtp_status_ok; +} + +/*! \brief This function updates the sliding window state by setting appropriate bit and + * shifting the sliding window if needed. + * \param srtp_rp - pointer to replay protection engine data + * \param packet - pointer to packet structure + * \return + * - zrtp_status_ok + */ +/*---------------------------------------------------------------------------*/ +zrtp_status_t zrtp_srtp_rp_add(zrtp_srtp_rp_t *srtp_rp, zrtp_rtp_info_t *packet) +{ + int32_t delta = packet->seq - srtp_rp->seq; + if(delta > 0){ + /* packet sequence nubmer is larger than current on-top sequence number. + shift the window, set top bit and update on-top sequence number value */ + srtp_rp->seq = packet->seq; + zrtp_bitmap_left_shift(srtp_rp->window, ZRTP_SRTP_WINDOW_WIDTH_BYTES, delta); + zrtp_bitmap_set_bit(srtp_rp->window, ZRTP_SRTP_WINDOW_WIDTH-1); + }else + + /* commented by book, 19.07.07: + we need not consider case when delta == 0 + if(0 == delta){ + zrtp_bitmap_set_bit(srtp_rp->window, ZRTP_SRTP_WINDOW_WIDTH-1); + }else*/ + + { + /* + packet sequence number is into the sliding window. + set appropriate bit + */ + zrtp_bitmap_set_bit(srtp_rp->window, ZRTP_SRTP_WINDOW_WIDTH-1 + delta); + } + + return zrtp_status_ok; +} + + +/*===========================================================================*/ +/* Key derivation mechanism functions set */ +/*===========================================================================*/ + + +/*! \brief This function allocates key derivation context and initializes it with + * given master key, master salt and cipher. + * \param cipher - pointer to cipher that is used for key derivation + * \param key - pointer to master key + * \param salt - pointer to master salt + * \return + * - allocated key derivation context + * - NULL if error + */ +/*---------------------------------------------------------------------------*/ +zrtp_dk_ctx *zrtp_dk_init( zrtp_cipher_t *cipher, + zrtp_stringn_t *key, + zrtp_stringn_t *salt) +{ + zrtp_dk_ctx *ctx = NULL; +#if ZRTP_DEBUG_SRTP_KEYS + ZRTP_LOG(3,(_ZTU_,"\tzrtp_dk_init():\n")); + ZRTP_LOG(3,(_ZTU_,"\tcipher ID[%i]\n", cipher->base.id)); +#endif + do{ + ctx = zrtp_sys_alloc(sizeof(zrtp_dk_ctx)); + if(NULL == ctx){ + break; + } + + ctx->ctx = cipher->start(cipher, key->buffer, salt->buffer, ZRTP_CIPHER_MODE_CTR); + if(NULL == ctx->ctx){ + zrtp_sys_free(ctx); + ctx = NULL; + break; + } + + ctx->cipher = cipher; + }while(0); + + return ctx; +} + +/*! \brief This function derives key for different purposes like SRTP encryption, + * SRTP message authentication, etc. See RFC3711, "4.3. Key Derivation" for more details. + * \warning This function may change length field value in the result_key variable when + * length is larger than max_length field value. + * \param ctx - pointer to key derivation context + * \param label - defines purpose of key to derive + * \param result_key - out parameter. It contains derived key on success. + * \return + * - actually derived key length + * - -1 if error + */ +/*---------------------------------------------------------------------------*/ +uint16_t zrtp_derive_key( zrtp_dk_ctx *ctx, + zrtp_srtp_prf_label label, + zrtp_stringn_t *result_key ) +{ + zrtp_v128_t nonce; + uint16_t length; +#if ZRTP_DEBUG_SRTP_KEYS + char buffer[256]; + ZRTP_LOG(3,(_ZTU_,"\tzrtp_derive_key():\n")); +#endif + + /* set eigth octet of nonce to