pax_global_header00006660000000000000000000000064131341123530014506gustar00rootroot0000000000000052 comment=721fc7700f4dc55fb7f975b52f2c3204f40c2844 bzrtp-1.0.6/000077500000000000000000000000001313411235300126535ustar00rootroot00000000000000bzrtp-1.0.6/.gitignore000066400000000000000000000004651313411235300146500ustar00rootroot00000000000000Makefile Makefile.in aclocal.m4 autom4te.cache compile config.guess config.h config.h.in config.log config.status config.sub configure depcomp install-sh intltool-extract intltool-merge intltool-update libtool ltmain.sh missing mkinstalldirs stamp-h1 *.o *.exe *.zip *~ *.lo *.la *.swp .deps .libs INSTALL m4 bzrtp-1.0.6/AUTHORS000066400000000000000000000000751313411235300137250ustar00rootroot00000000000000Copyright 2014 Belledonne Communications SARL. Johan Pascal bzrtp-1.0.6/Android.mk000066400000000000000000000014351313411235300145670ustar00rootroot00000000000000LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_CFLAGS += -DHAVE_LIBXML2 LOCAL_MODULE := libbzrtp LOCAL_ARM_MODE := arm LOCAL_SRC_FILES = \ src/bzrtp.c \ src/cryptoUtils.c \ src/packetParser.c \ src/stateMachine.c \ src/zidCache.c \ src/pgpwords.c LOCAL_STATIC_LIBRARIES += liblpxml2 LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/include \ $(LOCAL_PATH)/../externals/libxml2/include \ $(LOCAL_PATH)/../externals/build/libxml2 ifeq ($(BUILD_BCTOOLBOX_MBEDTLS),1) LOCAL_SRC_FILES += src/cryptoMbedtls.c LOCAL_STATIC_LIBRARIES += mbedtls LOCAL_C_INCLUDES += $(LOCAL_PATH)/../externals/mbedtls/include else LOCAL_SRC_FILES += src/cryptoPolarssl.c LOCAL_STATIC_LIBRARIES += polarssl LOCAL_C_INCLUDES += $(LOCAL_PATH)/../externals/polarssl/include endif include $(BUILD_STATIC_LIBRARY) bzrtp-1.0.6/CMakeLists.txt000066400000000000000000000113171313411235300154160ustar00rootroot00000000000000############################################################################ # CMakeLists.txt # Copyright (C) 2014 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################################################ cmake_minimum_required(VERSION 3.0) project(bzrtp VERSION 1.0.6 LANGUAGES C CXX) option(ENABLE_SHARED "Build shared library." YES) option(ENABLE_STATIC "Build static library." YES) option(ENABLE_ZIDCACHE "Turn on compilation of ZID cache, request sqlite" YES) option(ENABLE_STRICT "Build with strict compile options." YES) option(ENABLE_TESTS "Enable compilation of unit tests." NO) if(NOT CMAKE_INSTALL_RPATH AND CMAKE_INSTALL_PREFIX) set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}) message(STATUS "Setting install rpath to ${CMAKE_INSTALL_RPATH}") endif() list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") set(MSVC_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include/MSVC") if(MSVC) list(APPEND CMAKE_REQUIRED_INCLUDES ${MSVC_INCLUDE_DIR}) endif() include(GNUInstallDirs) include(CheckLibraryExists) check_library_exists("m" "sqrt" "" HAVE_SQRT) if(LINPHONE_BUILDER_GROUP_EXTERNAL_SOURCE_PATH_BUILDERS) set(BcToolbox_FIND_COMPONENTS tester) include("${EP_bctoolbox_CONFIG_DIR}/BcToolboxConfig.cmake") else() find_package(BcToolbox 0.0.3 REQUIRED OPTIONAL_COMPONENTS tester) endif() if(ENABLE_ZIDCACHE) find_package(Sqlite3 REQUIRED) # Also check if we have libxml2, as we need it for migration purpose find_package(XML2) endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/config.h PROPERTIES GENERATED ON) add_definitions("-DHAVE_CONFIG_H") set(STRICT_OPTIONS_CPP ) if(NOT MSVC) list(APPEND STRICT_OPTIONS_CPP "-Wall") if(CMAKE_C_COMPILER_ID STREQUAL "Clang") list(APPEND STRICT_OPTIONS_CPP "-Qunused-arguments") endif() if(ENABLE_STRICT) list(APPEND STRICT_OPTIONS_CPP "-Werror" "-Wextra" "-Wno-unused-parameter" "-Wno-missing-field-initializers") endif() endif() if(STRICT_OPTIONS_CPP) list(REMOVE_DUPLICATES STRICT_OPTIONS_CPP) string(REPLACE ";" " " STRICT_OPTIONS_CPP "${STRICT_OPTIONS_CPP}") endif() set(BZRTP_CPPFLAGS ${BCTOOLBOX_CPPFLAGS}) if(ENABLE_STATIC) list(APPEND BZRTP_CPPFLAGS "-DBZRTP_STATIC") endif() if(BZRTP_CPPFLAGS) list(REMOVE_DUPLICATES BZRTP_CPPFLAGS) add_definitions(${BZRTP_CPPFLAGS}) endif() include_directories( include ${CMAKE_CURRENT_BINARY_DIR} ) if(MSVC) include_directories(${MSVC_INCLUDE_DIR}) endif() if(ENABLE_ZIDCACHE) add_definitions("-DZIDCACHE_ENABLED") if(XML2_FOUND) add_definitions("-DHAVE_LIBXML2") endif() endif() if(LINPHONE_BUILDER_GROUP_EXTERNAL_SOURCE_PATH_BUILDERS) set(EXPORT_TARGETS_NAME "LinphoneBuilder") else() set(EXPORT_TARGETS_NAME "BZRTP") endif() add_subdirectory(include) add_subdirectory(src) if(ENABLE_TESTS AND BCTOOLBOX_TESTER_FOUND) enable_testing() add_subdirectory(test) endif() include(CMakePackageConfigHelpers) write_basic_package_version_file( "${CMAKE_CURRENT_BINARY_DIR}/BZRTPConfigVersion.cmake" VERSION ${PROJECT_VERSION} COMPATIBILITY AnyNewerVersion ) export(EXPORT ${EXPORT_TARGETS_NAME}Targets FILE "${CMAKE_CURRENT_BINARY_DIR}/BZRTPTargets.cmake" ) configure_file(cmake/BZRTPConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/BZRTPConfig.cmake" @ONLY ) set(CONFIG_PACKAGE_LOCATION "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/cmake") install(EXPORT ${EXPORT_TARGETS_NAME}Targets FILE BZRTPTargets.cmake DESTINATION ${CONFIG_PACKAGE_LOCATION} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/BZRTPConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/BZRTPConfigVersion.cmake" DESTINATION ${CONFIG_PACKAGE_LOCATION} ) # CPack settings set(CPACK_PACKAGE_NAME "bzrtp") set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION}) set(CPACK_SOURCE_GENERATOR "TGZ") set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") set(CPACK_SOURCE_IGNORE_FILES "^${CMAKE_BINARY_DIR}" "/\\\\..+" ) include(CPack) bzrtp-1.0.6/COPYING000066400000000000000000000431101313411235300137050ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. bzrtp-1.0.6/ChangeLog000066400000000000000000000000001313411235300144130ustar00rootroot00000000000000bzrtp-1.0.6/Makefile.am000066400000000000000000000005211313411235300147050ustar00rootroot00000000000000ACLOCAL_AMFLAGS = -I m4 SUBDIRS = src include test EXTRA_DIST= \ CMakeLists.txt \ cmake/BZRTPConfig.cmake.in \ cmake/FindXML2.cmake \ config.h.cmake \ include/CMakeLists.txt \ src/CMakeLists.txt \ test/CMakeLists.txt \ README.md test: cd test && $(MAKE) test pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libbzrtp.pc bzrtp-1.0.6/NEWS000066400000000000000000000005301313411235300133500ustar00rootroot00000000000000bzrtp-1.0.6 - July 20th, 2017 * bug fixes bzrtp-1.0.5 - February 23th, 2017 * bug fixes bzrtp-1.0.4 - August 8th, 2016 * build system fixes * security fix bzrtp-1.0.3 - November 2nd, 2015 * build system fixes bzrtp-1.0.2 - Thursday, May 7th 2015 * bug fixes bzrtp-1.0.0 - Thursday, March 5th 2015 * first official release of bzrtp bzrtp-1.0.6/README.md000066400000000000000000000040641313411235300141360ustar00rootroot00000000000000BZRTP ===== What's BZRTP ------------ BZRTP is an opensource implementation of ZRTP keys exchange protocol. The library written in C 89 is fully portable and can be executed on many platforms including both ARM processor and x86. Licensing: The source code is licensed under GPLv2. Compatibility with RFC6189 - ZRTP: Media Path Key Agreement for Unicast Secure RTP ---------------------------------------------------------------------------------- ### Mandatory but NOT implemented * Sas Relay mechanism (section 7.3) * Error message generation, emission or reception(which doesn't imply any security problem, they are mostly for debug purpose) ### Optional and implementd * multistream mode * cacheless implementation * zrtp-hash attribute in SDP ### Optional and NOT implemented * Go Clear/Clear ACK messages * SAS signing ### Supported Algorithms * Hash : SHA-256 * Cipher : AES-128, AES-256 * SAS rendering: B32, B256(PGP word list) * Auth Tag : HS32, HS80 * Key Agreement : DH-2048, DH-3072 Dependencies ------------ - *bctoolbox[1]*: portability layer and crypto function abstraction Build BZRTP ----------- cmake . -DCMAKE_INSTALL_PREFIX= -DCMAKE_PREFIX_PATH= make make install Build options ------------- * `CMAKE_INSTALL_PREFIX=` : install prefix * `CMAKE_PREFIX_PATH=` : column-separated list of prefixes where to search for dependencies * `ENABLE_SHARED=NO` : do not build the shared library * `ENABLE_STATIC=NO` : do not build the static library * `ENABLE_STRICT=NO` : build without the strict compilation flags * `ENABLE_TESTS=YES` : build non-regression tests Notes for packagers ------------------- Our CMake scripts may automatically add some paths into research paths of generated binaries. To ensure that the installed binaries are striped of any rpath, use `-DCMAKE_SKIP_INSTALL_RPATH=ON` while you invoke cmake. ---------------------------------- * [1] git://git.linphone.org/bctoolbox.git or bzrtp-1.0.6/autogen.sh000077500000000000000000000013551313411235300146600ustar00rootroot00000000000000#!/bin/sh srcdir=`dirname $0` test -z "$srcdir" && srcdir=. THEDIR=`pwd` cd $srcdir #AM_VERSION="1.11" if ! type aclocal-$AM_VERSION 1>/dev/null 2>&1; then AUTOMAKE=automake ACLOCAL=aclocal else ACLOCAL=aclocal-${AM_VERSION} AUTOMAKE=automake-${AM_VERSION} fi if test -f /opt/local/bin/glibtoolize ; then # darwin LIBTOOLIZE=/opt/local/bin/glibtoolize else LIBTOOLIZE=libtoolize fi if test -d /opt/local/share/aclocal ; then ACLOCAL_ARGS="-I /opt/local/share/aclocal" fi if test -d /share/aclocal ; then ACLOCAL_ARGS="-I /share/aclocal" fi echo "Generating build scripts for BZRtp: ZRTP engine" set -x $LIBTOOLIZE --copy --force $ACLOCAL $ACLOCAL_ARGS #autoheader $AUTOMAKE --force-missing --add-missing --copy autoconf cd $THEDIR bzrtp-1.0.6/cmake/000077500000000000000000000000001313411235300137335ustar00rootroot00000000000000bzrtp-1.0.6/cmake/BZRTPConfig.cmake.in000066400000000000000000000045221313411235300173740ustar00rootroot00000000000000############################################################################ # BZRTPConfig.cmake # Copyright (C) 2015 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################################################ # # Config file for the bzrtp package. # It defines the following variables: # # BZRTP_FOUND - system has bzrtp # BZRTP_INCLUDE_DIRS - the bzrtp include directory # BZRTP_LIBRARIES - The libraries needed to use bzrtp # BZRTP_CPPFLAGS - The compilation flags needed to use bzrtp if(NOT LINPHONE_BUILDER_GROUP_EXTERNAL_SOURCE_PATH_BUILDERS) include("${CMAKE_CURRENT_LIST_DIR}/BZRTPTargets.cmake") endif() if(@ENABLE_SHARED@) set(BZRTP_TARGETNAME bzrtp) set(BZRTP_LIBRARIES ${BZRTP_TARGETNAME}) else() set(BZRTP_TARGETNAME bzrtp-static) if(TARGET ${BZRTP_TARGETNAME}) if(LINPHONE_BUILDER_GROUP_EXTERNAL_SOURCE_PATH_BUILDERS) set(BZRTP_LIBRARIES ${BZRTP_TARGETNAME}) else() get_target_property(BZRTP_LIBRARIES ${BZRTP_TARGETNAME} LOCATION) endif() get_target_property(BZRTP_LINK_LIBRARIES ${BZRTP_TARGETNAME} INTERFACE_LINK_LIBRARIES) if(BZRTP_LINK_LIBRARIES) list(APPEND BZRTP_LIBRARIES ${BZRTP_LINK_LIBRARIES}) endif() endif() endif() get_target_property(BZRTP_INCLUDE_DIRS ${BZRTP_TARGETNAME} INTERFACE_INCLUDE_DIRECTORIES) if(LINPHONE_BUILDER_GROUP_EXTERNAL_SOURCE_PATH_BUILDERS) list(INSERT BZRTP_INCLUDE_DIRS 0 "${EP_bzrtp_INCLUDE_DIR}") else() list(INSERT BZRTP_INCLUDE_DIRS 0 "@CMAKE_INSTALL_FULL_INCLUDEDIR@") endif() list(REMOVE_DUPLICATES BZRTP_INCLUDE_DIRS) set(BZRTP_CPPFLAGS @BZRTP_CPPFLAGS@) set(BZRTP_FOUND 1) bzrtp-1.0.6/cmake/FindSqlite3.cmake000066400000000000000000000034531313411235300170670ustar00rootroot00000000000000############################################################################ # FindSqlite3.cmake # Copyright (C) 2014 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################################################ # # - Find the sqlite3 include file and library # # SQLITE3_FOUND - system has sqlite3 # SQLITE3_INCLUDE_DIRS - the sqlite3 include directory # SQLITE3_LIBRARIES - The libraries needed to use sqlite3 if(APPLE AND NOT IOS) set(SQLITE3_HINTS "/usr") endif() if(SQLITE3_HINTS) set(SQLITE3_LIBRARIES_HINTS "${SQLITE3_HINTS}/lib") endif() find_path(SQLITE3_INCLUDE_DIRS NAMES sqlite3.h HINTS "${SQLITE3_HINTS}" PATH_SUFFIXES include ) if(SQLITE3_INCLUDE_DIRS) set(HAVE_SQLITE3_H 1) endif() find_library(SQLITE3_LIBRARIES NAMES sqlite3 HINTS "${SQLITE3_LIBRARIES_HINTS}" ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Sqlite3 DEFAULT_MSG SQLITE3_INCLUDE_DIRS SQLITE3_LIBRARIES HAVE_SQLITE3_H ) mark_as_advanced(SQLITE3_INCLUDE_DIRS SQLITE3_LIBRARIES HAVE_SQLITE3_H) bzrtp-1.0.6/cmake/FindXML2.cmake000066400000000000000000000033541313411235300162650ustar00rootroot00000000000000############################################################################ # FindXML2.txt # Copyright (C) 2015 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################################################ # # - Find the libxml2 include file and library # # XML2_FOUND - system has libxml2 # XML2_INCLUDE_DIRS - the libxml2 include directory # XML2_LIBRARIES - The libraries needed to use libxml2 if(APPLE AND NOT IOS) set(XML2_HINTS "/usr") endif() if(XML2_HINTS) set(XML2_LIBRARIES_HINTS "${XML2_HINTS}/lib") endif() find_path(XML2_INCLUDE_DIRS NAMES libxml/xmlreader.h HINTS "${XML2_HINTS}" PATH_SUFFIXES include/libxml2 ) if(XML2_INCLUDE_DIRS) set(HAVE_LIBXML_XMLREADER_H 1) endif() find_library(XML2_LIBRARIES NAMES xml2 HINTS "${XML2_LIBRARIES_HINTS}" ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(XML2 DEFAULT_MSG XML2_INCLUDE_DIRS XML2_LIBRARIES ) mark_as_advanced(XML2_INCLUDE_DIRS XML2_LIBRARIES) bzrtp-1.0.6/config.h.cmake000066400000000000000000000022261313411235300153520ustar00rootroot00000000000000/*************************************************************************** * config.h.cmake * Copyright (C) 2014 Belledonne Communications, Grenoble France * **************************************************************************** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ #cmakedefine HAVE_CU_ADD_SUITE #cmakedefine HAVE_CU_GET_SUITE #cmakedefine HAVE_CU_CURSES #cmakedefine ZIDCACHE_ENABLED #cmakedefine HAVE_LIBXML2 bzrtp-1.0.6/configure.ac000066400000000000000000000047501313411235300151470ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_INIT([bzrtp],[1.0.5]) AC_PREREQ(2.63) AC_CONFIG_SRCDIR([src/bzrtp.c]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE([tar-ustar --warnings=no-portability foreign]) AC_PROG_CC(["xcrun clang" gcc]) LT_INIT(win32-dll shared disable-static) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AC_ARG_ENABLE(strict, [ --enable-strict Enable error on compilation warning [default=yes]], [wall_werror=$enableval], [wall_werror=yes] ) # configure option to disable the tests PKG_CHECK_MODULES(BCTOOLBOXTESTER, bctoolbox-tester, [found_pkg_config_bctoolboxtester=yes],[found_pkg_config_bctoolboxtester=no]) if test "$found_pkg_config_bctoolboxtester" = "no" ; then AC_MSG_WARN([Could not find bctoolbox-tester wrapper, tests are not compiled.]) fi dnl check bctoolbox PKG_CHECK_MODULES(BCTOOLBOX, [bctoolbox] ,[bctoolbox_found=yes] ,foo=bar) if test "$bctoolbox_found" != "yes" ; then AC_MSG_ERROR([bctoolbox not found, aborting. ]) fi dnl check for sqlite PKG_CHECK_MODULES(SQLITE3,[sqlite3 >= 3.6.0],[found_sqlite=yes],[found_sqlite=no]) if test "$found_sqlite" != "yes" ; then AC_MSG_WARN([sqlite3 not found. Disabling cache.]) else AC_DEFINE(ZIDCACHE_ENABLED,1,[defined when libxml2 is available]) fi dnl check libxml2 PKG_CHECK_MODULES(LIBXML2, [libxml-2.0] ,[libxml2_found=yes] ,foo=bar) if test "$libxml2_found$found_sqlite" != "yesyes" ; then AC_MSG_WARN([libxml2 not found. Disabling cache.]) else AC_DEFINE(HAVE_LIBXML2,1,[defined when libxml2 is available]) fi AC_ARG_ENABLE(tests, [AS_HELP_STRING([--disable-tests], [Disable compilation of tests])], [case "${enableval}" in yes) tests_enabled=true ;; no) tests_enabled=false ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-tests) ;; esac], [tests_enabled=yes] ) AM_CONDITIONAL(ENABLE_TESTS, test x$tests_enabled = xyes && test x$found_pkg_config_bctoolboxtester = xyes) CFLAGS="$CFLAGS -Wall" case $CC in *clang*) CFLAGS="$CFLAGS -Qunused-arguments" ;; esac if test $GCC = yes && test $wall_werror = yes; then CFLAGS="$CFLAGS -Werror -Wextra -Wno-unused-parameter -Wno-missing-field-initializers " fi # Create the following files from their .in counterparts AC_CONFIG_FILES([ Makefile src/Makefile include/Makefile include/bzrtp/Makefile test/Makefile libbzrtp.pc ]) AC_OUTPUT bzrtp-1.0.6/include/000077500000000000000000000000001313411235300142765ustar00rootroot00000000000000bzrtp-1.0.6/include/CMakeLists.txt000066400000000000000000000022111313411235300170320ustar00rootroot00000000000000############################################################################ # CMakeLists.txt # Copyright (C) 2014 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################################################ install(FILES bzrtp/bzrtp.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/bzrtp PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ ) bzrtp-1.0.6/include/MSVC/000077500000000000000000000000001313411235300150465ustar00rootroot00000000000000bzrtp-1.0.6/include/MSVC/stdint.h000066400000000000000000000170601313411235300165300ustar00rootroot00000000000000// ISO C9x compliant stdint.h for Microsoft Visual Studio // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 // // Copyright (c) 2006-2008 Alexander Chemeris // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. The name of the author may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // /////////////////////////////////////////////////////////////////////////////// #ifndef _MSC_VER // [ #error "Use this header only with Microsoft Visual C++ compilers!" #endif // _MSC_VER ] #ifndef _MSC_STDINT_H_ // [ #define _MSC_STDINT_H_ #if _MSC_VER > 1000 #pragma once #endif #include // For Visual Studio 6 in C++ mode and for many Visual Studio versions when // compiling for ARM we should wrap include with 'extern "C++" {}' // or compiler give many errors like this: // error C2733: second C linkage of overloaded function 'wmemchr' not allowed #ifdef __cplusplus extern "C" { #endif # include #ifdef __cplusplus } #endif // Define _W64 macros to mark types changing their size, like intptr_t. #ifndef _W64 # if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 # define _W64 __w64 # else # define _W64 # endif #endif // 7.18.1 Integer types // 7.18.1.1 Exact-width integer types // Visual Studio 6 and Embedded Visual C++ 4 doesn't // realize that, e.g. char has the same size as __int8 // so we give up on __intX for them. #if (_MSC_VER < 1300) typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #else typedef signed __int8 int8_t; typedef signed __int16 int16_t; typedef signed __int32 int32_t; typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; #endif typedef signed __int64 int64_t; typedef unsigned __int64 uint64_t; // 7.18.1.2 Minimum-width integer types typedef int8_t int_least8_t; typedef int16_t int_least16_t; typedef int32_t int_least32_t; typedef int64_t int_least64_t; typedef uint8_t uint_least8_t; typedef uint16_t uint_least16_t; typedef uint32_t uint_least32_t; typedef uint64_t uint_least64_t; // 7.18.1.3 Fastest minimum-width integer types typedef int8_t int_fast8_t; typedef int16_t int_fast16_t; typedef int32_t int_fast32_t; typedef int64_t int_fast64_t; typedef uint8_t uint_fast8_t; typedef uint16_t uint_fast16_t; typedef uint32_t uint_fast32_t; typedef uint64_t uint_fast64_t; // 7.18.1.4 Integer types capable of holding object pointers #ifdef _WIN64 // [ typedef signed __int64 intptr_t; typedef unsigned __int64 uintptr_t; #else // _WIN64 ][ typedef _W64 signed int intptr_t; typedef _W64 unsigned int uintptr_t; #endif // _WIN64 ] // 7.18.1.5 Greatest-width integer types typedef int64_t intmax_t; typedef uint64_t uintmax_t; // 7.18.2 Limits of specified-width integer types #if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 // 7.18.2.1 Limits of exact-width integer types #define INT8_MIN ((int8_t)_I8_MIN) #define INT8_MAX _I8_MAX #define INT16_MIN ((int16_t)_I16_MIN) #define INT16_MAX _I16_MAX #define INT32_MIN ((int32_t)_I32_MIN) #define INT32_MAX _I32_MAX #define INT64_MIN ((int64_t)_I64_MIN) #define INT64_MAX _I64_MAX #define UINT8_MAX _UI8_MAX #define UINT16_MAX _UI16_MAX #define UINT32_MAX _UI32_MAX #define UINT64_MAX _UI64_MAX // 7.18.2.2 Limits of minimum-width integer types #define INT_LEAST8_MIN INT8_MIN #define INT_LEAST8_MAX INT8_MAX #define INT_LEAST16_MIN INT16_MIN #define INT_LEAST16_MAX INT16_MAX #define INT_LEAST32_MIN INT32_MIN #define INT_LEAST32_MAX INT32_MAX #define INT_LEAST64_MIN INT64_MIN #define INT_LEAST64_MAX INT64_MAX #define UINT_LEAST8_MAX UINT8_MAX #define UINT_LEAST16_MAX UINT16_MAX #define UINT_LEAST32_MAX UINT32_MAX #define UINT_LEAST64_MAX UINT64_MAX // 7.18.2.3 Limits of fastest minimum-width integer types #define INT_FAST8_MIN INT8_MIN #define INT_FAST8_MAX INT8_MAX #define INT_FAST16_MIN INT16_MIN #define INT_FAST16_MAX INT16_MAX #define INT_FAST32_MIN INT32_MIN #define INT_FAST32_MAX INT32_MAX #define INT_FAST64_MIN INT64_MIN #define INT_FAST64_MAX INT64_MAX #define UINT_FAST8_MAX UINT8_MAX #define UINT_FAST16_MAX UINT16_MAX #define UINT_FAST32_MAX UINT32_MAX #define UINT_FAST64_MAX UINT64_MAX // 7.18.2.4 Limits of integer types capable of holding object pointers #ifdef _WIN64 // [ # define INTPTR_MIN INT64_MIN # define INTPTR_MAX INT64_MAX # define UINTPTR_MAX UINT64_MAX #else // _WIN64 ][ # define INTPTR_MIN INT32_MIN # define INTPTR_MAX INT32_MAX # define UINTPTR_MAX UINT32_MAX #endif // _WIN64 ] // 7.18.2.5 Limits of greatest-width integer types #define INTMAX_MIN INT64_MIN #define INTMAX_MAX INT64_MAX #define UINTMAX_MAX UINT64_MAX // 7.18.3 Limits of other integer types #ifdef _WIN64 // [ # define PTRDIFF_MIN _I64_MIN # define PTRDIFF_MAX _I64_MAX #else // _WIN64 ][ # define PTRDIFF_MIN _I32_MIN # define PTRDIFF_MAX _I32_MAX #endif // _WIN64 ] #define SIG_ATOMIC_MIN INT_MIN #define SIG_ATOMIC_MAX INT_MAX #ifndef SIZE_MAX // [ # ifdef _WIN64 // [ # define SIZE_MAX _UI64_MAX # else // _WIN64 ][ # define SIZE_MAX _UI32_MAX # endif // _WIN64 ] #endif // SIZE_MAX ] // WCHAR_MIN and WCHAR_MAX are also defined in #ifndef WCHAR_MIN // [ # define WCHAR_MIN 0 #endif // WCHAR_MIN ] #ifndef WCHAR_MAX // [ # define WCHAR_MAX _UI16_MAX #endif // WCHAR_MAX ] #define WINT_MIN 0 #define WINT_MAX _UI16_MAX #endif // __STDC_LIMIT_MACROS ] // 7.18.4 Limits of other integer types #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 // 7.18.4.1 Macros for minimum-width integer constants #define INT8_C(val) val##i8 #define INT16_C(val) val##i16 #define INT32_C(val) val##i32 #define INT64_C(val) val##i64 #define UINT8_C(val) val##ui8 #define UINT16_C(val) val##ui16 #define UINT32_C(val) val##ui32 #define UINT64_C(val) val##ui64 // 7.18.4.2 Macros for greatest-width integer constants #define INTMAX_C INT64_C #define UINTMAX_C UINT64_C #endif // __STDC_CONSTANT_MACROS ] #endif // _MSC_STDINT_H_ ] bzrtp-1.0.6/include/Makefile.am000066400000000000000000000001361313411235300163320ustar00rootroot00000000000000SUBDIRS = bzrtp EXTRA_DIST=cryptoUtils.h packetParser.h stateMachine.h typedef.h zidCache.h bzrtp-1.0.6/include/bzrtp/000077500000000000000000000000001313411235300154375ustar00rootroot00000000000000bzrtp-1.0.6/include/bzrtp/Makefile.am000066400000000000000000000001521313411235300174710ustar00rootroot00000000000000bzrtp_includedir=$(includedir)/bzrtp bzrtp_include_HEADERS= bzrtp.h EXTRA_DIST=$(bzrtp_include_HEADERS) bzrtp-1.0.6/include/bzrtp/bzrtp.h000066400000000000000000000554641313411235300167670ustar00rootroot00000000000000/** @file bzrtp.h @brief Public entry points to the ZRTP implementation @author Johan Pascal @copyright Copyright (C) 2014 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef BZRTP_H #define BZRTP_H #include #include "bctoolbox/crypto.h" #ifdef _MSC_VER #ifdef BZRTP_STATIC #define BZRTP_EXPORT #else #ifdef BZRTP_EXPORTS #define BZRTP_EXPORT __declspec(dllexport) #else #define BZRTP_EXPORT __declspec(dllimport) #endif #endif #else #define BZRTP_EXPORT __attribute__ ((visibility ("default"))) #endif /** * Define different types of crypto functions */ #define ZRTP_HASH_TYPE 0x01 #define ZRTP_CIPHERBLOCK_TYPE 0x02 #define ZRTP_AUTHTAG_TYPE 0x04 #define ZRTP_KEYAGREEMENT_TYPE 0x08 #define ZRTP_SAS_TYPE 0x10 /** * map the differents algorithm (some may not be available) to integer */ #define ZRTP_UNSET_ALGO 0x00 #define ZRTP_HASH_S256 0x11 #define ZRTP_HASH_S384 0x12 #define ZRTP_HASH_N256 0x13 #define ZRTP_HASH_N384 0x14 #define ZRTP_CIPHER_AES1 0x21 #define ZRTP_CIPHER_AES2 0x22 #define ZRTP_CIPHER_AES3 0x23 #define ZRTP_CIPHER_2FS1 0x24 #define ZRTP_CIPHER_2FS2 0x25 #define ZRTP_CIPHER_2FS3 0x26 #define ZRTP_AUTHTAG_HS32 0x31 #define ZRTP_AUTHTAG_HS80 0x32 #define ZRTP_AUTHTAG_SK32 0x33 #define ZRTP_AUTHTAG_SK64 0x34 /** * WARNING : it is very important to keep the key agreement defined in that order * as it is used to easily sort them from faster(DH2k) to slower(EC52) */ #define ZRTP_KEYAGREEMENT_DH2k 0x41 #define ZRTP_KEYAGREEMENT_EC25 0x42 #define ZRTP_KEYAGREEMENT_DH3k 0x43 #define ZRTP_KEYAGREEMENT_EC38 0x44 #define ZRTP_KEYAGREEMENT_EC52 0x45 #define ZRTP_KEYAGREEMENT_Prsh 0x46 #define ZRTP_KEYAGREEMENT_Mult 0x47 #define ZRTP_SAS_B32 0x51 #define ZRTP_SAS_B256 0x52 /** * Define to give client indication on which srtp secrets are valid when given */ #define ZRTP_SRTP_SECRETS_FOR_SENDER 0x01 #define ZRTP_SRTP_SECRETS_FOR_RECEIVER 0x02 /** * brief The data structure containing the keys and algorithms to be used by srtp * Also stores SAS and informations about the crypto algorithms selected during ZRTP negotiation */ typedef struct bzrtpSrtpSecrets_struct { uint8_t *selfSrtpKey; /**< The key used by local part to encrypt */ uint8_t selfSrtpKeyLength; /**< The length in byte of the key */ uint8_t *selfSrtpSalt; /**< The salt used by local part to encrypt */ uint8_t selfSrtpSaltLength; /**< The length in byte of the salt */ uint8_t *peerSrtpKey; /**< The key used by local part to decrypt */ uint8_t peerSrtpKeyLength; /**< The length in byte of the key */ uint8_t *peerSrtpSalt; /**< The salt used by local part to decrypt */ uint8_t peerSrtpSaltLength; /**< The length in byte of the salt */ uint8_t cipherAlgo; /**< The cipher block algorithm selected durign ZRTP negotiation and used by srtp */ uint8_t cipherKeyLength; /**< The key length in bytes for the cipher block algorithm used by srtp */ uint8_t authTagAlgo; /**< srtp authentication tag algorithm agreed on after Hello packet exchange */ char *sas; /**< a null terminated char containing the Short Authentication String */ uint8_t sasLength; /**< The length of sas, including the termination character */ uint8_t hashAlgo; /**< The hash algo selected during ZRTP negotiation */ uint8_t keyAgreementAlgo; /**< The key agreement algo selected during ZRTP negotiation */ uint8_t sasAlgo; /**< The SAS rendering algo selected during ZRTP negotiation */ uint8_t cacheMismatch; /**< Flag set to 1 in case of ZRTP cache mismatch, may occurs only on first channel(the one computing SAS) */ } bzrtpSrtpSecrets_t; /* define message levels */ #define BZRTP_MESSAGE_ERROR 0x00 #define BZRTP_MESSAGE_WARNING 0x01 #define BZRTP_MESSAGE_LOG 0x02 #define BZRTP_MESSAGE_DEBUG 0x03 /* define message codes */ #define BZRTP_MESSAGE_CACHEMISMATCH 0x01 #define BZRTP_MESSAGE_PEERVERSIONOBSOLETE 0x02 #define BZRTP_MESSAGE_PEERNOTBZRTP 0x03 /** * Function pointer used by bzrtp to free memory allocated by callbacks. **/ typedef void (*zrtpFreeBuffer_callback)(void *); /** * @brief All the callback functions provided by the client needed by the ZRTP engine */ typedef struct bzrtpCallbacks_struct { /* messaging status and warnings */ int (* bzrtp_statusMessage)(void *clientData, const uint8_t messageLevel, const uint8_t messageId, const char *messageString); /**< Sending messages to caller: error, warnings, logs, the messageString can be NULL or a NULL terminated string */ int bzrtp_messageLevel; /**< Filter calls to this callback to levels inferiors to this setting (BZRTP_MESSAGE_ERROR, BZRTP_MESSAGE_WARNING, BZRTP_MESSAGE_LOG, BZRTP_MESSAGE_DEBUG )*/ /* sending packets */ int (* bzrtp_sendData)(void *clientData, const uint8_t *packetString, uint16_t packetLength); /**< Send a ZRTP packet to peer. Shall return 0 on success */ /* dealing with SRTP session */ int (* bzrtp_srtpSecretsAvailable)(void *clientData, const bzrtpSrtpSecrets_t *srtpSecrets, uint8_t part); /**< Send the srtp secrets to the client, for either sender, receiver or both according to the part parameter value. Client may wait for the end of ZRTP process before using it */ int (* bzrtp_startSrtpSession)(void *clientData, const bzrtpSrtpSecrets_t *srtpSecrets, int32_t verified); /**< ZRTP process ended well, client is given the SAS and informations about the crypto algo used during ZRTP negotiation. He may start his SRTP session if not done when calling srtpSecretsAvailable */ /* ready for exported keys */ int (* bzrtp_contextReadyForExportedKeys)(void *clientData, int zuid, uint8_t role); /**< Tell the client that this is the time to create any exported keys, s0 is erased just after the call to this callback. Callback is given the peerZID and zuid to adress the correct node in cache and current role which is needed to set a pair of keys for IM encryption */ } bzrtpCallbacks_t; #define ZRTP_MAGIC_COOKIE 0x5a525450 #define ZRTP_VERSION "1.10" /* error code definition */ #define BZRTP_ERROR_INVALIDCALLBACKID 0x0001 #define BZRTP_ERROR_CONTEXTNOTREADY 0x0002 #define BZRTP_ERROR_INVALIDCONTEXT 0x0004 #define BZRTP_ERROR_MULTICHANNELNOTSUPPORTEDBYPEER 0x0008 #define BZRTP_ERROR_UNABLETOADDCHANNEL 0x0010 #define BZRTP_ERROR_UNABLETOSTARTCHANNEL 0x0020 #define BZRTP_ERROR_OUTPUTBUFFER_LENGTH 0x0040 #define BZRTP_ERROR_HELLOHASH_MISMATCH 0x0080 #define BZRTP_ERROR_CHANNELALREADYSTARTED 0x0100 #define BZRTP_ERROR_CACHEDISABLED 0x0200 #define BZRTP_ERROR_CACHEMIGRATIONFAILED 0x0400 /* channel status definition */ #define BZRTP_CHANNEL_NOTFOUND 0x1000 #define BZRTP_CHANNEL_INITIALISED 0x1001 #define BZRTP_CHANNEL_ONGOING 0x1002 #define BZRTP_CHANNEL_SECURE 0x1004 #define BZRTP_CHANNEL_ERROR 0x1008 /* role mapping */ #define BZRTP_ROLE_INITIATOR 0 #define BZRTP_ROLE_RESPONDER 1 /* cache related value */ #define BZRTP_CACHE_SETUP 0x2000 #define BZRTP_CACHE_UPDATE 0x2001 #define BZRTP_CACHE_DATA_NOTFOUND 0x2002 /** * @brief bzrtpContext_t The ZRTP engine context * Store current state, timers, HMAC and encryption keys */ typedef struct bzrtpContext_struct bzrtpContext_t; /** * Create context structure and initialise it * * @return The ZRTP engine context data * */ BZRTP_EXPORT bzrtpContext_t *bzrtp_createBzrtpContext(void); /** * @brief Perform initialisation which can't be done without ZIDcache acces * - get ZID and create the first channel context * * @param[in] context The context to initialise * @param[in] selfSSRC The SSRC given to the first channel context created within the zrtpContext * * @return 0 on success */ BZRTP_EXPORT int bzrtp_initBzrtpContext(bzrtpContext_t *context, uint32_t selfSSRC); /** * Free memory of context structure to a channel, if all channels are freed, free the global zrtp context * @param[in] context Context hosting the channel to be destroyed.(note: the context zrtp context itself is destroyed with the last channel) * @param[in] selfSSRC The SSRC identifying the channel to be destroyed * * @return the number of channel still active in this ZRTP context */ BZRTP_EXPORT int bzrtp_destroyBzrtpContext(bzrtpContext_t *context, uint32_t selfSSRC); /** * @brief Allocate a function pointer to the callback function identified by his id * @param[in/out] context The zrtp context to set the callback function * @param[in] cbs A structure containing all the callbacks to supply. * * @return 0 on success * */ BZRTP_EXPORT int bzrtp_setCallbacks(bzrtpContext_t *context, const bzrtpCallbacks_t *cbs); /** * @brief Set the pointer allowing cache access * * @param[in] zidCachePointer Used by internal function to access cache: turn into a sqlite3 pointer if cache is enabled * @param[in] selfURI Local URI used for this communication, needed to perform cache operation, NULL terminated string, duplicated by this function * @param[in] peerURI Peer URI used for this communication, needed to perform cache operation, NULL terminated string, duplicated by this function * * @return 0 or BZRTP_CACHE_SETUP(if cache is populated by this call) on success, error code otherwise */ BZRTP_EXPORT int bzrtp_setZIDCache(bzrtpContext_t *context, void *zidCache, const char *selfURI, const char *peerURI); /** * @brief Set the client data pointer in a channel context * This pointer is returned to the client by the callbacks function, used to store associated contexts (RTP session) * @param[in/out] zrtpContext The ZRTP context we're dealing with * @param[in] selfSSRC The SSRC identifying the channel to be linked to the client Data * @param[in] clientData The clientData pointer, casted to a (void *) * * @return 0 on success * */ BZRTP_EXPORT int bzrtp_setClientData(bzrtpContext_t *zrtpContext, uint32_t selfSSRC, void *clientData); /** * @brief Add a channel to an existing context * * @param[in/out] zrtpContext The zrtp context who will get the additionnal channel * @param[in] selfSSRC The SSRC given to the channel context * * @return 0 on succes, error code otherwise */ BZRTP_EXPORT int bzrtp_addChannel(bzrtpContext_t *zrtpContext, uint32_t selfSSRC); /** * @brief Start the state machine of the specified channel * To be able to start an addional channel, we must be in secure state * * @param[in/out] zrtpContext The ZRTP context hosting the channel to be started * @param[in] selfSSRC The SSRC identifying the channel to be started(will start sending Hello packets and listening for some) * * @return 0 on succes, error code otherwise */ BZRTP_EXPORT int bzrtp_startChannelEngine(bzrtpContext_t *zrtpContext, uint32_t selfSSRC); /** * @brief Send the current time to a specified channel, it will check if it has to trig some timer * * @param[in/out] zrtpContext The ZRTP context hosting the channel * @param[in] selfSSRC The SSRC identifying the channel * @param[in] timeReference The current time in ms * * @return 0 on succes, error code otherwise */ BZRTP_EXPORT int bzrtp_iterate(bzrtpContext_t *zrtpContext, uint32_t selfSSRC, uint64_t timeReference); /** * @brief Process a received message * * @param[in/out] zrtpContext The ZRTP context we're dealing with * @param[in] selfSSRC The SSRC identifying the channel receiving the message * @param[in] zrtpPacketString The packet received * @param[in] zrtpPacketStringLength Length of the packet in bytes * * @return 0 on success, errorcode otherwise */ BZRTP_EXPORT int bzrtp_processMessage(bzrtpContext_t *zrtpContext, uint32_t selfSSRC, uint8_t *zrtpPacketString, uint16_t zrtpPacketStringLength); /** * @brief Called by user when the SAS has been verified * * @param[in/out] zrtpContext The ZRTP context we're dealing with */ BZRTP_EXPORT void bzrtp_SASVerified(bzrtpContext_t *zrtpContext); /** * @brief Called by user when the SAS has been set to unverified * * @param[in/out] zrtpContext The ZRTP context we're dealing with */ BZRTP_EXPORT void bzrtp_resetSASVerified(bzrtpContext_t *zrtpContext); /** * @brief Reset the retransmission timer of a given channel. * Packets will be sent again if appropriate: * - when in responder role, zrtp engine only answer to packets sent by the initiator. * - if we are still in discovery phase, Hello or Commit packets will be resent. * * @param[in/out] zrtpContext The ZRTP context we're dealing with * @param[in] selfSSRC The SSRC identifying the channel to reset * * return 0 on success, error code otherwise */ BZRTP_EXPORT int bzrtp_resetRetransmissionTimer(bzrtpContext_t *zrtpContext, uint32_t selfSSRC); /** * @brief Get the supported crypto types * * @param[int] zrtpContext The ZRTP context we're dealing with * @param[in] algoType mapped to defines, must be in [ZRTP_HASH_TYPE, ZRTP_CIPHERBLOCK_TYPE, ZRTP_AUTHTAG_TYPE, ZRTP_KEYAGREEMENT_TYPE or ZRTP_SAS_TYPE] * @param[out] supportedTypes mapped to uint8_t value of the 4 char strings giving the supported types as string according to rfc section 5.1.2 to 5.1.6 * * @return number of supported types, 0 on error */ BZRTP_EXPORT uint8_t bzrtp_getSupportedCryptoTypes(bzrtpContext_t *zrtpContext, uint8_t algoType, uint8_t supportedTypes[7]); /** * @brief set the supported crypto types * * @param[int/out] zrtpContext The ZRTP context we're dealing with * @param[in] algoType mapped to defines, must be in [ZRTP_HASH_TYPE, ZRTP_CIPHERBLOCK_TYPE, ZRTP_AUTHTAG_TYPE, ZRTP_KEYAGREEMENT_TYPE or ZRTP_SAS_TYPE] * @param[in] supportedTypes mapped to uint8_t value of the 4 char strings giving the supported types as string according to rfc section 5.1.2 to 5.1.6 * @param[in] supportedTypesCount number of supported crypto types */ BZRTP_EXPORT void bzrtp_setSupportedCryptoTypes(bzrtpContext_t *zrtpContext, uint8_t algoType, uint8_t supportedTypes[7], uint8_t supportedTypesCount); /** * @brief Set the peer hello hash given by signaling to a ZRTP channel * * @param[in/out] zrtpContext The ZRTP context we're dealing with * @param[in] selfSSRC The SSRC identifying the channel * @param[in] peerHelloHashHexString A NULL terminated string containing the hexadecimal form of the hash received in signaling, * may contain ZRTP version as header. * @param[in] peerHelloHashHexStringLength Length of hash string (shall be at least 64 as the hash is a SHA256 so 32 bytes, * more if it contains the version header) * * @return 0 on success, errorcode otherwise */ BZRTP_EXPORT int bzrtp_setPeerHelloHash(bzrtpContext_t *zrtpContext, uint32_t selfSSRC, uint8_t *peerHelloHashHexString, size_t peerHelloHashHexStringLength); /** * @brief Get the self hello hash from ZRTP channel * * @param[in/out] zrtpContext The ZRTP context we're dealing with * @param[in] selfSSRC The SSRC identifying the channel * @param[out] output A NULL terminated string containing the hexadecimal form of the hash received in signaling, * contain ZRTP version as header. Buffer must be allocated by caller. * @param[in] outputLength Length of output buffer, shall be at least 70 : 5 chars for version, 64 for the hash itself, SHA256), NULL termination * * @return 0 on success, errorcode otherwise */ BZRTP_EXPORT int bzrtp_getSelfHelloHash(bzrtpContext_t *zrtpContext, uint32_t selfSSRC, uint8_t *output, size_t outputLength); /** * @brief Get the channel status * * @param[in] zrtpContext The ZRTP context we're dealing with * @param[in] selfSSRC The SSRC identifying the channel * * @return BZRTP_CHANNEL_NOTFOUND no channel matching this SSRC doesn't exists in the zrtp context * BZRTP_CHANNEL_INITIALISED channel initialised but not started * BZRTP_CHANNEL_ONGOING ZRTP key exchange in ongoing * BZRTP_CHANNEL_SECURE Channel is secure * BZRTP_CHANNEL_ERROR An error occured on this channel */ BZRTP_EXPORT int bzrtp_getChannelStatus(bzrtpContext_t *zrtpContext, uint32_t selfSSRC); /*** Cache related functions ***/ /** * @brief Check the given sqlite3 DB and create requested tables if needed * Also manage DB schema upgrade * @param[in/out] db Pointer to the sqlite3 db open connection * Use a void * to keep this API when building cacheless * * @return 0 on success, BZRTP_CACHE_SETUP if cache was empty, BZRTP_CACHE_UPDATE if db structure was updated, error code otherwise */ BZRTP_EXPORT int bzrtp_initCache(void *db); /** * @brief : retrieve ZID from cache * ZID is randomly generated if cache is empty or inexistant * ZID is randomly generated in case of cacheless implementation(db argument is NULL) * * @param[in/out] db sqlite3 database(or NULL if we don't use cache at runtime) * Use a void * to keep this API when building cacheless * @param[in] selfURI the sip uri of local user, NULL terminated string * @param[out] selfZID the ZID, retrieved from cache or randomly generated * @param[in] RNGContext A RNG context used to generate ZID if needed * * @return 0 on success, or BZRTP_CACHE_DATA_NOTFOUND if no ZID matching the URI was found and no RNGContext is given to generate one */ BZRTP_EXPORT int bzrtp_getSelfZID(void *db, const char *selfURI, uint8_t selfZID[12], bctbx_rng_context_t *RNGContext); /** * @brief get the cache internal id used to bind local uri(hence local ZID associated to it)<->peer uri/peer ZID. * Providing a valid local URI(already present in cache), a peer ZID and peer URI will return the zuid creating it if needed * Any pair ZID/sipURI shall identify an account on a device. * * @param[in/out] db the opened sqlite database pointer * @param[in] selfURI local URI, must be already associated to a ZID in the DB(association is performed by any call of getSelfZID on this URI) * @param[in] peerURI peer URI * @param[in] peerZID peer ZID * @param[out] zuid the internal db reference to the data row matching this particular pair of correspondant * * @return 0 on success, error code otherwise */ BZRTP_EXPORT int bzrtp_cache_getZuid(void *dbPointer, const char *selfURI, const char *peerURI, const uint8_t peerZID[12], int *zuid); /** * @brief Write(insert or update) data in cache, adressing it by zuid (ZID/URI binding id used in cache) * Get arrays of column names, values to be inserted, lengths of theses values * All three arrays must be the same lenght: columnsCount * If the row isn't present in the given table, it will be inserted * * @param[in/out] dbPointer Pointer to an already opened sqlite db * @param[in] zuid The DB internal id to adress the correct row(binding between local uri and peer ZID+URI) * @param[in] tableName The name of the table to write in the db, must already exists. Null terminated string * @param[in] columns An array of null terminated strings containing the name of the columns to update * @param[in] values An array of buffers containing the values to insert/update matching the order of columns array * @param[in] lengths An array of integer containing the lengths of values array buffer matching the order of columns array * @param[in] columnsCount length common to columns,values and lengths arrays * * @return 0 on succes, error code otherwise */ BZRTP_EXPORT int bzrtp_cache_write(void *dbPointer, int zuid, char *tableName, char **columns, uint8_t **values, size_t *lengths, uint8_t columnsCount); /** * @brief Read data from specified table/columns from cache adressing it by zuid (ZID/URI binding id used in cache) * Get arrays of column names, values to be read, and the number of colums to be read * Produce an array of values(uint8_t arrays) and a array of corresponding lengths * Values memory is allocated by this function and must be freed by caller * * @param[in/out] dbPointer Pointer to an already opened sqlite db * @param[in] zuid The DB internal id to adress the correct row(binding between local uri and peer ZID+URI) * @param[in] tableName The name of the table to read in the db. Null terminated string * @param[in] columns An array of null terminated strings containing the name of the columns to read, the array's length is columnsCount * @param[out] values An array of uint8_t pointers, each one will be allocated to the read value and they must be freed by caller * @param[out] lengths An array of integer containing the lengths of values array buffer read * @param[in] columnsCount length common to columns,values and lengths arrays * * @return 0 on succes, error code otherwise */ BZRTP_EXPORT int bzrtp_cache_read(void *dbPointer, int zuid, char *tableName, char **columns, uint8_t **values, size_t *lengths, uint8_t columnsCount); /** * @brief Perform migration from xml version to sqlite3 version of cache * Warning: new version of cache associate a ZID to each local URI, the old one did not * the migration function will associate any data in the cache to the sip URI given in parameter which shall be the default URI * @param[in] cacheXml a pointer to an xmlDocPtr structure containing the old cache to be migrated * @param[in/out] cacheSqlite a pointer to an sqlite3 structure containing a cache initialised using bzrtp_cache_init function * @param[in] selfURI default sip URI for this end point, NULL terminated char * * @return 0 on success, BZRTP_ERROR_CACHEDISABLED when bzrtp was not compiled with cache enabled, BZRTP_ERROR_CACHEMIGRATIONFAILED on error during migration */ BZRTP_EXPORT int bzrtp_cache_migration(void *cacheXmlPtr, void *cacheSqlite, const char *selfURI); /* * @brief Allow client to compute an exported according to RFC section 4.5.2 * Check the context is ready(we already have a master exported key and KDF context) * and run KDF(master exported key, "Label", KDF_Context, negotiated hash Length) * * @param[in] zrtpContext The ZRTP context we're dealing with * @param[in] label Label used in the KDF * @param[in] labelLength Length of previous buffer * @param[out] derivedKey Buffer to store the derived key * @param[in/out] derivedKeyLength Length of previous buffer(updated to fit actual length of data produced if too long) * * @return 0 on succes, error code otherwise */ BZRTP_EXPORT int bzrtp_exportKey(bzrtpContext_t *zrtpContext, char *label, size_t labelLength, uint8_t *derivedKey, size_t *derivedKeyLength); #endif /* ifndef BZRTP_H */ bzrtp-1.0.6/include/cryptoUtils.h000066400000000000000000000236231313411235300170160ustar00rootroot00000000000000/** @file cryptoUtils.h @brief Prototypes for security related functions - Key Derivation Function - CRC - Base32 - Key agreement algorithm negociation @author Johan Pascal @copyright Copyright (C) 2014 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef CRYPTOUTILS_H #define CRYPTOUTILS_H #include "typedef.h" #include "packetParser.h" /** Return available crypto functions. For now we have * * - Hash: HMAC-SHA256(Mandatory) * - CipherBlock: AES128(Mandatory) * - Auth Tag: HMAC-SHA132 and HMAC-SHA180 (These are mandatory for SRTP and depends on the SRTP implementation thus we can just suppose they are both available) * - Key Agreement: DHM3k(Mandatory), DHM2k(optional and shall not be used except on low power devices) * - Sas: base32(Mandatory), b256(pgp words) */ uint8_t bzrtpUtils_getAvailableCryptoTypes(uint8_t algoType, uint8_t availableTypes[7]); /** * * @brief ZRTP Key Derivation Function as in rfc 4.5.1 * * KDF(KI, Label, Context, L) = HMAC(KI, i || Label || * 0x00 || Context || L) * where * - i is a 32-bits integer fixed to 0x00000001 * - L is a 32-bit big-endian positive * integer, not to exceed the length in bits of the output of the HMAC. * The output of the KDF is truncated to the leftmost L bits. * * @param[in] key The key for HMAC * @param[in] keyLength Length of the key in bytes * @param[in] label A string to be included in the hash * @param[in] labelLength Length of the label in bytes * @param[in] context a context string for the key derivation * @param[in] contextLength Length of the context string in bytes * @param[in] hmacLength The output of the KDF is the HMAC truncated to the leftmost L bytes * @param[in] hmacFunction The hashmac function to be used to compute the KDF * @param[out] output A buffer to store the hmacLength bytes of output * * @return 0 on succes, error code otherwise */ BZRTP_EXPORT int bzrtp_keyDerivationFunction(uint8_t *key, uint16_t keyLength, uint8_t *label, uint16_t labelLength, uint8_t *context, uint16_t contextLength, uint16_t hmacLength, void (*hmacFunction)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *), uint8_t *output); /** * @brief SAS rendering from 32 bits to 4 characters * Function defined in rfc section 5.1.6 * * @param[in] sas The 32 bits SAS * @param[out] output The 4 chars string to be displayed to user for vocal confirmation * */ void bzrtp_base32(uint32_t sas, char *output, int outputSize); /** * @brief SAS rendering from 32 bits to pgp word list * Function defined in rfc section 5.1.6 * * @param[in] sas The 32 bits SAS * @param[out] output The output list. Passed in array must be at least 32 bytes * */ void bzrtp_base256(uint32_t sas, char *output, int outputSize); /** * @brief CRC32 as defined in RFC4960 Appendix B - Polynomial is 0x1EDC6F41 * * CRC is computed in reverse bit mode (least significant bit first within each byte) * reversed value of polynom (0x82F63B78) was used to compute the lookup table (source * http://en.wikipedia.org/wiki/Cyclic_redundancy_check#Commonly_used_and_standardized_CRCs) * * @param[in] input input data * @param[in] length length of data in bytes * * @return the 32 bits CRC value * */ BZRTP_EXPORT uint32_t bzrtp_CRC32(uint8_t *input, uint16_t length); /* error code for the cryptoAlgoAgreement and function pointer update functions */ #define ZRTP_CRYPTOAGREEMENT_INVALIDCONTEXT 0x1001 #define ZRTP_CRYPTOAGREEMENT_INVALIDMESSAGE 0x1002 #define ZRTP_CRYPTOAGREEMENT_INVALIDSELFALGO 0x1003 #define ZRTP_CRYPTOAGREEMENT_NOCOMMONALGOFOUND 0x1004 #define ZRTP_CRYPTOAGREEMENT_INVALIDCIPHER 0x1005 #define ZRTP_CRYPTOAGREEMENT_INVALIDHASH 0x1006 #define ZRTP_CRYPTOAGREEMENT_INVALIDAUTHTAG 0x1007 #define ZRTP_CRYPTOAGREEMENT_INVALIDSAS 0x1008 /** * @brief select a key agreement algorithm from the one available in context and the one provided by * peer in Hello Message as described in rfc section 4.1.2 * - other algorithm are selected according to availability and selected key agreement as described in * rfc section 5.1.5 * The other algorithm choice will finally be set by the endpoint acting as initiator in the commit packet * * @param[in] zrtpContext The context contains the list of available algo * @param[out] zrtpChannelContext The bzrtp channel context to be updated * @param[in] peerHelloMessage The peer hello message containing his set of available algos * * return 0 on succes, error code otherwise * */ BZRTP_EXPORT int bzrtp_cryptoAlgoAgreement(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext, bzrtpHelloMessage_t *peerHelloMessage); /** * @brief Update context crypto function pointer according to related values of choosen algorithms fields (hashAlgo, cipherAlgo, etc..) * * @param[in/out] zrtpChannelContext The bzrtp channel context to be updated * * @return 0 on succes */ BZRTP_EXPORT int bzrtp_updateCryptoFunctionPointers(bzrtpChannelContext_t *zrtpChannelContext); /** * @brief Select common algorithm from the given array where algo are represented by their 4 chars string defined in rfc section 5.1.2 to 5.1.6 * Master array is the one given the preference order * All algo are designed by their uint8_t mapped values * * @param[in] masterArray The ordered available algo, result will follow this ordering * @param[in] masterArrayLength Number of valids element in the master array * @param[in] slaveArray The available algo, order is not taken in account * @param[in] slaveArrayLength Number of valids element in the slave array * @param[out] commonArray Common algorithms found, max size 7 * * @return the number of common algorithms found */ uint8_t selectCommonAlgo(uint8_t masterArray[7], uint8_t masterArrayLength, uint8_t slaveArray[7], uint8_t slaveArrayLength, uint8_t commonArray[7]); /** * @brief add mandatory crypto functions if they are not already included * - Hash function * - Cipher Block * - Auth Tag * - Key agreement * - SAS * * @param[in] algoType mapped to defines, must be in [ZRTP_HASH_TYPE, ZRTP_CIPHERBLOCK_TYPE, ZRTP_AUTHTAG_TYPE, ZRTP_KEYAGREEMENT_TYPE or ZRTP_SAS_TYPE] * @param[in/out] algoTypes mapped to uint8_t value of the 4 char strings giving the algo types as string according to rfc section 5.1.2 to 5.1.6 * @param[in/out] algoTypesCount number of algo types */ BZRTP_EXPORT void bzrtp_addMandatoryCryptoTypesIfNeeded(uint8_t algoType, uint8_t algoTypes[7], uint8_t *algoTypesCount); /** * @brief Map the string description of algo type to an int defined in cryptoWrapper.h * * @param[in] algoType A 4 chars string containing the algo type as listed in rfc sections 5.1.2 to 5.1.6 * @param[in] algoFamily The integer mapped algo family (ZRTP_HASH_TYPE, ZRTP_CIPHERBLOCK_TYPE, ZRTP_AUTHTAG_TYPE, * ZRTP_KEYAGREEMENT_TYPE or ZRTP_SAS_TYPE) * @return The int value mapped to the algo type, ZRTP_UNSET_ALGO on error */ BZRTP_EXPORT uint8_t bzrtp_cryptoAlgoTypeStringToInt(uint8_t algoType[4], uint8_t algoFamily); /** * @brief Unmap the string description of algo type to an int defined in cryptoWrapper.h * * @param[in] algoTypeInt The integer algo type defined in crypoWrapper.h * @param[in] algoFamily The string code for the algorithm as defined in rfc 5.1.2 to 5.1.6 */ BZRTP_EXPORT void bzrtp_cryptoAlgoTypeIntToString(uint8_t algoTypeInt, uint8_t algoTypeString[4]); /** * @brief Destroy a key by setting it to a random number * Key is not freed, caller must deal with memory management. * Does nothing if the key pointer is NULL * * @param[in/out] key The key to be destroyed * @param[in] keyLength The keyLength in bytes * @param[in] rngContext The context for RNG */ BZRTP_EXPORT void bzrtp_DestroyKey(uint8_t *key, uint8_t keyLength, void *rngContext); /** * @brief Convert an hexadecimal string into the corresponding byte buffer * * @param[out] outputBytes The output bytes buffer, must have a length of half the input string buffer * @param[in] inputString The input string buffer, must be hexadecimal(it is not checked by function, any non hexa char is converted to 0) * @param[in] inputStringLength The length in chars of the string buffer, output is half this length */ void bzrtp_strToUint8(uint8_t *outputBytes, uint8_t *inputString, uint16_t inputStringLength); /** * @brief Convert a byte buffer into the corresponding hexadecimal string * * @param[out] outputString The output string buffer, must have a length of twice the input bytes buffer * @param[in] inputBytes The input bytes buffer * @param[in] inputBytesLength The length in bytes buffer, output is twice this length */ void bzrtp_int8ToStr(uint8_t *outputString, uint8_t *inputBytes, uint16_t inputBytesLength); /** * @brief convert an hexa char [0-9a-fA-F] into the corresponding unsigned integer value * Any invalid char will be converted to zero without any warning * * @param[in] inputChar a char which shall be in range [0-9a-fA-F] * * @return the unsigned integer value in range [0-15] */ uint8_t bzrtp_charToByte(uint8_t inputChar); /** * @brief convert a byte which value is in range [0-15] into an hexa char [0-9a-fA-F] * * @param[in] inputByte an integer which shall be in range [0-15] * * @return the hexa char [0-9a-f] corresponding to the input */ uint8_t bzrtp_byteToChar(uint8_t inputByte); #endif /* CRYPTOUTILS_H */ bzrtp-1.0.6/include/packetParser.h000066400000000000000000000502261313411235300171000ustar00rootroot00000000000000/** @file packetParser.h @brief functions to parse and generate a ZRTP packet @author Johan Pascal @copyright Copyright (C) 2014 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef PACKETPARSER_H #define PACKETPARSER_H #include #include "bzrtp/bzrtp.h" /* header of ZRTP packet is 12 bytes : Preambule/Sequence Number + ZRTP Magic Cookie + SSRC */ #define ZRTP_PACKET_HEADER_LENGTH 12 #define ZRTP_PACKET_CRC_LENGTH 4 #define ZRTP_PACKET_OVERHEAD 16 #define BZRTP_PARSER_ERROR_INVALIDCRC 0xa001 #define BZRTP_PARSER_ERROR_INVALIDPACKET 0xa002 #define BZRTP_PARSER_ERROR_OUTOFORDER 0xa004 #define BZRTP_PARSER_ERROR_INVALIDMESSAGE 0xa008 #define BZRTP_PARSER_ERROR_INVALIDCONTEXT 0xa010 #define BZRTP_PARSER_ERROR_UNMATCHINGCONFIRMMAC 0xa020 #define BZRTP_PARSER_ERROR_UNMATCHINGSSRC 0xa040 #define BZRTP_PARSER_ERROR_UNMATCHINGHASHCHAIN 0xa080 #define BZRTP_PARSER_ERROR_UNMATCHINGMAC 0xa100 #define BZRTP_PARSER_ERROR_UNEXPECTEDMESSAGE 0xa200 #define BZRTP_PARSER_ERROR_UNMATCHINGHVI 0xa400 #define BZRTP_BUILDER_ERROR_INVALIDPACKET 0x5001 #define BZRTP_BUILDER_ERROR_INVALIDMESSAGE 0x5002 #define BZRTP_BUILDER_ERROR_INVALIDMESSAGETYPE 0x5004 #define BZRTP_BUILDER_ERROR_UNKNOWN 0x5008 #define BZRTP_BUILDER_ERROR_INVALIDCONTEXT 0x5010 #define BZRTP_CREATE_ERROR_INVALIDMESSAGETYPE 0x0a01 #define BZRTP_CREATE_ERROR_UNABLETOCREATECRYPTOCONTEXT 0x0a02 #define BZRTP_CREATE_ERROR_INVALIDCONTEXT 0x0a04 /* map all message type to an uint8_t value */ #define MSGTYPE_INVALID 0x00 #define MSGTYPE_HELLO 0x01 #define MSGTYPE_HELLOACK 0x02 #define MSGTYPE_COMMIT 0x03 #define MSGTYPE_DHPART1 0x04 #define MSGTYPE_DHPART2 0x05 #define MSGTYPE_CONFIRM1 0x06 #define MSGTYPE_CONFIRM2 0x07 #define MSGTYPE_CONF2ACK 0x08 #define MSGTYPE_ERROR 0x10 #define MSGTYPE_ERRORACK 0x11 #define MSGTYPE_GOCLEAR 0x12 #define MSGTYPE_CLEARACK 0x13 #define MSGTYPE_SASRELAY 0x14 #define MSGTYPE_RELAYACK 0x15 #define MSGTYPE_PING 0x16 #define MSGTYPE_PINGACK 0x17 /** * @brief Store all zrtpPacket informations * according to type a specific structure type is mapped to the void * data pointer */ typedef struct bzrtpPacket_struct { uint16_t sequenceNumber; /**< set by packet parser to enable caller to retrieve the packet sequence number. This field is not used buy the packet creator, sequence number is given as a parameter when converting the message to a packet string. Used only when parsing a string into a packet struct */ uint32_t sourceIdentifier; /**< the SSRC of current RTP stream */ uint8_t messageType; /**< the ZRTP message type mapped from strings to hard defined byte */ uint16_t messageLength; /**< the ZRTP message length in bytes - the message length indicated in the message itself is in 32 bits words. Is not the packet length(do not include packet header and CRC) */ void *messageData; /**< a pointer to the structure containing all the message field according to message type */ uint8_t *packetString; /**< used to stored the string version of the packet build from the message data or keep a string copy of received packets */ } bzrtpPacket_t; /** * Structure definition for all zrtp message type according to rfc section 5.2 to 5.16 * */ /** * @brief Hello Message rfc 5.2 */ typedef struct bzrtpHelloMessage_struct { uint8_t version[4]; /**< a string defining the current version, shall be 1.10 */ uint8_t clientIdentifier[17]; /**< a string identifing the vendor and release of ZRTP software, actual content is 16, but last character forced to '\0' */ uint8_t H3[32]; /**< the hash image H3 (256 bits) */ uint8_t ZID[12]; /**< unique identifier for ZRTP endpoint (96 bits) */ uint8_t S; /**< The signature-capable flag. If signatures are not supported, the (S) flag MUST be set to zero (1 bit) */ uint8_t M; /**< The MiTM flag (M) is a Boolean that is set to true if and only if this Hello message is sent from a device, usually a PBX, that has the capability to send an SASrelay message (1 bit) **/ uint8_t P; /**< The Passive flag (P) is a Boolean normally set to false, and is set to true if and only if this Hello message is sent from a device that is configured to never send a Commit message (Section 5.4). This would mean it cannot initiate secure sessions, but may act as a responder. (1 bit) */ uint8_t hc; /**< hash count -zrtpPacket set to 0 means we support only HMAC-SHA256 (4 bits) */ uint8_t supportedHash[7]; /**< list of supported hash algorithms mapped to uint8_t */ uint8_t cc; /**< cipher count - set to 0 means we support only AES128-CFB128 (4 bits) */ uint8_t supportedCipher[7]; /**< list of supported cipher algorithms mapped to uint8_t */ uint8_t ac; /**< auth tag count - set to 0 mean we support only HMAC-SHA1-32 (4 bits) */ uint8_t supportedAuthTag[7]; /**< list of supported SRTP authentication tag algorithms mapped to uint8_t */ uint8_t kc; /**< key agreement count - set to 0 means we support only Diffie-Hellman-Merkle 3072 (4 bits) */ uint8_t supportedKeyAgreement[7]; /**< list of supported key agreement algorithms mapped to uint8_t */ uint8_t sc; /**< sas count - set to 0 means we support only base32 (4 bits) */ uint8_t supportedSas[7]; /**< list of supported Sas representations (4 chars string) */ uint8_t MAC[8]; /**< HMAC over the whole message, keyed by the hash image H2 (64 bits)*/ } bzrtpHelloMessage_t; /** * @brief Hello ACK Message rfc 5.3 * This message contains no data but only a length and message type which are stored in the bzrtpPacket_t structure * There the no need to define a structure type for this packet */ /** * * @brief Commit Message rfc 5.4 * This message can be of 3 different types: DHM, PreShared and Multistream, some field of it may be used only by certain type of message * It is generated by the initiator (see section 4.2 for commit contention) */ typedef struct bzrtpCommitMessage_struct { uint8_t H2[32]; /**< the hash image H2 (256 bits) */ uint8_t ZID[12]; /**< initiator's unique identifier for ZRTP endpoint (96 bits) */ uint8_t hashAlgo; /**< the hash algorithm identifier rfc section 5.1.2 mapped to an integer */ uint8_t cipherAlgo; /**< the cipher algorithm identifier rfc section 5.1.3 mapped to an integer */ uint8_t authTagAlgo; /**< the auth tag algorithm identifier rfc section 5.1.4 mapped to an integer */ uint8_t keyAgreementAlgo; /**< the key agreement algorithm identifier rfc section 5.1.5. It can either be a key exchange algorithm or the commit packet type in case of preShared or multistream commit message mapped to an integer */ uint8_t sasAlgo; /**< the sas rendering algorithm identifier rfc section 5.1.6 mapped to an integer */ uint8_t hvi[32]; /**< only for DH commit : a hash of initiator's DHPart2 and responder's Hello message rfc section 4.4.1.1 */ uint8_t nonce[16]; /**< only for preShared or Multistream modes : a 128 bits random number generated by the initiator */ uint8_t keyID[8]; /**< only for preShared mode : the preshared key identifier */ uint8_t MAC[8]; /**< HMAC over the whole message, keyed by the hash image H1 (64 bits)*/ } bzrtpCommitMessage_t; /** * * @brief DHPart Message rfc 5.5 and rfc 5.6 * DHPart1 and DHPart2 message have the same structure * DHPart1 is generated by the responder, and DHPart2 by the initiator */ typedef struct bzrtpDHPartMessage_struct { uint8_t H1[32]; /**< the hash image H1 (256 bits) */ uint8_t rs1ID[8]; /**< hash of the retained secret 1 (64 bits) */ uint8_t rs2ID[8]; /**< hash of the retained secret 2 (64 bits) */ uint8_t auxsecretID[8]; /**< hash of the auxiliary shared secret (64 bits) */ uint8_t pbxsecretID[8]; /**< hash of the trusted MiTM PBX shared secret pbxsecret, defined in section 7.3.1 (64 bits) */ uint8_t *pv; /* Key exchange public value (length depends on key agreement type) */ uint8_t MAC[8]; /**< HMAC over the whole message, keyed by the hash image H1 (64 bits)*/ } bzrtpDHPartMessage_t; /** * * @brief Confirm Message rfc 5.7 * Confirm1 and Confirm2 messages have the same structure * Confirm1 is generated by the responder and Confirm2 by the initiator * Part of the message is encrypted using the negotiated block cipher for media encryption. Keys ares zrtpkeyr for responder and zrtpkeyi for initiator */ typedef struct bzrtpConfirmMessage_struct { uint8_t confirm_mac[8]; /**< a MAC computed over the encrypted part of the message (64 bits) */ uint8_t CFBIV[16]; /**< The CFB Initialization Vector is a 128-bit random nonce (128 bits) */ uint8_t H0[32]; /**< the hash image H0 - Encrypted - (256 bits) */ uint16_t sig_len; /**< The SAS signature length. If no SAS signature (described in Section 7.2) is present, all bits are set to zero. The signature length is in words and includes the signature type block. If the calculated signature octet count is not a multiple of 4, zeros are added to pad it out to a word boundary. If no signature is present, the overall length of the Confirm1 or Confirm2 message will be set to 19 words - Encrypted - (9 bits) */ uint8_t E; /**< The PBX Enrollment flag (E) is a Boolean bit defined in Section 7.3.1 - Encrypted - (1 bit) */ uint8_t V; /**< The SAS Verified flag (V) is a Boolean bit defined in Section 7.1. - Encrypted - (1 bit) */ uint8_t A; /**< The Allow Clear flag (A) is a Boolean bit defined in Section 4.7.2 - Encrypted - (1 bit) */ uint8_t D; /**< The Disclosure Flag (D) is a Boolean bit defined in Section 11. - Encrypted - (1 bit) */ uint32_t cacheExpirationInterval; /**< The cache expiration interval is defined in Section 4.9 - Encrypted - (32 bits) */ uint8_t signatureBlockType[4]; /**< Optionnal signature type : "PGP " or "X509" string - Encrypted - (32 bits) */ uint8_t *signatureBlock; /**< Optionnal signature block as decribded in section 7.2 - Encrypted - (variable length) */ } bzrtpConfirmMessage_t; /** * @brief Conf2 ACK Message rfc 5.8 * This message contains no data but only a length and message type which are stored in the bzrtpPacket_t structure * There the no need to define a structure type for this packet */ /** * @brief Error Message rfc section 5.9 * The Error message is sent to terminate an in-process ZRTP key agreement exchange due to an error. * There is no need to define a structure for this packet as it contains length and message type which are stored * in the bzrtpPacket_t structure and a 32 bits integer error code only */ /** * @brief Error ACK Message rfc 5.10 * This message contains no data but only a length and message type which are stored in the bzrtpPacket_t structure * There the no need to define a structure type for this packet */ /** * @brief GoClear Message rfc 5.11 * Support for the GoClear message is OPTIONAL in the protocol, and it is sent to switch from SRTP to RTP. */ typedef struct bzrtpGoClearMessage_struct { uint8_t clear_mac[8]; /**< The clear_mac is used to authenticate the GoClear message so that bogus GoClear messages introduced by an attacker can be detected and discarded. (64 bits) */ } bzrtpGoClearMessage_t; /** * * @brief Clear ACK Message rfc 5.12 * This message contains no data but only a length and message type which are stored in the bzrtpPacket_t structure * There the no need to define a structure type for this packet */ /** * @brief SASRelay Message rfc 5.13 * The SASrelay message is sent by a trusted MiTM, most often a PBX. It is not sent as a response to a packet, but is sent as a self-initiated packet by the trusted MiTM (Section 7.3). It can only be sent after the rest of the ZRTP key negotiations have completed, after the Confirm messages and their ACKs. It can only be sent after the trusted MiTM has finished key negotiations with the other party, because it is the other party's SAS that is being relayed. It is sent with retry logic until a RelayACK message (Section 5.14) is received or the retry schedule has been exhausted. Part of the message is encrypted using the negotiated block cipher for media encryption. * Depending on whether the trusted MiTM had taken the role of the initiator or the responder during the ZRTP key negotiation, the * SASrelay message is encrypted with zrtpkeyi or zrtpkeyr. */ typedef struct bzrtpSASRelayMessage_struct { uint8_t MAC[8]; /**< a MAC computed over the encrypted part of the message (64 bits) */ uint8_t CFBIV[16]; /**< The CFB Initialization Vector is a 128-bit random nonce (128 bits) */ uint16_t sig_len; /**< The SAS signature length. The trusted MiTM MAY compute a digital signature on the SAS hash, as described in Section 7.2, using a persistent signing key owned by the trusted MiTM. If no SAS signature is present, all bits are set to zero. The signature length is in words and includes the signature type block. If the calculated signature octet count is not a multiple of 4, zeros are added to pad it out to a word boundary. If no signature block is present, the overall length of the SASrelay message will be set to 19 words.*/ uint8_t V; /**< The SAS Verified flag (V) is a Boolean bit defined in Section 7.1. - Encrypted - (1 bit) */ uint8_t A; /**< The Allow Clear flag (A) is a Boolean bit defined in Section 4.7.2 - Encrypted - (1 bit) */ uint8_t D; /**< The Disclosure Flag (D) is a Boolean bit defined in Section 11. - Encrypted - (1 bit) */ uint8_t renderingScheme[4]; /**< the SAS rendering scheme for the relayed sashash, which will be the same rendering scheme used by the other party on the other side of the trusted MiTM. - Encrypted - (32 bits) */ uint8_t relayedSasHash[32]; /**< the sashash relayed from the other party. The first 32-bit word of the sashash contains the sasvalue, which may be rendered to the user using the specified SAS rendering scheme. If this SASrelay message is being sent to a ZRTP client that does not trust this MiTM, the sashash will be ignored by the recipient and should be set to zeros by the PBX. - Encrypted - (256 bits) */ uint8_t signatureBlockType; /**< Optionnal signature type : "PGP " or "X509" string - Encrypted - (32 bits) */ uint8_t *signatureBlock; /**< Optionnal signature block as decribded in section 7.2 - Encrypted - (variable length) */ } bzrtpSASRelayMessage_t; /** * @brief Relay ACK Message rfc 5.14 * This message contains no data but only a length and message type which are stored in the bzrtpPacket_t structure * There the no need to define a structure type for this packet */ /** * @brief Ping Message * The Ping and PingACK messages are unrelated to the rest of the ZRTP protocol. No ZRTP endpoint is required to generate a Ping message, but every ZRTP endpoint MUST respond to a Ping message with a PingACK message. */ typedef struct bzrtpPingMessage_struct { uint8_t version[4]; /**< a string defining the current version, shall be 1.10 (32 bits) */ uint8_t endpointHash[8]; /**< see section 5.16 for the endpointHash definition (64 bits) */ } bzrtpPingMessage_t; /** * * @brief PingAck Message * The Ping and PingACK messages are unrelated to the rest of the ZRTP protocol. No ZRTP endpoint is required to generate a Ping message, but every ZRTP endpoint MUST respond to a Ping message with a PingACK message. */ typedef struct bzrtpPingAckMessage_struct { uint8_t version[4]; /**< a string defining the current version, shall be 1.10 (32 bits) */ uint8_t endpointHash[8]; /**< see section 5.16 for the endpointHash definition (64 bits) */ uint8_t endpointHashReceived[8]; /**< the endpoint hash received in the ping Message we're acknowledging (64 bits) */ uint32_t SSRC; /**< the SSRC received in the ping packet we're acknowledging (32 bits) */ } bzrtpPingAckMessage_t; /** * @brief Parse a string which shall be a valid ZRTP packet * Check validity and allocate the bzrtpPacket structure but do not parse the message except for type and length. * messageData structure field is not allocated by this function (use then bzrtp_packetParse for that). * The packet check and actual message parsing are split in two functions to avoid useless parsing when message is * to be discarded as the check will give message type (in case of message repetition for example) * * @param[in] input The string buffer storing the complete ZRTP packet * @param[in] inputLength Input length in bytes * @param[in] lastValidSequenceNumber If the sequence number of this packet is smaller than this param, packet will be discarded * and an error code returned * @param[out] exitCode 0 on success, error code otherwise * * @return The create bzrtpPacket structure(to be freed using bzrtp_freeZrtpPacket). NULL on error */ BZRTP_EXPORT bzrtpPacket_t *bzrtp_packetCheck(const uint8_t * input, uint16_t inputLength, uint16_t lastValidSequenceNumber, int *exitCode); /** * @brief Parse the packet to extract the message and allocate the matching message structure if needed * * @param[in] zrtpContext The current ZRTP context, some parameters(key agreement algorithm) may be needed to parse packet. * @param[in] zrtpChannelContext The channel context this packet is intended to(channel context and packet must match peer SSRC). * @param[in] input The string buffer storing the complete ZRTP packet * @param[in] inputLength Input length in bytes * @param[in] zrtpPacket The zrtpPacket structure allocated by previous call to bzrtpPacketCheck * * @return 0 on sucess, error code otherwise */ BZRTP_EXPORT int bzrtp_packetParser(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext, const uint8_t * input, uint16_t inputLength, bzrtpPacket_t *zrtpPacket); /** * @brief Create an empty packet and allocate the messageData according to requested packetType * * @param[in] zrtpContext The current ZRTP context, some data (H chain or others, may be needed to create messages) * @param[in] zrtpChannelContext The channel context this packet is intended to * @param[in] messageType The 32bit integer mapped to the message type to be created * @param[out] exitCode 0 on success, error code otherwise * * @return An empty packet initialised to get data for the requested paquet tyep. NULL on error */ BZRTP_EXPORT bzrtpPacket_t *bzrtp_createZrtpPacket(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext, uint32_t messageType, int *exitCode); /** * @brief Create a ZRTP packet string from the ZRTP packet values present in the structure * messageType, messageData and sourceIdentifier in zrtpPacket must have been correctly set before calling this function * * @param[in] zrtpContext A zrtp context where to find H0-H3 to compute MAC requested by some paquets or encryption's key for commit/SASRelay packet * @param[in] zrtpChannelContext The channel context this packet is intended to * @param[in/out] zrtpPacket The zrtpPacket structure containing the message Data structure, output is stored in ->packetString * @param[in] sequenceNumber Sequence number of this packet * * @return 0 on success, error code otherwise * */ BZRTP_EXPORT int bzrtp_packetBuild(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext, bzrtpPacket_t *zrtpPacket, uint16_t sequenceNumber); /** * @brief Deallocate zrtp Packet * * @param[in] zrtpPacket The packet to be freed * */ BZRTP_EXPORT void bzrtp_freeZrtpPacket(bzrtpPacket_t *zrtpPacket); /** * @brief Modify the current sequence number of the packet in the packetString and sequenceNumber fields * The CRC at the end of packetString is also updated * * param[in/out] zrtpPacket The zrtpPacket to modify, the packetString must have been generated by * a call to bzrtp_packetBuild on this packet * param[in] sequenceNumber The new sequence number to insert in the packetString * * return 0 on succes, error code otherwise */ BZRTP_EXPORT int bzrtp_packetUpdateSequenceNumber(bzrtpPacket_t *zrtpPacket, uint16_t sequenceNumber); #endif /* PACKETPARSER_H */ bzrtp-1.0.6/include/stateMachine.h000066400000000000000000000164501313411235300170620ustar00rootroot00000000000000/** @file stateMachine.h @brief The state machine implementing the ZRTP protocol Each state is defined as a function pointer and on arrival of a new event after sanity checks, the state function is called giving the event as parameter On a transition, the next state is called with the event which generated the transition @author Johan Pascal @copyright Copyright (C) 2014 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef STATEMACHINE_H #define STATEMACHINE_H #include "typedef.h" /* types definition for event and state function */ /* the INIT event type is used to run some state for the firt time : create packet and send it */ #define BZRTP_EVENT_INIT 0 #define BZRTP_EVENT_MESSAGE 1 #define BZRTP_EVENT_TIMER 2 /* error code definition */ #define BZRTP_ERROR_UNSUPPORTEDZRTPVERSION 0xe001 #define BZRTP_ERROR_UNMATCHINGPACKETREPETITION 0xe002 #define BZRTP_ERROR_CACHEMISMATCH 0xe004 /** * @brief The event type, used as a parameter for the state function */ typedef struct bzrtpEvent_struct { uint8_t eventType; /**< Event can be a message or a timer's end */ uint8_t *bzrtpPacketString; /**< a pointer to the zrtp packet string, NULL in case of timer event */ uint16_t bzrtpPacketStringLength; /**< the length of packet string in bytes */ bzrtpPacket_t *bzrtpPacket; /**< a pointer to the zrtp packet structure created by the processMessage function */ bzrtpContext_t *zrtpContext; /**< the current ZRTP context */ bzrtpChannelContext_t *zrtpChannelContext; /**< the current ZRTP channel hosting this state machine context */ } bzrtpEvent_t; /** * @brief the state function pointer definition */ typedef int (*bzrtpStateMachine_t)(bzrtpEvent_t); /* state functions prototypes, split in categories corresponding to the differents protocol phases: discovery, key agreement, confirmation */ /** * @brief This is the initial state * On first call, we will create the Hello message and start sending it until we receive an helloACK or a hello message from peer * * Arrives from : * - This is the initial state * Goes to: * - state_discovery_waitingForHello upon HelloACK reception * - state_discovery_waitingForHelloAck upon Hello reception * Send : * - Hello until timer's end or transition */ int state_discovery_init(bzrtpEvent_t event); /** * @brief Arrives in this state coming from init upon reception on Hello ACK, we are now waiting for the Hello packet from peer * * Arrives from : * - state_discovery_init upon HelloACK reception * Goes to: * - state_keyAgreement_sendingCommit upon Hello reception * Send : * - HelloACK on Hello reception * */ int state_discovery_waitingForHello(bzrtpEvent_t event); /** * @brief We are now waiting for the HelloACK packet from peer or a Commit packet * * Arrives from : * - state_discovery_init upon Hello reception * Goes to: * - state_keyAgreement_sendingCommit upon HelloACK reception * - state_keyAgreement_responderSendingDHPart1 upon Commit reception in DHM mode * - state_confirmation_responderSendingConfirm1 upon Commit reception in non DHM mode * Send : * - Hello until timer's end or transition * - HelloACK on Hello reception * */ int state_discovery_waitingForHelloAck(bzrtpEvent_t event); /** * @brief For any kind of key agreement (DHM, Mult, PreShared), we keep sending commit. * * Arrives from : * - state_discovery_waitingForHello upon Hello received * - state_discovery_waitingForHelloAck upon HelloACK received * Goes to: * - state_keyAgreement_initiatorSendingDHPart2 upon DHPart1 reception in DHM mode * - state_confirmation_initiatorSendingConfirm2 upon Confirm1 reception in non DHM mode * - state_keyAgreement_responderSendingDHPart1 upon Commit reception in DHM mode and commit contention gives us the responder role * - state_confirmation_responderSendingConfirm1 upon Commit reception in non DHM mode and commit contention gives us the responder role * Send : * - Commit until timer's end or transition * - HelloACK on Hello reception * */ int state_keyAgreement_sendingCommit(bzrtpEvent_t event); /** * @brief For DHM mode only, responder send DHPart1 packet * * Arrives from: * - state_discovery_waitingForHelloAck upon Commit reception in DHM mode * - state_keyAgreement_sendingCommit upon Commit reception in DHM mode and commit contention gives us the responder role * Goes to: * - state_confirmation_responderSendingConfirm1 upon DHPart2 reception * Send : * - DHPart1 on Commit reception * */ int state_keyAgreement_responderSendingDHPart1(bzrtpEvent_t event); /** * @brief For DHM mode only, initiator send DHPart2 packet * * Arrives from: * - state_keyAgreement_sendingCommit upon DHPart1 reception * Goes to: * - state_confirmation_initiatorSendingConfirm2 upon reception of Confirm1 * Send : * - DHPart2 until timer's end or transition * */ int state_keyAgreement_initiatorSendingDHPart2(bzrtpEvent_t event); /** * @brief Responder send the confirm1 message * * Arrives from: * - state_keyAgreement_responderSendingDHPart1 upon DHPart2 reception * - state_keyAgreement_sendingCommit upon Commit reception in non DHM mode and commit contention gives us the responder role * - state_discovery_waitingForHelloAck upon Commit reception in non DHM mode * Goes to: * - state_secure on Confirm2 reception * Send : * - Confirm1 on Commit or DHPart2 reception * */ int state_confirmation_responderSendingConfirm1(bzrtpEvent_t event); /** * @brief Initiator send the confirm2 message * * Arrives from: * - state_keyAgreement_initiatorSendingDHPart2 upon confirm1 reception * - state_keyAgreement_sendingCommit upon Confirm1 reception in non DHM mode * Goes to: * - state_secure on Conf2ACK reception or first SRTP message * Send : * - Confirm2 until timer's end or transition * */ int state_confirmation_initiatorSendingConfirm2(bzrtpEvent_t event); /** * @brief We are in secure state * * Arrives from: * - state_confirmation_responderSendingConfirm1 on Confirm2 reception * - state_confirmation_initiatorSendingConfirm2 on conf2ACK or first SRTP message * Goes to: * - This is the end(we do not support GoClear message), state machine may be destroyed after going to secure mode * Send : * - Conf2ACK on Confirm2 reception * */ int state_secure(bzrtpEvent_t event); /** * @brief Compute the new rs1 and update the cached secrets according to rfc section 4.6.1 * * param[in] zrtpContext The context we are operation on * param[in/out] zrtpChannelContext The channel context we are operation on(contains s0) * * return 0 on success, error code otherwise */ int bzrtp_updateCachedSecrets(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext); #endif /* STATEMACHINE_H */ bzrtp-1.0.6/include/typedef.h000066400000000000000000000351161313411235300161150ustar00rootroot00000000000000/** @file typedef.h @author Johan Pascal @copyright Copyright (C) 2014 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef TYPEDEF_H #define TYPEDEF_H /* maximum number of simultaneous channels opened in a ZRTP session */ #define ZRTP_MAX_CHANNEL_NUMBER 2 /* aux secret may rarely be used define his maximum length in bytes */ #define MAX_AUX_SECRET_LENGTH 64 /* the context will store some of the sent or received packets */ #define PACKET_STORAGE_CAPACITY 4 #define HELLO_MESSAGE_STORE_ID 0 #define COMMIT_MESSAGE_STORE_ID 1 #define DHPART_MESSAGE_STORE_ID 2 #define CONFIRM_MESSAGE_STORE_ID 3 #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #ifdef ZIDCACHE_ENABLED #include "sqlite3.h" #endif /* ZIDCACHE_ENABLED */ typedef struct bzrtpChannelContext_struct bzrtpChannelContext_t; #include #include "packetParser.h" #include "stateMachine.h" /* logging */ #define BCTBX_LOG_DOMAIN "bzrtp" #include "bctoolbox/logging.h" #ifdef _WIN32 #define snprintf _snprintf #endif /* timer related definitions */ #define BZRTP_TIMER_ON 1 #define BZRTP_TIMER_OFF 2 /* values for retransmission timers, as recommended in rfc section 6 */ #define HELLO_BASE_RETRANSMISSION_STEP 50 #define HELLO_CAP_RETRANSMISSION_STEP 200 #define HELLO_MAX_RETRANSMISSION_NUMBER 20 #define NON_HELLO_BASE_RETRANSMISSION_STEP 150 #define NON_HELLO_CAP_RETRANSMISSION_STEP 1200 #define NON_HELLO_MAX_RETRANSMISSION_NUMBER 10 /* Client identifier can contain up to 16 characters, it identify the BZRTP library version */ /* Use it to pass bzrtp version number to peer, is it part of Hello message */ /* custom Linphone Instant Messaging Encryption depends on bzrtp version */ /* Note: ZRTP_VERSION and BZrtp version are for now both at 1.1 but they are unrelated */ /* historically since the creation of bzrtp, it used client idenfiers : */ #define ZRTP_CLIENT_IDENTIFIERv1_0a "LINPHONE-ZRTPCPP" #define ZRTP_CLIENT_IDENTIFIERv1_0b "BZRTP" /* Since version 1.1 which implement correctly the key export mechanism described in ZRTP RFC 4.5.2, bzrtp lib identifies itself as */ #define ZRTP_CLIENT_IDENTIFIERv1_1 "BZRTPv1.1" #define ZRTP_CLIENT_IDENTIFIER ZRTP_CLIENT_IDENTIFIERv1_1 /* pgp word list for use with SAS */ extern const char * pgpWordsEven[]; extern const char * pgpWordsOdd[]; /** * @brief Timer structure : The timer mechanism receives a tick giving a current time in ms * a timer object will check on tick reception if it must fire or not */ typedef struct bzrtpTimer_struct { uint8_t status; /**< Status is BZRTP_TIMER_ON or BZRTP_TIMER_OFF */ uint64_t firingTime; /**< in ms. The timer will fire if currentTime >= firingTime */ uint8_t firingCount; /**< Timer is used to resend packets, count the number of times a packet has been resent */ int timerStep; /**< in ms. Step between next timer fire: used to reset firingTime for next timer fire */ } bzrtpTimer_t; /* the rs1 and rs2 are 256 bits long - see rfc section 4.6.1 */ #define RETAINED_SECRET_LENGTH 32 /** * @brief A set of cached secrets retrieved from the cache as defined */ typedef struct cachedSecrets_struct { uint8_t *rs1; /**< retained secret 1 */ uint8_t rs1Length; /**< retained secret 1 length in bytes */ uint8_t *rs2; /**< retained secret 2 */ uint8_t rs2Length; /**< retained secret 2 length in bytes */ uint8_t *auxsecret; /**< auxiliary secret */ uint8_t auxsecretLength; /**< auxiliary secret length in bytes */ uint8_t *pbxsecret; /**< PBX secret */ uint8_t pbxsecretLength; /**< PBX secret length in bytes */ uint8_t previouslyVerifiedSas; /* boolean, is a SAS has been previously verified with this user */ } cachedSecrets_t; /** * @brief The hash of cached secret truncated to the 64 leftmost bits * aux secret ID is not part of it because channel context dependend while these one are session wise */ typedef struct cachedSecretsHash_struct { uint8_t rs1ID[8]; /**< retained secret 1 Hash */ uint8_t rs2ID[8]; /**< retained secret 2 Hash */ uint8_t pbxsecretID[8]; /**< pbx secret Hash */ } cachedSecretsHash_t; /** * @brief The zrtp context of a channel * */ struct bzrtpChannelContext_struct { void *clientData; /**< this is a pointer provided by the client which is then resent as a parameter of the callbacks functions. Usefull to store RTP session context for example */ uint8_t role;/**< can be INITIATOR or RESPONDER, is set to INITIATOR at creation, may switch to responder later */ bzrtpStateMachine_t stateMachine; /**< The state machine function, holds the current state of the channel: points to the current state function */ bzrtpTimer_t timer; /**< a timer used to manage packets retransmission */ uint32_t selfSSRC; /**< A context is identified by his own SSRC and the peer one */ /* flags */ uint8_t isSecure; /**< This flag is set to 1 when the ZRTP negociation ends and SRTP secrets are generated and confirmed for this channel */ uint8_t isMainChannel; /**< this flag is set for the firt channel only, allow to distinguish channel to be secured using DHM or multiStream */ /* Hash chains, self is generated at channel context init */ uint8_t selfH[4][32]; /**< Store self 256 bits Hash images H0-H3 used to generate messages MAC */ uint8_t peerH[4][32]; /**< Store peer 256 bits Hash images H0-H3 used to check messages authenticity */ /* packet storage : shall store some sent and received packets */ bzrtpPacket_t *selfPackets[PACKET_STORAGE_CAPACITY]; /**< Hello, Commit and DHPart packet locally generated */ bzrtpPacket_t *peerPackets[PACKET_STORAGE_CAPACITY]; /**< Hello, Commit and DHPart packet received from peer */ /* peer Hello hash : store the peer hello hash when given by signaling */ uint8_t *peerHelloHash; /**< peer hello hash - SHA256 of peer Hello packet, given through signaling, shall be a 32 bytes buffer */ /* sequence number: self and peer */ uint16_t selfSequenceNumber; /**< Sequence number of the next packet to be sent */ uint16_t peerSequenceNumber; /**< Sequence number of the last valid received packet */ /* algorithm agreed after Hello message exchange(use mapping define in cryptoWrapper.h) and the function pointer to use them */ uint8_t hashAlgo; /**< hash algorithm agreed on after Hello packet exchange, stored using integer mapping defined in cryptoWrapper.h */ uint8_t hashLength; /**< the length in bytes of a hash generated with the agreed hash algo */ uint8_t cipherAlgo; /**< cipher algorithm agreed on after Hello packet exchange, stored using integer mapping defined in cryptoWrapper.h */ uint8_t cipherKeyLength; /**< the length in bytes of the key needed by the agreed cipher block algo */ uint8_t authTagAlgo; /**< srtp authentication tag algorithm agreed on after Hello packet exchange, stored using integer mapping defined in cryptoWrapper.h */ uint8_t keyAgreementAlgo; /**< key agreement algorithm agreed on after Hello packet exchange, stored using integer mapping defined in cryptoWrapper.h */ uint16_t keyAgreementLength; /**< the length in byte of the secret generated by the agreed key exchange algo */ uint8_t sasAlgo; /**< sas rendering algorithm agreed on after Hello packet exchange, stored using integer mapping defined in cryptoWrapper.h */ uint8_t sasLength; /**< length of the SAS depends on the algorithm agreed */ /* function pointer to the agreed algorithms - Note, key agreement manage directly this selection so it is not set here */ void (*hmacFunction)(const uint8_t *key, size_t keyLength, const uint8_t *input, size_t inputLength, uint8_t hmacLength, uint8_t *output); /**< function pointer to the agreed hmacFunction */ void (*hashFunction)(const uint8_t *input, size_t inputLength, uint8_t hashLength, uint8_t *output); /**< function pointer to the agreed hash function */ void (*cipherEncryptionFunction)(const uint8_t *key, const uint8_t *IV, const uint8_t *input, size_t inputLength, uint8_t *output); /**< function pointer to the agreed cipher block function, encryption mode */ void (*cipherDecryptionFunction)(const uint8_t *key, const uint8_t *IV, const uint8_t *input, size_t inputLength, uint8_t *output); /**< function pointer to the agreed cipher block function, decryption mode */ void (*sasFunction)(uint32_t sas, char * output, int outputSize); /**< function pointer to the agreed sas rendering function */ /* keys */ uint8_t *s0; /**< the s0 as describred rfc section 4.4 - have a length of hashLength */ uint8_t *KDFContext; /**< defined in rfc section 4.4 */ uint16_t KDFContextLength; /**< length of the KDF context, is 24 + output length of the selected hash algo */ uint8_t *mackeyi; /**< the initiator mackey as defined in rfc section 4.5.3 - have a length of hashLength */ uint8_t *mackeyr; /**< the responder mackey as defined in rfc section 4.5.3 - have a length of hashLength*/ uint8_t *zrtpkeyi; /**< the initiator mackey as defined in rfc section 4.5.3 - have a length of cipherKeyLength */ uint8_t *zrtpkeyr; /**< the responder mackey as defined in rfc section 4.5.3 - have a length of cipherKeyLength*/ bzrtpSrtpSecrets_t srtpSecrets; /**< the secrets keys and salt needed by SRTP */ /* shared secret hash : unlike pbx, rs1 and rs2 secret hash, the auxsecret hash use a channel dependent data (H3) and is then stored in the channel context */ uint8_t initiatorAuxsecretID[8]; /**< initiator auxiliary secret Hash */ uint8_t responderAuxsecretID[8]; /**< responder auxiliary secret Hash */ /* temporary buffer stored in the channel context */ bzrtpPacket_t *pingPacket; /**< Temporary stores a ping packet when received to be used to create the pingACK response */ }; /** * @brief structure of the ZRTP engine context * Store current state, timers, HMAC and encryption keys */ struct bzrtpContext_struct { /* contexts */ bctbx_rng_context_t *RNGContext; /**< context for random number generation */ bctbx_DHMContext_t *DHMContext; /**< context for the Diffie-Hellman-Merkle operations. Only one DHM computation may be done during a call, so this belongs to the general context and not the channel one */ /* flags */ uint8_t isInitialised; /**< this flag is set once the context was initialised : self ZID retrieved from cache or generated, used to unlock the creation of addtional channels */ uint8_t isSecure; /**< this flag is set to 1 after the first channel have completed the ZRTP protocol exchange(i.e. when the responder have sent the conf2ACK message), must be set in order to start an additional channel */ uint8_t peerSupportMultiChannel; /**< this flag is set to 1 when the first valid HELLO packet from peer arrives if it support Multichannel ZRTP */ uint64_t timeReference; /**< in ms. This field will set at each channel State Machine start and updated at each tick after creation of the context, it is used to set the firing time of a channel timer */ /* callbacks */ bzrtpCallbacks_t zrtpCallbacks; /**< structure holding all the pointers to callbacks functions needed by the ZRTP engine. Functions are set by client using the bzrtp_setCallback function */ /* channel contexts */ bzrtpChannelContext_t *channelContext[ZRTP_MAX_CHANNEL_NUMBER]; /**< All the context data needed for a channel are stored in a dedicated structure */ /* List of available algorithms, initialised with algo implemented in cryptoWrapper but can be then be modified according to user settings */ uint8_t hc; /**< hash count -zrtpPacket set to 0 means we support only HMAC-SHA256 (4 bits) */ uint8_t supportedHash[7]; /**< list of supported hash algorithms mapped to uint8_t */ uint8_t cc; /**< cipher count - set to 0 means we support only AES128-CFB128 (4 bits) */ uint8_t supportedCipher[7]; /**< list of supported cipher algorithms mapped to uint8_t */ uint8_t ac; /**< auth tag count - set to 0 mean we support only HMAC-SHA1-32 (4 bits) */ uint8_t supportedAuthTag[7]; /**< list of supported SRTP authentication tag algorithms mapped to uint8_t */ uint8_t kc; /**< key agreement count - set to 0 means we support only Diffie-Hellman-Merkle 3072 (4 bits) */ uint8_t supportedKeyAgreement[7]; /**< list of supported key agreement algorithms mapped to uint8_t */ uint8_t sc; /**< sas count - set to 0 means we support only base32 (4 bits) */ uint8_t supportedSas[7]; /**< list of supported Sas representations mapped to uint8_t */ /* ZIDs and cache */ #ifdef ZIDCACHE_ENABLED sqlite3 *zidCache; /**< an sqlite3 db pointer to the zid cache **/ #else void *zidCache; /**< an empty pointer always set to NULL when cache is disabled **/ #endif /* ZIDCACHE_ENABLED */ int zuid; /**< internal id used to address zid cache SIP/ZID pair binding **/ char *selfURI; /**< a null terminated string storing the local user URI **/ uint8_t selfZID[12]; /**< The ZRTP Identifier of this ZRTP end point - a random if running cache less */ char *peerURI; /**< a null terminated string storing the peer user URI **/ uint8_t peerZID[12]; /**< The ZRTP Identifier of the peer ZRTP end point - given by the Hello packet */ uint32_t peerBzrtpVersion; /**< The Bzrtp library version used by peer, retrieved from the peer Hello packet Client identifier and used for backward compatibility in exported key computation */ cachedSecrets_t cachedSecret; /**< the local cached secrets */ cachedSecretsHash_t initiatorCachedSecretHash; /**< The hash of cached secret from initiator side, computed as described in rfc section 4.3.1 */ cachedSecretsHash_t responderCachedSecretHash; /**< The hash of cached secret from responder side, computed as described in rfc section 4.3.1 */ uint8_t cacheMismatchFlag; /**< Flag set in case of cache mismatch(detected in DHM mode when DH part packet arrives) */ uint8_t peerPVS; /**< used to store value of PVS flag sent by peer in the confirm packet on first channel only, then used to compute the PVS value sent to the application */ /* keys */ uint8_t *ZRTPSess; /**< ZRTP session key as described in rfc section 4.5.2 */ uint8_t ZRTPSessLength; /**< length of ZRTP session key depends on agreed hash algorithm */ uint8_t *exportedKey; /**< computed as in rfc section 4.5.2 only if needed */ uint8_t exportedKeyLength; /**< length of previous buffer, shall be channel[0]->hashLength */ }; #endif /* ifndef TYPEDEF_H */ bzrtp-1.0.6/include/zidCache.h000066400000000000000000000036601313411235300161660ustar00rootroot00000000000000/** @file zidCache.h @brief all ZID and cache related operations are implemented in this file - get or create ZID - get/update associated secrets It supports cacheless implementation when cache file access functions are null @author Johan Pascal @copyright Copyright (C) 2017 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef ZIDCACHE_H #define ZIDCACHE_H #include "typedef.h" #define BZRTP_ZIDCACHE_INVALID_CONTEXT 0x2001 #define BZRTP_ZIDCACHE_INVALID_CACHE 0x2002 #define BZRTP_ZIDCACHE_UNABLETOUPDATE 0x2003 #define BZRTP_ZIDCACHE_UNABLETOREAD 0x2004 #define BZRTP_ZIDCACHE_BADINPUTDATA 0x2005 #define BZRTP_ZIDCACHE_RUNTIME_CACHELESS 0x2010 /** * @brief Parse the cache to find secrets associated to the given ZID, set them and their length in the context if they are found * Note: this function also retrieve zuid(set in the context) wich allow successive calls to cache operation to be faster. * * @param[in/out] context the current context, used to get the cache db pointer, self and peer URI and store results * @param[in] peerZID a byte array of the peer ZID * * return 0 on succes, error code otherwise */ BZRTP_EXPORT int bzrtp_getPeerAssociatedSecrets(bzrtpContext_t *context, uint8_t peerZID[12]); #endif /* ZIDCACHE_H */ bzrtp-1.0.6/libbzrtp.pc.in000066400000000000000000000004371313411235300154400ustar00rootroot00000000000000# This is a comment prefix=@prefix@ exec_prefix=@exec_prefix@ includedir=@includedir@ Name: libbzrtp Description: Implement the ZRTP Media Path Key agreement for unicast secure RTP Version: @PACKAGE_VERSION@ Libs: -L@libdir@ -lbzrtp Cflags: -I@includedir@ bzrtp-1.0.6/src/000077500000000000000000000000001313411235300134425ustar00rootroot00000000000000bzrtp-1.0.6/src/CMakeLists.txt000066400000000000000000000057341313411235300162130ustar00rootroot00000000000000############################################################################ # CMakeLists.txt # Copyright (C) 2014 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################################################ set(SOURCE_FILES bzrtp.c cryptoUtils.c packetParser.c pgpwords.c stateMachine.c zidCache.c ) if(POLARSSL_FOUND) list(APPEND SOURCE_FILES cryptoPolarssl.c) elseif(MBEDTLS_FOUND) list(APPEND SOURCE_FILES cryptoMbedtls.c) endif() bc_apply_compile_flags(SOURCE_FILES STRICT_OPTIONS_CPP) set(INCLUDE_DIRS ${BCTOOLBOX_CORE_INCLUDE_DIRS}) set(LIBS ${BCTOOLBOX_CORE_LIBRARIES}) if(SQLITE3_FOUND) list(APPEND INCLUDE_DIRS ${SQLITE3_INCLUDE_DIRS}) list(APPEND LIBS ${SQLITE3_LIBRARIES}) endif() if(XML2_FOUND) list(APPEND INCLUDE_DIRS ${XML2_INCLUDE_DIRS}) list(APPEND LIBS ${XML2_LIBRARIES}) endif() if(ENABLE_STATIC) add_library(bzrtp-static STATIC ${SOURCE_FILES}) set_target_properties(bzrtp-static PROPERTIES OUTPUT_NAME bzrtp) target_include_directories(bzrtp-static PUBLIC ${INCLUDE_DIRS}) target_link_libraries(bzrtp-static INTERFACE ${LIBS}) install(TARGETS bzrtp-static EXPORT ${EXPORT_TARGETS_NAME}Targets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) endif() if(ENABLE_SHARED) add_library(bzrtp SHARED ${SOURCE_FILES}) target_compile_definitions(bzrtp PRIVATE "-DBZRTP_EXPORTS") set_target_properties(bzrtp PROPERTIES VERSION 0) target_include_directories(bzrtp PUBLIC ${INCLUDE_DIRS}) target_link_libraries(bzrtp PRIVATE ${LIBS}) if(MSVC) if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/bzrtp.pdb DESTINATION ${CMAKE_INSTALL_BINDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) endif() endif() install(TARGETS bzrtp EXPORT ${EXPORT_TARGETS_NAME}Targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) endif() bzrtp-1.0.6/src/Makefile.am000066400000000000000000000005551313411235300155030ustar00rootroot00000000000000lib_LTLIBRARIES = libbzrtp.la libbzrtp_la_LIBADD= $(SQLITE3_LIBS) $(LIBXML2_LIBS) $(BCTOOLBOX_LIBS) libbzrtp_la_SOURCES= bzrtp.c cryptoUtils.c packetParser.c zidCache.c stateMachine.c pgpwords.c AM_CPPFLAGS= -I$(top_srcdir)/include AM_CFLAGS= $(LIBXML2_CFLAGS) $(LIBSQLITE3_CFLAGS) $(BCTOOLBOX_CFLAGS) libbzrtp_la_LDFLAGS=-fvisibility=hidden -no-undefined bzrtp-1.0.6/src/bzrtp.c000066400000000000000000001345241313411235300147600ustar00rootroot00000000000000/** @file bzrtp.c @brief Public entry points to the ZRTP implementation @author Johan Pascal @copyright Copyright (C) 2014 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include "bzrtp/bzrtp.h" #include "typedef.h" #include "bctoolbox/crypto.h" #include "cryptoUtils.h" #include "zidCache.h" #include "packetParser.h" #include "stateMachine.h" #define BZRTP_ERROR_INVALIDCHANNELCONTEXT 0x8001 /* local functions prototypes */ static int bzrtp_initChannelContext(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext, uint32_t selfSSRC, uint8_t isMain); static void bzrtp_destroyChannelContext(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext); static bzrtpChannelContext_t *getChannelContext(bzrtpContext_t *zrtpContext, uint32_t selfSSRC); static uint8_t copyCryptoTypes(uint8_t destination[7], uint8_t source[7], uint8_t size); /* * Create context structure and initialise it * * @return The ZRTP engine context data * */ bzrtpContext_t *bzrtp_createBzrtpContext(void) { int i; /*** create and intialise the context structure ***/ bzrtpContext_t *context = malloc(sizeof(bzrtpContext_t)); memset(context, 0, sizeof(bzrtpContext_t)); /* start the random number generator */ context->RNGContext = bctbx_rng_context_new(); /* TODO: give a seed for the RNG? */ /* set the DHM context to NULL, it will be created if needed when creating a DHPart packet */ context->DHMContext = NULL; /* set flags */ context->isSecure = 0; /* start unsecure */ context->peerSupportMultiChannel = 0; /* peer does not support Multichannel by default */ context->isInitialised = 0; /* will be set by bzrtp_initBzrtpContext */ /* set to NULL all callbacks pointer */ context->zrtpCallbacks.bzrtp_sendData = NULL; context->zrtpCallbacks.bzrtp_srtpSecretsAvailable = NULL; context->zrtpCallbacks.bzrtp_startSrtpSession = NULL; context->zrtpCallbacks.bzrtp_contextReadyForExportedKeys = NULL; for (i=1; ichannelContext[i] = NULL; } /* get the list of crypto algorithms provided by the crypto module */ /* this list may then be updated according to users settings */ context->hc = bzrtpUtils_getAvailableCryptoTypes(ZRTP_HASH_TYPE, context->supportedHash); context->cc = bzrtpUtils_getAvailableCryptoTypes(ZRTP_CIPHERBLOCK_TYPE, context->supportedCipher); context->ac = bzrtpUtils_getAvailableCryptoTypes(ZRTP_AUTHTAG_TYPE, context->supportedAuthTag); context->kc = bzrtpUtils_getAvailableCryptoTypes(ZRTP_KEYAGREEMENT_TYPE, context->supportedKeyAgreement); context->sc = bzrtpUtils_getAvailableCryptoTypes(ZRTP_SAS_TYPE, context->supportedSas); /* initialise cached secret buffer to null */ context->zidCache = NULL; /* a pointer to the sqlite3 db accessor, can be NULL if running cacheless */ context->zuid = 0; context->peerBzrtpVersion = 0; context->selfURI = NULL; context->cachedSecret.rs1 = NULL; context->cachedSecret.rs1Length = 0; context->cachedSecret.rs2 = NULL; context->cachedSecret.rs2Length = 0; context->cachedSecret.pbxsecret = NULL; context->cachedSecret.pbxsecretLength = 0; context->cachedSecret.auxsecret = NULL; context->cachedSecret.auxsecretLength = 0; context->cacheMismatchFlag = 0; context->peerPVS = 0; /* initialise key buffers */ context->ZRTPSess = NULL; context->ZRTPSessLength = 0; context->exportedKey = NULL; context->exportedKeyLength = 0; return context; } /** * @brief Set the pointer allowing cache access * * @param[in] zidCachePointer Used by internal function to access cache: turn into a sqlite3 pointer if cache is enabled * * @return 0 or BZRTP_CACHE_SETUP(if cache is populated by this call) on success, error code otherwise */ int bzrtp_setZIDCache(bzrtpContext_t *context, void *zidCache, const char *selfURI, const char *peerURI) { #ifdef ZIDCACHE_ENABLED /* is zrtp context valid */ if (context==NULL) { return BZRTP_ERROR_INVALIDCONTEXT; } /* zidCache pointer is actually a pointer to sqlite3 db, store it in context */ context->zidCache = (sqlite3 *)zidCache; context->selfURI = strdup(selfURI); context->peerURI = strdup(peerURI); /* and init the cache(create needed tables if they don't exist) */ return bzrtp_initCache(context->zidCache); #else /* ZIDCACHE_ENABLED */ return BZRTP_ERROR_CACHEDISABLED; #endif /* ZIDCACHE_ENABLED */ } /** * @brief Perform some initialisation which can't be done without some callback functions: * This function is called once per session when the first channel is created. * It must be called after the cache access pointer have been set * - Get ZID from cache or generate a random ZID * - Initialise the first channel * * @param[in] context The context to initialise * @param[in] selfSSRC SSRC of the first channel * @return 0 on success */ int bzrtp_initBzrtpContext(bzrtpContext_t *context, uint32_t selfSSRC) { /* is zrtp context valid */ if (context==NULL) { return BZRTP_ERROR_INVALIDCONTEXT; } /* initialise self ZID. Randomly generated if no ZID is found in cache or no cache found */ bzrtp_getSelfZID(context->zidCache, context->selfURI, context->selfZID, context->RNGContext); context->isInitialised = 1; /* allocate 1 channel context, set all the others pointers to NULL */ context->channelContext[0] = (bzrtpChannelContext_t *)malloc(sizeof(bzrtpChannelContext_t)); memset(context->channelContext[0], 0, sizeof(bzrtpChannelContext_t)); return bzrtp_initChannelContext(context, context->channelContext[0], selfSSRC, 1); } /* * Free memory of context structure to a channel, if all channels are freed, free the global zrtp context * @param[in] context Context hosting the channel to be destroyed.(note: the context zrtp context itself is destroyed with the last channel) * @param[in] selfSSRC The SSRC identifying the channel to be destroyed * * @return the number of channel still active in this ZRTP context * */ int bzrtp_destroyBzrtpContext(bzrtpContext_t *context, uint32_t selfSSRC) { int i; int validChannelsNumber = 0; if (context == NULL) { return 0; } /* Find the channel to be destroyed, destroy it and check if we have anymore valid channels */ for (i=0; ichannelContext[i] != NULL) { if (context->channelContext[i]->selfSSRC == selfSSRC) { bzrtp_destroyChannelContext(context, context->channelContext[i]); context->channelContext[i] = NULL; } else { validChannelsNumber++; } } } if (validChannelsNumber>0) { return validChannelsNumber; /* we have more valid channels, keep the zrtp context */ } /* We have no more channel, destroy the zrtp context */ /* DHM context shall already been destroyed after s0 computation, but just in case */ if (context->DHMContext != NULL) { bctbx_DestroyDHMContext(context->DHMContext); context->DHMContext = NULL; } /* Destroy keys and secrets */ /* rs1, rs2, pbxsecret and auxsecret shall already been destroyed, just in case */ if (context->cachedSecret.rs1!=NULL) { bzrtp_DestroyKey(context->cachedSecret.rs1, context->cachedSecret.rs1Length, context->RNGContext); free(context->cachedSecret.rs1); context->cachedSecret.rs1 = NULL; } if (context->cachedSecret.rs2!=NULL) { bzrtp_DestroyKey(context->cachedSecret.rs2, context->cachedSecret.rs2Length, context->RNGContext); free(context->cachedSecret.rs2); context->cachedSecret.rs2 = NULL; } if (context->cachedSecret.auxsecret!=NULL) { bzrtp_DestroyKey(context->cachedSecret.auxsecret, context->cachedSecret.auxsecretLength, context->RNGContext); free(context->cachedSecret.auxsecret); context->cachedSecret.auxsecret = NULL; } if (context->cachedSecret.pbxsecret!=NULL) { bzrtp_DestroyKey(context->cachedSecret.pbxsecret, context->cachedSecret.pbxsecretLength, context->RNGContext); free(context->cachedSecret.pbxsecret); context->cachedSecret.pbxsecret = NULL; } if (context->ZRTPSess!=NULL) { bzrtp_DestroyKey(context->ZRTPSess, context->ZRTPSessLength, context->RNGContext); free(context->ZRTPSess); context->ZRTPSess=NULL; } if (context->exportedKey!=NULL) { bzrtp_DestroyKey(context->exportedKey, context->exportedKeyLength, context->RNGContext); free(context->exportedKey); context->ZRTPSess=NULL; } free(context->selfURI); free(context->peerURI); /* destroy the RNG context at the end because it may be needed to destroy some keys */ bctbx_rng_context_free(context->RNGContext); context->RNGContext = NULL; free(context); return 0; } /* * @brief Allocate a function pointer to the callback function identified by his id * @param[in/out] context The zrtp context to set the callback function * @param[in] cbs A structure containing all the callbacks to supply. * * @return 0 on success */ int bzrtp_setCallbacks(bzrtpContext_t *context, const bzrtpCallbacks_t *cbs) { /* is zrtp context valid */ if (context==NULL) { return BZRTP_ERROR_INVALIDCONTEXT; } context->zrtpCallbacks=*cbs; return 0; } /** * @brief Add a channel to an existing context, this can be done only if the first channel has concluded a DH key agreement * * @param[in/out] zrtpContext The zrtp context who will get the additionnal channel. Must be in secure state. * @param[in] selfSSRC The SSRC given to the channel context * * @return 0 on succes, error code otherwise */ int bzrtp_addChannel(bzrtpContext_t *zrtpContext, uint32_t selfSSRC) { bzrtpChannelContext_t *zrtpChannelContext = NULL; int i=0; /* is zrtp context valid */ if (zrtpContext==NULL) { return BZRTP_ERROR_INVALIDCONTEXT; } /* context must be initialised(selfZID available) to enable the creation of an additional channel */ if (zrtpContext->isInitialised == 0) { return BZRTP_ERROR_CONTEXTNOTREADY; } /* get the first free channel context from ZRTP context and create a channel context */ while(ichannelContext[i] == NULL) { int retval; zrtpChannelContext = (bzrtpChannelContext_t *)malloc(sizeof(bzrtpChannelContext_t)); memset(zrtpChannelContext, 0, sizeof(bzrtpChannelContext_t)); retval = bzrtp_initChannelContext(zrtpContext, zrtpChannelContext, selfSSRC, 0); if (retval != 0) { free(zrtpChannelContext); return retval; } } else { i++; } } if (zrtpChannelContext == NULL) { return BZRTP_ERROR_UNABLETOADDCHANNEL; } /* attach the created channel to the ZRTP context */ zrtpContext->channelContext[i] = zrtpChannelContext; return 0; } /* * @brief Start the state machine of the specified channel * * @param[in/out] zrtpContext The ZRTP context hosting the channel to be started * @param[in] selfSSRC The SSRC identifying the channel to be started(will start sending Hello packets and listening for some) * * @return 0 on succes, error code otherwise */ int bzrtp_startChannelEngine(bzrtpContext_t *zrtpContext, uint32_t selfSSRC) { bzrtpEvent_t initEvent; /* get channel context */ bzrtpChannelContext_t *zrtpChannelContext = getChannelContext(zrtpContext, selfSSRC); if (zrtpChannelContext == NULL) { return BZRTP_ERROR_INVALIDCONTEXT; } /* is this channel already started? */ if (zrtpChannelContext->stateMachine != NULL) { return BZRTP_ERROR_CHANNELALREADYSTARTED; } /* if this is an additional channel(not channel 0), we must be sure that channel 0 is already secured */ if (zrtpChannelContext->isMainChannel == 0) { /* is ZRTP context able to add a channel (means channel 0 has already performed the secrets generation) */ if (zrtpContext->isSecure == 0) { return BZRTP_ERROR_CONTEXTNOTREADY; } /* check the peer support Multichannel(shall be set in the first Hello message received) */ if (zrtpContext->peerSupportMultiChannel == 0) { return BZRTP_ERROR_MULTICHANNELNOTSUPPORTEDBYPEER; } } /* set the timer reference to 0 to force a message to be sent at first timer tick */ zrtpContext->timeReference = 0; /* start the engine by setting the state to init and calling it */ zrtpChannelContext->stateMachine = state_discovery_init; /* create an INIT event to call the init state function which will create a hello packet and start sending it */ initEvent.eventType = BZRTP_EVENT_INIT; initEvent.bzrtpPacketString = NULL; initEvent.bzrtpPacketStringLength = 0; initEvent.zrtpContext = zrtpContext; initEvent.zrtpChannelContext = zrtpChannelContext; return zrtpChannelContext->stateMachine(initEvent); } /* * @brief Send the current time to a specified channel, it will check if it has to trig some timer * * @param[in/out] zrtpContext The ZRTP context hosting the channel * @param[in] selfSSRC The SSRC identifying the channel * @param[in] timeReference The current time in ms * * @return 0 on succes, error code otherwise */ int bzrtp_iterate(bzrtpContext_t *zrtpContext, uint32_t selfSSRC, uint64_t timeReference) { /* get channel context */ bzrtpChannelContext_t *zrtpChannelContext = getChannelContext(zrtpContext, selfSSRC); if (zrtpChannelContext == NULL) { return BZRTP_ERROR_INVALIDCONTEXT; } /* update the context time reference used when arming timers */ zrtpContext->timeReference = timeReference; if (zrtpChannelContext->timer.status == BZRTP_TIMER_ON) { if (zrtpChannelContext->timer.firingTime<=timeReference) { /* we must trig the timer */ bzrtpEvent_t timerEvent; zrtpChannelContext->timer.firingCount++; /* create a timer event */ timerEvent.eventType = BZRTP_EVENT_TIMER; timerEvent.bzrtpPacketString = NULL; timerEvent.bzrtpPacketStringLength = 0; timerEvent.bzrtpPacket = NULL; timerEvent.zrtpContext = zrtpContext; timerEvent.zrtpChannelContext = zrtpChannelContext; /* send it to the state machine*/ if (zrtpChannelContext->stateMachine != NULL) { return zrtpChannelContext->stateMachine(timerEvent); } } } return 0; } /* * @brief Set the client data pointer in a channel context * This pointer is returned to the client by the callbacks function, used to store associated contexts (RTP session) * @param[in/out] zrtpContext The ZRTP context we're dealing with * @param[in] selfSSRC The SSRC identifying the channel to be linked to the client Data * @param[in] clientData The clientData pointer, casted to a (void *) * * @return 0 on success * */ int bzrtp_setClientData(bzrtpContext_t *zrtpContext, uint32_t selfSSRC, void *clientData) { /* get channel context */ bzrtpChannelContext_t *zrtpChannelContext = getChannelContext(zrtpContext, selfSSRC); if (zrtpChannelContext == NULL) { return BZRTP_ERROR_INVALIDCONTEXT; } zrtpChannelContext->clientData = clientData; return 0; } /* * @brief Process a received message * * @param[in/out] zrtpContext The ZRTP context we're dealing with * @param[in] selfSSRC The SSRC identifying the channel receiving the message * @param[in] zrtpPacketString The packet received * @param[in] zrtpPacketStringLength Length of the packet in bytes * * @return 0 on success, errorcode otherwise */ int bzrtp_processMessage(bzrtpContext_t *zrtpContext, uint32_t selfSSRC, uint8_t *zrtpPacketString, uint16_t zrtpPacketStringLength) { int retval; bzrtpPacket_t *zrtpPacket; bzrtpEvent_t event; /* get channel context */ bzrtpChannelContext_t *zrtpChannelContext = getChannelContext(zrtpContext, selfSSRC); if (zrtpChannelContext == NULL) { return BZRTP_ERROR_INVALIDCONTEXT; } /* check the context is initialised (we may receive packets before initialisation is complete i.e. between channel initialisation and channel start) */ if (zrtpChannelContext->stateMachine == NULL) { return BZRTP_ERROR_INVALIDCONTEXT; /* drop the message */ } /* first check the packet */ zrtpPacket = bzrtp_packetCheck(zrtpPacketString, zrtpPacketStringLength, zrtpChannelContext->peerSequenceNumber, &retval); if (retval != 0) { /*TODO: check the returned error code and do something or silent drop? */ return retval; } /* TODO: Intercept error and ping zrtp packets */ /* if we have a ping packet, just answer with a ping ACK and do not forward to the state machine */ if (zrtpPacket->messageType == MSGTYPE_PING) { bzrtpPacket_t *pingAckPacket = NULL; bzrtp_packetParser(zrtpContext, zrtpChannelContext, zrtpPacketString, zrtpPacketStringLength, zrtpPacket); /* store ping packet in the channel context as packet creator will need it to create the pingACK */ zrtpChannelContext->pingPacket = zrtpPacket; /* create the pingAck packet */ pingAckPacket = bzrtp_createZrtpPacket(zrtpContext, zrtpChannelContext, MSGTYPE_PINGACK, &retval); if (retval == 0) { retval = bzrtp_packetBuild(zrtpContext, zrtpChannelContext, pingAckPacket, zrtpChannelContext->selfSequenceNumber); if (retval==0 && zrtpContext->zrtpCallbacks.bzrtp_sendData!=NULL) { /* send the packet */ zrtpContext->zrtpCallbacks.bzrtp_sendData(zrtpChannelContext->clientData, pingAckPacket->packetString, pingAckPacket->messageLength+ZRTP_PACKET_OVERHEAD); zrtpChannelContext->selfSequenceNumber++; } } /* free packets and reset channel context storage */ bzrtp_freeZrtpPacket(zrtpPacket); bzrtp_freeZrtpPacket(pingAckPacket); zrtpChannelContext->pingPacket = NULL; return retval; } /* build a packet event of it and send it to the state machine */ event.eventType = BZRTP_EVENT_MESSAGE; event.bzrtpPacketString = zrtpPacketString; event.bzrtpPacketStringLength = zrtpPacketStringLength; event.bzrtpPacket = zrtpPacket; event.zrtpContext = zrtpContext; event.zrtpChannelContext = zrtpChannelContext; return zrtpChannelContext->stateMachine(event); } /* * @brief Called by user when the SAS has been verified * update the cache(if any) to set the previously verified flag * * @param[in/out] zrtpContext The ZRTP context we're dealing with */ void bzrtp_SASVerified(bzrtpContext_t *zrtpContext) { if (zrtpContext != NULL) { uint8_t pvsFlag = 1; char *colNames[] = {"pvs"}; uint8_t *colValues[] = {&pvsFlag}; size_t colLength[] = {1}; /* check if we must update the cache(delayed until sas verified in case of cache mismatch) */ if (zrtpContext->cacheMismatchFlag == 1) { zrtpContext->cacheMismatchFlag = 0; bzrtp_updateCachedSecrets(zrtpContext, zrtpContext->channelContext[0]); /* channel[0] is the only one in DHM mode, so the only one able to have a cache mismatch */ } bzrtp_cache_write(zrtpContext->zidCache, zrtpContext->zuid, "zrtp", colNames, colValues, colLength, 1); } } /* * @brief Called by user when the SAS has been set to unverified * update the cache(if any) to unset the previously verified flag * * @param[in/out] zrtpContext The ZRTP context we're dealing with */ void bzrtp_resetSASVerified(bzrtpContext_t *zrtpContext) { if (zrtpContext != NULL) { uint8_t pvsFlag = 0; char *colNames[] = {"pvs"}; uint8_t *colValues[] = {&pvsFlag}; size_t colLength[] = {1}; bzrtp_cache_write(zrtpContext->zidCache, zrtpContext->zuid, "zrtp", colNames, colValues, colLength, 1); } } /* * @brief Allow client to compute an exported according to RFC section 4.5.2 * Check the context is ready(we already have a master exported key and KDF context) * and run KDF(master exported key, "Label", KDF_Context, negotiated hash Length) * * @param[in] zrtpContext The ZRTP context we're dealing with * @param[in] label Label used in the KDF * @param[in] labelLength Length of previous buffer * @param[out] derivedKey Buffer to store the derived key * @param[in/out] derivedKeyLength Length of previous buffer(updated to fit actual length of data produced if too long) * * @return 0 on succes, error code otherwise */ int bzrtp_exportKey(bzrtpContext_t *zrtpContext, char *label, size_t labelLength, uint8_t *derivedKey, size_t *derivedKeyLength) { /* check we have s0 or exportedKey and KDFContext in channel[0] - export keys is available only on channel 0 completion - see RFC 4.5.2 */ bzrtpChannelContext_t *zrtpChannelContext = zrtpContext->channelContext[0]; if (zrtpContext->peerBzrtpVersion == 10000) { /* keep compatibility with older implementation of bzrtp */ /* before version 1.1.0 (turned into an int MMmmpp -> 010100) exported keys wrongly derives from given label and s0 direclty instead of deriving one Exported Key from S0 and then as many as needed from the exported key as specified in the RFC section 4.5.2 */ if (zrtpChannelContext->s0 == NULL || zrtpChannelContext->KDFContext == NULL) { return BZRTP_ERROR_INVALIDCONTEXT; } /* We derive a maximum of hashLength bytes */ if (*derivedKeyLength > zrtpChannelContext->hashLength) { *derivedKeyLength = zrtpChannelContext->hashLength; } bzrtp_keyDerivationFunction(zrtpChannelContext->s0, zrtpChannelContext->hashLength, (uint8_t *)label, labelLength, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, *derivedKeyLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, derivedKey); } else { /* peer either use version 1.1 of BZRTP or another library, just stick to the RFC to create the export key */ if ((zrtpChannelContext->s0 == NULL && zrtpContext->exportedKey) || zrtpChannelContext->KDFContext == NULL) { return BZRTP_ERROR_INVALIDCONTEXT; } /* if we didn't already computed the master exported key, do it now */ if (zrtpContext->exportedKey == NULL) { zrtpContext->exportedKeyLength = zrtpChannelContext->hashLength; zrtpContext->exportedKey = (uint8_t *)malloc(zrtpContext->exportedKeyLength*sizeof(uint8_t)); bzrtp_keyDerivationFunction(zrtpChannelContext->s0, zrtpChannelContext->hashLength, (uint8_t *)"Exported key", 12, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, zrtpContext->exportedKeyLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, zrtpContext->exportedKey); } /* We derive a maximum of hashLength bytes */ if (*derivedKeyLength > zrtpChannelContext->hashLength) { *derivedKeyLength = zrtpChannelContext->hashLength; } bzrtp_keyDerivationFunction(zrtpContext->exportedKey, zrtpChannelContext->hashLength, (uint8_t *)label, labelLength, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, *derivedKeyLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, derivedKey); } return 0; } /* * @brief Reset the retransmission timer of a given channel. * Packets will be sent again if appropriate: * - when in responder role, zrtp engine only answer to packets sent by the initiator. * - if we are still in discovery phase, Hello or Commit packets will be resent. * * @param[in/out] zrtpContext The ZRTP context we're dealing with * @param[in] selfSSRC The SSRC identifying the channel to reset * * return 0 on success, error code otherwise */ int bzrtp_resetRetransmissionTimer(bzrtpContext_t *zrtpContext, uint32_t selfSSRC) { /* get channel context */ bzrtpChannelContext_t *zrtpChannelContext = getChannelContext(zrtpContext, selfSSRC); if (zrtpChannelContext == NULL) { return BZRTP_ERROR_INVALIDCONTEXT; } /* reset timer only when not in secure mode yet and for initiator(engine start as initiator so if we call this function in discovery phase, it will reset the timer */ if ((zrtpChannelContext->isSecure == 0) && (zrtpChannelContext->role == BZRTP_ROLE_INITIATOR)) { zrtpChannelContext->timer.status = BZRTP_TIMER_ON; zrtpChannelContext->timer.firingTime = 0; /* be sure it will trigger at next call to bzrtp_iterate*/ zrtpChannelContext->timer.firingCount = -1; /* -1 to count the initial packet and then retransmit the regular number of packets */ /* reset timerStep to the base value */ if ((zrtpChannelContext->timer.timerStep % NON_HELLO_BASE_RETRANSMISSION_STEP) == 0) { zrtpChannelContext->timer.timerStep = NON_HELLO_BASE_RETRANSMISSION_STEP; } else { zrtpChannelContext->timer.timerStep = HELLO_BASE_RETRANSMISSION_STEP; } } return 0; } /** * @brief Get the supported crypto types * * @param[int] zrtpContext The ZRTP context we're dealing with * @param[in] algoType mapped to defines, must be in [ZRTP_HASH_TYPE, ZRTP_CIPHERBLOCK_TYPE, ZRTP_AUTHTAG_TYPE, ZRTP_KEYAGREEMENT_TYPE or ZRTP_SAS_TYPE] * @param[out] supportedTypes mapped to uint8_t value of the 4 char strings giving the supported types as string according to rfc section 5.1.2 to 5.1.6 * * @return number of supported types, 0 on error */ uint8_t bzrtp_getSupportedCryptoTypes(bzrtpContext_t *zrtpContext, uint8_t algoType, uint8_t supportedTypes[7]) { if (zrtpContext==NULL) { return 0; } switch(algoType) { case ZRTP_HASH_TYPE: return copyCryptoTypes(supportedTypes, zrtpContext->supportedHash, zrtpContext->hc); case ZRTP_CIPHERBLOCK_TYPE: return copyCryptoTypes(supportedTypes, zrtpContext->supportedCipher, zrtpContext->cc); case ZRTP_AUTHTAG_TYPE: return copyCryptoTypes(supportedTypes, zrtpContext->supportedAuthTag, zrtpContext->ac); case ZRTP_KEYAGREEMENT_TYPE: return copyCryptoTypes(supportedTypes, zrtpContext->supportedKeyAgreement, zrtpContext->kc); case ZRTP_SAS_TYPE: return copyCryptoTypes(supportedTypes, zrtpContext->supportedSas, zrtpContext->sc); default: return 0; } } /** * @brief set the supported crypto types * * @param[int/out] zrtpContext The ZRTP context we're dealing with * @param[in] algoType mapped to defines, must be in [ZRTP_HASH_TYPE, ZRTP_CIPHERBLOCK_TYPE, ZRTP_AUTHTAG_TYPE, ZRTP_KEYAGREEMENT_TYPE or ZRTP_SAS_TYPE] * @param[in] supportedTypes mapped to uint8_t value of the 4 char strings giving the supported types as string according to rfc section 5.1.2 to 5.1.6 * @param[in] supportedTypesCount number of supported crypto types */ void bzrtp_setSupportedCryptoTypes(bzrtpContext_t *zrtpContext, uint8_t algoType, uint8_t supportedTypes[7], uint8_t supportedTypesCount) { uint8_t implementedTypes[7]; uint8_t implementedTypesCount; if (zrtpContext==NULL) { return; } implementedTypesCount = bzrtpUtils_getAvailableCryptoTypes(algoType, implementedTypes); switch(algoType) { case ZRTP_HASH_TYPE: zrtpContext->hc = selectCommonAlgo(supportedTypes, supportedTypesCount, implementedTypes, implementedTypesCount, zrtpContext->supportedHash); bzrtp_addMandatoryCryptoTypesIfNeeded(algoType, zrtpContext->supportedHash, &zrtpContext->hc); break; case ZRTP_CIPHERBLOCK_TYPE: zrtpContext->cc = selectCommonAlgo(supportedTypes, supportedTypesCount, implementedTypes, implementedTypesCount, zrtpContext->supportedCipher); bzrtp_addMandatoryCryptoTypesIfNeeded(algoType, zrtpContext->supportedCipher, &zrtpContext->cc); break; case ZRTP_AUTHTAG_TYPE: zrtpContext->ac = selectCommonAlgo(supportedTypes, supportedTypesCount, implementedTypes, implementedTypesCount, zrtpContext->supportedAuthTag); bzrtp_addMandatoryCryptoTypesIfNeeded(algoType, zrtpContext->supportedAuthTag, &zrtpContext->ac); break; case ZRTP_KEYAGREEMENT_TYPE: zrtpContext->kc = selectCommonAlgo(supportedTypes, supportedTypesCount, implementedTypes, implementedTypesCount, zrtpContext->supportedKeyAgreement); bzrtp_addMandatoryCryptoTypesIfNeeded(algoType, zrtpContext->supportedKeyAgreement, &zrtpContext->kc); break; case ZRTP_SAS_TYPE: zrtpContext->sc = selectCommonAlgo(supportedTypes, supportedTypesCount, implementedTypes, implementedTypesCount, zrtpContext->supportedSas); bzrtp_addMandatoryCryptoTypesIfNeeded(algoType, zrtpContext->supportedSas, &zrtpContext->sc); break; } } /** * @brief Set the peer hello hash given by signaling to a ZRTP channel * * @param[in/out] zrtpContext The ZRTP context we're dealing with * @param[in] selfSSRC The SSRC identifying the channel * @param[out] peerHelloHashHexString A NULL terminated string containing the hexadecimal form of the hash received in signaling, * may contain ZRTP version as header. * @param[in] peerHelloHashHexStringLength Length of hash string (shall be at least 64 as the hash is a SHA256 so 32 bytes, * more if it contains the version header) * * @return 0 on success, errorcode otherwise */ int bzrtp_setPeerHelloHash(bzrtpContext_t *zrtpContext, uint32_t selfSSRC, uint8_t *peerHelloHashHexString, size_t peerHelloHashHexStringLength) { size_t i=0; uint8_t *hexHashString = NULL; size_t hexHashStringLength = peerHelloHashHexStringLength; /* get channel context */ bzrtpChannelContext_t *zrtpChannelContext = getChannelContext(zrtpContext, selfSSRC); if (zrtpChannelContext == NULL) { return BZRTP_ERROR_INVALIDCONTEXT; } /* parse the given peerHelloHash, it may formatted or just */ /* just ignore anything(we do not care about version number) before a ' ' if found */ while (hexHashString==NULL && ipeerHelloHash) { free(zrtpChannelContext->peerHelloHash); } zrtpChannelContext->peerHelloHash = (uint8_t *)malloc(hexHashStringLength/2*sizeof(uint8_t)); /* convert to uint8 the hex string */ bzrtp_strToUint8(zrtpChannelContext->peerHelloHash, hexHashString, hexHashStringLength); /* Do we already have the peer Hello packet, if yes, check it match the hash */ if (zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID] != NULL) { uint8_t computedPeerHelloHash[32]; /* compute hash using implicit hash function: SHA256, skip packet header in the packetString buffer as the hash must be computed on message only */ bctbx_sha256(zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->messageLength, 32, computedPeerHelloHash); /* check they are the same */ if (memcmp(computedPeerHelloHash, zrtpChannelContext->peerHelloHash, 32)!=0) { /* a session already started on this channel but with a wrong Hello we must reset and restart it */ /* note: caller may decide to abort the ZRTP session */ /* reset state Machine */ zrtpChannelContext->stateMachine = NULL; /* set timer off */ zrtpChannelContext->timer.status = BZRTP_TIMER_OFF; /* destroy and free the key buffers */ bzrtp_DestroyKey(zrtpChannelContext->s0, zrtpChannelContext->hashLength, zrtpContext->RNGContext); bzrtp_DestroyKey(zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, zrtpContext->RNGContext); bzrtp_DestroyKey(zrtpChannelContext->mackeyi, zrtpChannelContext->hashLength, zrtpContext->RNGContext); bzrtp_DestroyKey(zrtpChannelContext->mackeyr, zrtpChannelContext->hashLength, zrtpContext->RNGContext); bzrtp_DestroyKey(zrtpChannelContext->zrtpkeyi, zrtpChannelContext->cipherKeyLength, zrtpContext->RNGContext); bzrtp_DestroyKey(zrtpChannelContext->zrtpkeyr, zrtpChannelContext->cipherKeyLength, zrtpContext->RNGContext); free(zrtpChannelContext->s0); free(zrtpChannelContext->KDFContext); free(zrtpChannelContext->mackeyi); free(zrtpChannelContext->mackeyr); free(zrtpChannelContext->zrtpkeyi); free(zrtpChannelContext->zrtpkeyr); zrtpChannelContext->s0=NULL; zrtpChannelContext->KDFContext=NULL; zrtpChannelContext->mackeyi=NULL; zrtpChannelContext->mackeyr=NULL; zrtpChannelContext->zrtpkeyi=NULL; zrtpChannelContext->zrtpkeyr=NULL; /* free the allocated buffers but not our self Hello packet */ for (i=0; iselfPackets[i]); zrtpChannelContext->selfPackets[i] = NULL; } bzrtp_freeZrtpPacket(zrtpChannelContext->peerPackets[i]); zrtpChannelContext->peerPackets[i] = NULL; } /* destroy and free the srtp and sas struture */ bzrtp_DestroyKey(zrtpChannelContext->srtpSecrets.selfSrtpKey, zrtpChannelContext->srtpSecrets.selfSrtpKeyLength, zrtpContext->RNGContext); bzrtp_DestroyKey(zrtpChannelContext->srtpSecrets.selfSrtpSalt, zrtpChannelContext->srtpSecrets.selfSrtpSaltLength, zrtpContext->RNGContext); bzrtp_DestroyKey(zrtpChannelContext->srtpSecrets.peerSrtpKey, zrtpChannelContext->srtpSecrets.peerSrtpKeyLength, zrtpContext->RNGContext); bzrtp_DestroyKey(zrtpChannelContext->srtpSecrets.peerSrtpSalt, zrtpChannelContext->srtpSecrets.peerSrtpSaltLength, zrtpContext->RNGContext); bzrtp_DestroyKey((uint8_t *)zrtpChannelContext->srtpSecrets.sas, zrtpChannelContext->srtpSecrets.sasLength, zrtpContext->RNGContext); free(zrtpChannelContext->srtpSecrets.selfSrtpKey); free(zrtpChannelContext->srtpSecrets.selfSrtpSalt); free(zrtpChannelContext->srtpSecrets.peerSrtpKey); free(zrtpChannelContext->srtpSecrets.peerSrtpSalt); free(zrtpChannelContext->srtpSecrets.sas); /* re-initialise srtpSecrets structure */ zrtpChannelContext->srtpSecrets.selfSrtpKey = NULL; zrtpChannelContext->srtpSecrets.selfSrtpSalt = NULL; zrtpChannelContext->srtpSecrets.peerSrtpKey = NULL; zrtpChannelContext->srtpSecrets.peerSrtpSalt = NULL; zrtpChannelContext->srtpSecrets.selfSrtpKeyLength = 0; zrtpChannelContext->srtpSecrets.selfSrtpSaltLength = 0; zrtpChannelContext->srtpSecrets.peerSrtpKeyLength = 0; zrtpChannelContext->srtpSecrets.peerSrtpSaltLength = 0; zrtpChannelContext->srtpSecrets.cipherAlgo = ZRTP_UNSET_ALGO; zrtpChannelContext->srtpSecrets.cipherKeyLength = 0; zrtpChannelContext->srtpSecrets.authTagAlgo = ZRTP_UNSET_ALGO; zrtpChannelContext->srtpSecrets.sas = NULL; zrtpChannelContext->srtpSecrets.sasLength = 0; zrtpChannelContext->srtpSecrets.hashAlgo = ZRTP_UNSET_ALGO; zrtpChannelContext->srtpSecrets.keyAgreementAlgo = ZRTP_UNSET_ALGO; zrtpChannelContext->srtpSecrets.sasAlgo = ZRTP_UNSET_ALGO; /* reset choosen algo and their functions */ zrtpChannelContext->hashAlgo = ZRTP_UNSET_ALGO; zrtpChannelContext->cipherAlgo = ZRTP_UNSET_ALGO; zrtpChannelContext->authTagAlgo = ZRTP_UNSET_ALGO; zrtpChannelContext->keyAgreementAlgo = ZRTP_UNSET_ALGO; zrtpChannelContext->sasAlgo = ZRTP_UNSET_ALGO; bzrtp_updateCryptoFunctionPointers(zrtpChannelContext); /* restart channel */ bzrtp_startChannelEngine(zrtpContext, selfSSRC); return BZRTP_ERROR_HELLOHASH_MISMATCH; } } return 0; } /** * @brief Get the self hello hash from ZRTP channel * * @param[in/out] zrtpContext The ZRTP context we're dealing with * @param[in] selfSSRC The SSRC identifying the channel * @param[out] output A NULL terminated string containing the hexadecimal form of the hash received in signaling, * contain ZRTP version as header. Buffer must be allocated by caller. * @param[in] outputLength Length of output buffer, shall be at least 70 : 5 chars for version, 64 for the hash itself, SHA256), NULL termination * * @return 0 on success, errorcode otherwise */ int bzrtp_getSelfHelloHash(bzrtpContext_t *zrtpContext, uint32_t selfSSRC, uint8_t *output, size_t outputLength) { uint8_t helloHash[32]; /* get channel context */ bzrtpChannelContext_t *zrtpChannelContext = getChannelContext(zrtpContext, selfSSRC); if (zrtpChannelContext == NULL) { return BZRTP_ERROR_INVALIDCONTEXT; } /* check we have the Hello packet in context */ if (zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID] == NULL) { return BZRTP_ERROR_CONTEXTNOTREADY; } /* check output length : version length +' '+64 hex hash + null termination */ if (outputLength < strlen(ZRTP_VERSION)+1+64+1) { return BZRTP_ERROR_OUTPUTBUFFER_LENGTH; } /* compute hash using implicit hash function: SHA256, skip packet header in the packetString buffer as the hash must be computed on message only */ bctbx_sha256(zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID]->messageLength, 32, helloHash); /* add version header */ strcpy((char *)output, ZRTP_VERSION); output[strlen(ZRTP_VERSION)]=' '; /* convert hash to hex string and set it in the output buffer */ bzrtp_int8ToStr(output+strlen(ZRTP_VERSION)+1, helloHash, 32); /* add NULL termination */ output[strlen(ZRTP_VERSION)+1+64]='\0'; return 0; } /** * @brief Get the channel status * * @param[in] zrtpContext The ZRTP context we're dealing with * @param[in] selfSSRC The SSRC identifying the channel * * @return BZRTP_CHANNEL_NOTFOUND no channel matching this SSRC doesn't exists in the zrtp context * BZRTP_CHANNEL_INITIALISED channel initialised but not started * BZRTP_CHANNEL_ONGOING ZRTP key exchange in ongoing * BZRTP_CHANNEL_SECURE Channel is secure * BZRTP_CHANNEL_ERROR An error occured on this channel */ int bzrtp_getChannelStatus(bzrtpContext_t *zrtpContext, uint32_t selfSSRC) { /* get channel context */ bzrtpChannelContext_t *zrtpChannelContext = getChannelContext(zrtpContext, selfSSRC); if (zrtpChannelContext == NULL) { return BZRTP_CHANNEL_NOTFOUND; } if (zrtpChannelContext->stateMachine == NULL) { return BZRTP_CHANNEL_INITIALISED; } if (zrtpChannelContext->isSecure == 1) { return BZRTP_CHANNEL_SECURE; } return BZRTP_CHANNEL_ONGOING; } /* Local functions implementation */ /** * @brief Look in the given ZRTP context for a channel referenced with given SSRC * * @param[in] zrtpContext The zrtp context which shall contain the channel context we are looking for * @param[in] selfSSRC The SSRC identifying the channel context * * @return a pointer to the channel context, NULL if the context is invalid or channel not found */ static bzrtpChannelContext_t *getChannelContext(bzrtpContext_t *zrtpContext, uint32_t selfSSRC) { int i; if (zrtpContext==NULL) { return NULL; } for (i=0; ichannelContext[i]!=NULL) { if (zrtpContext->channelContext[i]->selfSSRC == selfSSRC) { return zrtpContext->channelContext[i]; } } } return NULL; /* found no channel with this SSRC */ } /** * @brief Initialise the context of a channel and create and store the Hello packet * Initialise some vectors * * @param[in] zrtpContext The zrtpContext hosting this channel, needed to acces the RNG * @param[out] zrtpChanneContext The channel context to be initialised * @param[in] selfSSRC The SSRC allocated to this channel * @param[in] isMain This channel is channel 0 or an additional channel * * @return 0 on success, error code otherwise */ static int bzrtp_initChannelContext(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext, uint32_t selfSSRC, uint8_t isMain) { int i; int retval; bzrtpPacket_t *helloPacket; if (zrtpChannelContext == NULL) { return BZRTP_ERROR_INVALIDCHANNELCONTEXT; } zrtpChannelContext->clientData = NULL; /* the state machine is not started at the creation of the channel but on explicit call to the start function */ zrtpChannelContext->stateMachine = NULL; /* timer is off */ zrtpChannelContext->timer.status = BZRTP_TIMER_OFF; zrtpChannelContext->timer.timerStep = HELLO_BASE_RETRANSMISSION_STEP; /* we must initialise the timeStep just in case the resettimer function is called between init and start */ zrtpChannelContext->selfSSRC = selfSSRC; /* flags */ zrtpChannelContext->isSecure = 0; zrtpChannelContext->isMainChannel = isMain; /* initialise as initiator, switch to responder later if needed */ zrtpChannelContext->role = BZRTP_ROLE_INITIATOR; /* create H0 (32 bytes random) and derive using implicit Hash(SHA256) H1,H2,H3 */ bctbx_rng_get(zrtpContext->RNGContext, zrtpChannelContext->selfH[0], 32); bctbx_sha256(zrtpChannelContext->selfH[0], 32, 32, zrtpChannelContext->selfH[1]); bctbx_sha256(zrtpChannelContext->selfH[1], 32, 32, zrtpChannelContext->selfH[2]); bctbx_sha256(zrtpChannelContext->selfH[2], 32, 32, zrtpChannelContext->selfH[3]); /* initialisation of packet storage */ for (i=0; iselfPackets[i] = NULL; zrtpChannelContext->peerPackets[i] = NULL; } zrtpChannelContext->peerHelloHash = NULL; /* initialise the self Sequence number to a random and peer to 0 */ bctbx_rng_get(zrtpContext->RNGContext, (uint8_t *)&(zrtpChannelContext->selfSequenceNumber), 2); zrtpChannelContext->selfSequenceNumber &= 0x0FFF; /* first 4 bits to zero in order to avoid reaching FFFF and turning back to 0 */ zrtpChannelContext->selfSequenceNumber++; /* be sure it is not initialised to 0 */ zrtpChannelContext->peerSequenceNumber = 0; /* reset choosen algo and their functions */ zrtpChannelContext->hashAlgo = ZRTP_UNSET_ALGO; zrtpChannelContext->cipherAlgo = ZRTP_UNSET_ALGO; zrtpChannelContext->authTagAlgo = ZRTP_UNSET_ALGO; zrtpChannelContext->keyAgreementAlgo = ZRTP_UNSET_ALGO; zrtpChannelContext->sasAlgo = ZRTP_UNSET_ALGO; bzrtp_updateCryptoFunctionPointers(zrtpChannelContext); /* initialise key buffers */ zrtpChannelContext->s0 = NULL; zrtpChannelContext->KDFContext = NULL; zrtpChannelContext->KDFContextLength = 0; zrtpChannelContext->mackeyi = NULL; zrtpChannelContext->mackeyr = NULL; zrtpChannelContext->zrtpkeyi = NULL; zrtpChannelContext->zrtpkeyr = NULL; /* initialise srtpSecrets structure */ zrtpChannelContext->srtpSecrets.selfSrtpKey = NULL; zrtpChannelContext->srtpSecrets.selfSrtpSalt = NULL; zrtpChannelContext->srtpSecrets.peerSrtpKey = NULL; zrtpChannelContext->srtpSecrets.peerSrtpSalt = NULL; zrtpChannelContext->srtpSecrets.selfSrtpKeyLength = 0; zrtpChannelContext->srtpSecrets.selfSrtpSaltLength = 0; zrtpChannelContext->srtpSecrets.peerSrtpKeyLength = 0; zrtpChannelContext->srtpSecrets.peerSrtpSaltLength = 0; zrtpChannelContext->srtpSecrets.cipherAlgo = ZRTP_UNSET_ALGO; zrtpChannelContext->srtpSecrets.cipherKeyLength = 0; zrtpChannelContext->srtpSecrets.authTagAlgo = ZRTP_UNSET_ALGO; zrtpChannelContext->srtpSecrets.sas = NULL; zrtpChannelContext->srtpSecrets.sasLength = 0; zrtpChannelContext->srtpSecrets.hashAlgo = ZRTP_UNSET_ALGO; zrtpChannelContext->srtpSecrets.keyAgreementAlgo = ZRTP_UNSET_ALGO; zrtpChannelContext->srtpSecrets.sasAlgo = ZRTP_UNSET_ALGO; zrtpChannelContext->srtpSecrets.cacheMismatch = 0; /* create the Hello packet and store it */ helloPacket = bzrtp_createZrtpPacket(zrtpContext, zrtpChannelContext, MSGTYPE_HELLO, &retval); if (retval != 0) { return retval; } /* build the packet string and store the packet */ if (bzrtp_packetBuild(zrtpContext, zrtpChannelContext, helloPacket, zrtpChannelContext->selfSequenceNumber) ==0) { zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID] = helloPacket; } else { bzrtp_freeZrtpPacket(helloPacket); return retval; } return 0; } /** * @brief Destroy the context of a channel * Free allocated buffers, destroy keys * * @param[in] zrtpContext The zrtpContext hosting this channel, needed to acces the RNG * @param[in] zrtpChannelContext The channel context to be destroyed */ static void bzrtp_destroyChannelContext(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext) { int i; /* check there is something to be freed */ if (zrtpChannelContext == NULL) { return; } /* reset state Machine */ zrtpChannelContext->stateMachine = NULL; /* set timer off */ zrtpChannelContext->timer.status = BZRTP_TIMER_OFF; /* destroy and free the key buffers */ bzrtp_DestroyKey(zrtpChannelContext->s0, zrtpChannelContext->hashLength, zrtpContext->RNGContext); bzrtp_DestroyKey(zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, zrtpContext->RNGContext); bzrtp_DestroyKey(zrtpChannelContext->mackeyi, zrtpChannelContext->hashLength, zrtpContext->RNGContext); bzrtp_DestroyKey(zrtpChannelContext->mackeyr, zrtpChannelContext->hashLength, zrtpContext->RNGContext); bzrtp_DestroyKey(zrtpChannelContext->zrtpkeyi, zrtpChannelContext->cipherKeyLength, zrtpContext->RNGContext); bzrtp_DestroyKey(zrtpChannelContext->zrtpkeyr, zrtpChannelContext->cipherKeyLength, zrtpContext->RNGContext); free(zrtpChannelContext->s0); free(zrtpChannelContext->KDFContext); free(zrtpChannelContext->mackeyi); free(zrtpChannelContext->mackeyr); free(zrtpChannelContext->zrtpkeyi); free(zrtpChannelContext->zrtpkeyr); zrtpChannelContext->s0=NULL; zrtpChannelContext->KDFContext=NULL; zrtpChannelContext->mackeyi=NULL; zrtpChannelContext->mackeyr=NULL; zrtpChannelContext->zrtpkeyi=NULL; zrtpChannelContext->zrtpkeyr=NULL; /* free the allocated buffers */ for (i=0; iselfPackets[i]); bzrtp_freeZrtpPacket(zrtpChannelContext->peerPackets[i]); zrtpChannelContext->selfPackets[i] = NULL; zrtpChannelContext->peerPackets[i] = NULL; } free(zrtpChannelContext->peerHelloHash); zrtpChannelContext->peerHelloHash = NULL; /* destroy and free the srtp and sas struture */ bzrtp_DestroyKey(zrtpChannelContext->srtpSecrets.selfSrtpKey, zrtpChannelContext->srtpSecrets.selfSrtpKeyLength, zrtpContext->RNGContext); bzrtp_DestroyKey(zrtpChannelContext->srtpSecrets.selfSrtpSalt, zrtpChannelContext->srtpSecrets.selfSrtpSaltLength, zrtpContext->RNGContext); bzrtp_DestroyKey(zrtpChannelContext->srtpSecrets.peerSrtpKey, zrtpChannelContext->srtpSecrets.peerSrtpKeyLength, zrtpContext->RNGContext); bzrtp_DestroyKey(zrtpChannelContext->srtpSecrets.peerSrtpSalt, zrtpChannelContext->srtpSecrets.peerSrtpSaltLength, zrtpContext->RNGContext); bzrtp_DestroyKey((uint8_t *)zrtpChannelContext->srtpSecrets.sas, zrtpChannelContext->srtpSecrets.sasLength, zrtpContext->RNGContext); free(zrtpChannelContext->srtpSecrets.selfSrtpKey); free(zrtpChannelContext->srtpSecrets.selfSrtpSalt); free(zrtpChannelContext->srtpSecrets.peerSrtpKey); free(zrtpChannelContext->srtpSecrets.peerSrtpSalt); free(zrtpChannelContext->srtpSecrets.sas); /* free the channel context */ free(zrtpChannelContext); } static uint8_t copyCryptoTypes(uint8_t destination[7], uint8_t source[7], uint8_t size) { int i; for (i=0; i #include #include #include "cryptoUtils.h" #include "bctoolbox/crypto.h" /** Return available crypto functions. For now we have * * - Hash: HMAC-SHA256(Mandatory) * - CipherBlock: AES128(Mandatory) * - Auth Tag: HMAC-SHA132 and HMAC-SHA180 (These are mandatory for SRTP and depends on the SRTP implementation thus we can just suppose they are both available) * - Key Agreement: DHM3k(Mandatory), DHM2k(optional and shall not be used except on low power devices) * - Sas: base32(Mandatory), b256(pgp words) */ uint8_t bzrtpUtils_getAvailableCryptoTypes(uint8_t algoType, uint8_t availableTypes[7]) { switch(algoType) { case ZRTP_HASH_TYPE: availableTypes[0] = ZRTP_HASH_S256; return 1; break; case ZRTP_CIPHERBLOCK_TYPE: availableTypes[0] = ZRTP_CIPHER_AES1; availableTypes[1] = ZRTP_CIPHER_AES3; return 2; break; case ZRTP_AUTHTAG_TYPE: availableTypes[0] = ZRTP_AUTHTAG_HS32; availableTypes[1] = ZRTP_AUTHTAG_HS80; return 2; break; case ZRTP_KEYAGREEMENT_TYPE: availableTypes[0] = ZRTP_KEYAGREEMENT_DH3k; availableTypes[1] = ZRTP_KEYAGREEMENT_DH2k; availableTypes[2] = ZRTP_KEYAGREEMENT_Mult; /* This one shall always be at the end of the list, it is just to inform the peer ZRTP endpoint that we support the Multichannel ZRTP */ return 3; break; case ZRTP_SAS_TYPE: /* the SAS function is implemented in cryptoUtils.c and then is not directly linked to the polarSSL crypto wrapper */ availableTypes[0] = ZRTP_SAS_B32; availableTypes[1] = ZRTP_SAS_B256; return 2; break; default: return 0; } } /** Return mandatory crypto functions. For now we have * * - Hash: HMAC-SHA256 * - CipherBlock: AES128 * - Auth Tag: HMAC-SHA132 and HMAC-SHA180 * - Key Agreement: DHM3k * - Sas: base32 */ uint8_t bzrtpUtils_getMandatoryCryptoTypes(uint8_t algoType, uint8_t mandatoryTypes[7]) { switch(algoType) { case ZRTP_HASH_TYPE: mandatoryTypes[0] = ZRTP_HASH_S256; return 1; case ZRTP_CIPHERBLOCK_TYPE: mandatoryTypes[0] = ZRTP_CIPHER_AES1; return 1; case ZRTP_AUTHTAG_TYPE: mandatoryTypes[0] = ZRTP_AUTHTAG_HS32; mandatoryTypes[1] = ZRTP_AUTHTAG_HS80; return 2; case ZRTP_KEYAGREEMENT_TYPE: mandatoryTypes[0] = ZRTP_KEYAGREEMENT_DH3k; mandatoryTypes[1] = ZRTP_KEYAGREEMENT_Mult; /* we must add this one if we want to be able to make multistream */ return 2; case ZRTP_SAS_TYPE: mandatoryTypes[0] = ZRTP_SAS_B32; return 1; default: return 0; } } int bzrtp_keyDerivationFunction(uint8_t *key, uint16_t keyLength, uint8_t *label, uint16_t labelLength, uint8_t *context, uint16_t contextLength, uint16_t hmacLength, void (*hmacFunction)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *), uint8_t *output) { /* get the total length (in bytes) of the data to be hashed */ /* need to add 4 bytes for the initial constant 0x00000001, 1 byte for the 0x00 separator and 4 bytes for the hmacLength length */ uint32_t inputLength = 4 + labelLength + 1 + contextLength + 4; /* create the hmac function input */ uint8_t *input = (uint8_t *)malloc(inputLength*sizeof(uint8_t)); /* fill the input starting by the 32-bits big-endian interger set to 0x00000001 */ uint32_t index = 0; input[index++] = 0x00; input[index++] = 0x00; input[index++] = 0x00; input[index++] = 0x01; /* concat the label */ memcpy(input+index, label, labelLength); index += labelLength; /* a separation byte to 0x00 */ input[index++] = 0x00; /* concat the context string */ memcpy(input+index, context, contextLength); index += contextLength; /* end by L(hmacLength) in big-endian. hamcLength is in bytes and must be converted to bits before insertion in the text to hash */ input[index++] = (uint8_t)((hmacLength>>21)&0xFF); input[index++] = (uint8_t)((hmacLength>>13)&0xFF); input[index++] = (uint8_t)((hmacLength>>5)&0xFF); input[index++] = (uint8_t)((hmacLength<<3)&0xFF); /* call the hmac function */ hmacFunction(key, keyLength, input, inputLength, hmacLength, output); free(input); return 0; } /* Base32 function. Code from rfc section 5.1.6 */ void bzrtp_base32(uint32_t sas, char *output, int outputSize) { int i, n, shift; for (i=0,shift=27; i!=4; ++i,shift-=5) { n = (sas>>shift) & 31; output[i] = "ybndrfg8ejkmcpqxot1uwisza345h769"[n]; } output[4] = '\0'; } /* Base256 function. Code from rfc section 5.1.6 */ void bzrtp_base256(uint32_t sas, char *output, int outputSize) { // generate indexes and copy the appropriate words int evenIndex = (sas >> 24) & 0xFF; int oddIndex = (sas >> 16) & 0xFF; snprintf(output, outputSize, "%s:%s", pgpWordsEven[evenIndex], pgpWordsOdd[oddIndex]); } uint32_t CRC32LookupTable[256] = { 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351 }; /* CRC32 Polynomial 0x1EDC6F41 in reverse bit order so * used the reversed one 0x82F63B78 to compute the table */ uint32_t bzrtp_CRC32(uint8_t *input, uint16_t length) { int i; /* code used to generate the lookup table but it's faster to store it */ /* int j; uint32_t CRC32LookupTable[256]; for (i = 0; i <= 0xFF; i++) { uint32_t crcT = i; for (j = 0; j < 8; j++) { crcT = (crcT >> 1) ^ ((crcT & 1) * 0x82F63B78); } CRC32LookupTable[i] = crcT; } for (i=0; i<256; i+=4) { printf("0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx,\n", (long unsigned int)CRC32LookupTable[i], (long unsigned int)CRC32LookupTable[i+1], (long unsigned int)CRC32LookupTable[i+2], (long unsigned int)CRC32LookupTable[i+3]); }*/ uint32_t crc = 0xFFFFFFFF; for (i=0; i> 8) ^ CRC32LookupTable[(crc & 0xFF) ^ input[i]]; } crc =~crc; /* swap the byte order */ return ((crc&0xFF000000)>>24)|((crc&0x00FF0000)>>8)|((crc&0x0000FF00)<<8)|((crc&0x000000FF)<<24); } /* * @brief select a key agreement algorithm from the one available in context and the one provided by * peer in Hello Message as described in rfc section 4.1.2 * - other algorithm are selected according to availability and selected key agreement as described in * rfc section 5.1.5 * The other algorithm choice will finally be set by the endpoint acting as initiator in the commit packet * * @param[in/out] zrtpContext The context contains the list of available algo and is set with the selected ones and associated functions * @param[in] peerHelloMessage The peer hello message containing his set of available algos * * return 0 on succes, error code otherwise * */ int bzrtp_cryptoAlgoAgreement(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext, bzrtpHelloMessage_t *peerHelloMessage) { uint8_t selfCommonKeyAgreementType[7]; uint8_t peerCommonKeyAgreementType[7]; uint8_t commonKeyAgreementTypeNumber = 0; uint8_t commonCipherType[7]; uint8_t commonCipherTypeNumber; uint8_t commonHashType[7]; uint8_t commonHashTypeNumber; uint8_t commonAuthTagType[7]; uint8_t commonAuthTagTypeNumber; uint8_t commonSasType[7]; uint8_t commonSasTypeNumber; /* check context and Message */ if (zrtpContext == NULL) { return ZRTP_CRYPTOAGREEMENT_INVALIDCONTEXT; } if (zrtpContext->kc == 0) { return ZRTP_CRYPTOAGREEMENT_INVALIDCONTEXT; } if (peerHelloMessage == NULL) { return ZRTP_CRYPTOAGREEMENT_INVALIDMESSAGE; } if (peerHelloMessage->kc == 0) { return ZRTP_CRYPTOAGREEMENT_INVALIDMESSAGE; } /* now check what is in common in self and peer order */ /* self ordering: get the common list in the self order of preference */ commonKeyAgreementTypeNumber = selectCommonAlgo(zrtpContext->supportedKeyAgreement, zrtpContext->kc, peerHelloMessage->supportedKeyAgreement, peerHelloMessage->kc, selfCommonKeyAgreementType); /* check we have something in common */ if (commonKeyAgreementTypeNumber == 0) { /* this shall never bee true as all ZRTP endpoint MUST support at least DH3k */ return ZRTP_CRYPTOAGREEMENT_NOCOMMONALGOFOUND; } /* peer ordering: get the common list in the peer order of preference */ selectCommonAlgo(peerHelloMessage->supportedKeyAgreement, peerHelloMessage->kc, zrtpContext->supportedKeyAgreement, zrtpContext->kc, peerCommonKeyAgreementType); /* if the first choices are the same for both, select it */ if (selfCommonKeyAgreementType[0] == peerCommonKeyAgreementType[0]) { zrtpChannelContext->keyAgreementAlgo = selfCommonKeyAgreementType[0]; } else { /* select the fastest of the two algoritm. Order is "DH2k", "EC25", "DH3k", "EC38", "EC52" */ if (peerCommonKeyAgreementType[0]keyAgreementAlgo = peerCommonKeyAgreementType[0]; } else { zrtpChannelContext->keyAgreementAlgo = selfCommonKeyAgreementType[0]; } } /* now we shall select others algos among the availables and set them into the context, these choices may be * bypassed if we assume the receptor role as the initiator's commit will have the final word on the algo * selection */ /*** Cipher block algorithm ***/ /* get the self cipher types availables */ commonCipherTypeNumber = selectCommonAlgo(zrtpContext->supportedCipher, zrtpContext->cc, peerHelloMessage->supportedCipher, peerHelloMessage->cc, commonCipherType); if (commonCipherTypeNumber == 0) {/* This shall never happend but... */ return ZRTP_CRYPTOAGREEMENT_INVALIDCIPHER; } /* rfc section 5.1.5 specifies that if EC38 is choosen we SHOULD use AES256 or AES192 */ if (zrtpChannelContext->keyAgreementAlgo == ZRTP_KEYAGREEMENT_EC38) { int i=0; zrtpChannelContext->cipherAlgo = ZRTP_UNSET_ALGO; /* is AES3 available */ while (icipherAlgo == ZRTP_UNSET_ALGO) { if (commonCipherType[i] == ZRTP_CIPHER_AES3) { zrtpChannelContext->cipherAlgo = ZRTP_CIPHER_AES3; } i++; } /* is AES2 available */ if (zrtpChannelContext->cipherAlgo == ZRTP_UNSET_ALGO) { i=0; while (icipherAlgo == ZRTP_UNSET_ALGO) { if (commonCipherType[i] == ZRTP_CIPHER_AES2) { zrtpChannelContext->cipherAlgo = ZRTP_CIPHER_AES2; } i++; } } if (zrtpChannelContext->cipherAlgo == ZRTP_UNSET_ALGO) { return ZRTP_CRYPTOAGREEMENT_INVALIDCIPHER; } } else { /* no restrictions, pick the first one */ zrtpChannelContext->cipherAlgo = commonCipherType[0]; } /*** Hash algorithm ***/ /* get the self hash types availables */ commonHashTypeNumber = selectCommonAlgo(zrtpContext->supportedHash, zrtpContext->hc, peerHelloMessage->supportedHash, peerHelloMessage->hc, commonHashType); if (commonHashTypeNumber == 0) {/* This shall never happend but... */ return ZRTP_CRYPTOAGREEMENT_INVALIDHASH; } /* rfc section 5.1.5 specifies that if EC38 is choosen we SHOULD use SHA384 */ if (zrtpChannelContext->keyAgreementAlgo == ZRTP_KEYAGREEMENT_EC38) { int i=0; zrtpChannelContext->hashAlgo = ZRTP_UNSET_ALGO; /* is S384 available */ while (ihashAlgo == ZRTP_UNSET_ALGO) { if (commonHashType[i] == ZRTP_HASH_S384) { zrtpChannelContext->hashAlgo = ZRTP_HASH_S384; } i++; } if (zrtpChannelContext->hashAlgo == ZRTP_UNSET_ALGO) { return ZRTP_CRYPTOAGREEMENT_INVALIDHASH; } } else { /* no restrictions, pick the first one */ zrtpChannelContext->hashAlgo = commonHashType[0]; } /*** Authentication Tag algorithm ***/ /* get the self authentication tag types availables */ commonAuthTagTypeNumber = selectCommonAlgo(zrtpContext->supportedAuthTag, zrtpContext->ac, peerHelloMessage->supportedAuthTag, peerHelloMessage->ac, commonAuthTagType); if (commonAuthTagTypeNumber == 0) {/* This shall never happend but... */ return ZRTP_CRYPTOAGREEMENT_INVALIDAUTHTAG; } zrtpChannelContext->authTagAlgo = commonAuthTagType[0]; /*** Sas algorithm ***/ /* get the self Sas rendering types availables */ commonSasTypeNumber = selectCommonAlgo(zrtpContext->supportedSas, zrtpContext->sc, peerHelloMessage->supportedSas, peerHelloMessage->sc, commonSasType); if (commonSasTypeNumber == 0) {/* This shall never happend but... */ return ZRTP_CRYPTOAGREEMENT_INVALIDSAS; } zrtpChannelContext->sasAlgo = commonSasType[0]; /* update the function pointers */ return bzrtp_updateCryptoFunctionPointers(zrtpChannelContext); } /* * @brief Update context crypto function pointer according to related values of choosen algorithms fields (hashAlgo, cipherAlgo, etc..) * The associated length are updated too * * @param[in/out] context The bzrtp context to be updated * * @return 0 on succes */ int bzrtp_updateCryptoFunctionPointers(bzrtpChannelContext_t *zrtpChannelContext) { if (zrtpChannelContext==NULL) { return ZRTP_CRYPTOAGREEMENT_INVALIDCONTEXT; } /* Hash algo */ switch (zrtpChannelContext->hashAlgo) { case ZRTP_HASH_S256 : zrtpChannelContext->hashFunction = bctbx_sha256; zrtpChannelContext->hmacFunction = bctbx_hmacSha256; zrtpChannelContext->hashLength = 32; break; case ZRTP_UNSET_ALGO : zrtpChannelContext->hashFunction = NULL; zrtpChannelContext->hmacFunction = NULL; zrtpChannelContext->hashLength = 0; break; default: return ZRTP_CRYPTOAGREEMENT_INVALIDHASH; break; } /* CipherBlock algo */ switch (zrtpChannelContext->cipherAlgo) { case ZRTP_CIPHER_AES1 : zrtpChannelContext->cipherEncryptionFunction = bctbx_aes128CfbEncrypt; zrtpChannelContext->cipherDecryptionFunction = bctbx_aes128CfbDecrypt; zrtpChannelContext->cipherKeyLength = 16; break; case ZRTP_CIPHER_AES3 : zrtpChannelContext->cipherEncryptionFunction = bctbx_aes256CfbEncrypt; zrtpChannelContext->cipherDecryptionFunction = bctbx_aes256CfbDecrypt; zrtpChannelContext->cipherKeyLength = 32; break; case ZRTP_UNSET_ALGO : zrtpChannelContext->cipherEncryptionFunction = NULL; zrtpChannelContext->cipherDecryptionFunction = NULL; zrtpChannelContext->cipherKeyLength = 0; break; default: return ZRTP_CRYPTOAGREEMENT_INVALIDCIPHER; break; } /* Key agreement algo : there is an unique function for this one in the wrapper, just set the keyAgreementLength */ switch (zrtpChannelContext->keyAgreementAlgo) { case ZRTP_KEYAGREEMENT_DH2k : zrtpChannelContext->keyAgreementLength = 256; break; case ZRTP_KEYAGREEMENT_DH3k : zrtpChannelContext->keyAgreementLength = 384; break; default: return ZRTP_CRYPTOAGREEMENT_INVALIDCIPHER; break; } /* SAS rendering algo */ switch(zrtpChannelContext->sasAlgo) { case ZRTP_SAS_B32: zrtpChannelContext->sasFunction = bzrtp_base32; // extend 4 byte b32 length to include null terminator zrtpChannelContext->sasLength = 5; break; case ZRTP_SAS_B256: zrtpChannelContext->sasFunction = bzrtp_base256; zrtpChannelContext->sasLength = 32; break; case ZRTP_UNSET_ALGO : zrtpChannelContext->sasFunction = NULL; zrtpChannelContext->sasLength = 0; break; default: return ZRTP_CRYPTOAGREEMENT_INVALIDSAS; break; } return 0; } #define BITS_PRO_INT 8*sizeof(int) #define BITMASK_256_SIZE 256/BITS_PRO_INT #define BITMASK_256_SET_ZERO(bitmask) memset(bitmask, 0, sizeof(int)*BITMASK_256_SIZE) #define BITMASK_256_SET(bitmask, value) bitmask[value/BITS_PRO_INT] |= 1 << (value % BITS_PRO_INT) #define BITMASK_256_UNSET(bitmask, value) bitmask[value/BITS_PRO_INT] &= ~(1 << (value % BITS_PRO_INT)) #define BITMASK_256_CHECK(bitmask, value) (bitmask[value/BITS_PRO_INT] & 1 << (value % BITS_PRO_INT)) /** * @brief Select common algorithm from the given array where algo are represented by their 4 chars string defined in rfc section 5.1.2 to 5.1.6 * Master array is the one given the preference order * All algo are designed by their uint8_t mapped values * * @param[in] masterArray The ordered available algo, result will follow this ordering * @param[in] masterArrayLength Number of valids element in the master array * @param[in] slaveArray The available algo, order is not taken in account * @param[in] slaveArrayLength Number of valids element in the slave array * @param[out] commonArray Common algorithms found, max size 7 * * @return the number of common algorithms found */ uint8_t selectCommonAlgo(uint8_t masterArray[7], uint8_t masterArrayLength, uint8_t slaveArray[7], uint8_t slaveArrayLength, uint8_t commonArray[7]) { int i; uint8_t commonLength = 0; int algosBitmap[BITMASK_256_SIZE]; BITMASK_256_SET_ZERO(algosBitmap); for (i=0; i0 && i>4)&0x0F); outputString[2*i+1] = bzrtp_byteToChar(inputBytes[i]&0x0F); } } /** * @brief convert an hexa char [0-9a-fA-F] into the corresponding unsigned integer value * Any invalid char will be converted to zero without any warning * * @param[in] inputChar a char which shall be in range [0-9a-fA-F] * * @return the unsigned integer value in range [0-15] */ uint8_t bzrtp_charToByte(uint8_t inputChar) { /* 0-9 */ if (inputChar>0x29 && inputChar<0x3A) { return inputChar - 0x30; } /* a-f */ if (inputChar>0x60 && inputChar<0x67) { return inputChar - 0x57; /* 0x57 = 0x61(a) + 0x0A*/ } /* A-F */ if (inputChar>0x40 && inputChar<0x47) { return inputChar - 0x37; /* 0x37 = 0x41(a) + 0x0A*/ } /* shall never arrive here, string is not Hex*/ return 0; } /** * @brief convert a byte which value is in range [0-15] into an hexa char [0-9a-fA-F] * * @param[in] inputByte an integer which shall be in range [0-15] * * @return the hexa char [0-9a-f] corresponding to the input */ uint8_t bzrtp_byteToChar(uint8_t inputByte) { inputByte &=0x0F; /* restrict the input value to range [0-15] */ /* 0-9 */ if(inputByte<0x0A) { return inputByte+0x30; } /* a-f */ return inputByte + 0x57; } bzrtp-1.0.6/src/packetParser.c000066400000000000000000002122561313411235300162420ustar00rootroot00000000000000/** @file packetParser.c @brief functions to parse and generate a ZRTP packet @author Johan Pascal @copyright Copyright (C) 2014 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include "typedef.h" #include "packetParser.h" #include #include "cryptoUtils.h" /* DEBUG */ #include /* minimum length of a ZRTP packet: 12 bytes header + 12 bytes message(shortest are ACK messages) + 4 bytes CRC */ #define ZRTP_MIN_PACKET_LENGTH 28 /* maximum length of a ZRTP packet: 3072 bytes get it from GNU-ZRTP CPP code */ #define ZRTP_MAX_PACKET_LENGTH 3072 /* header of ZRTP message is 12 bytes : Preambule/Message Length + Message Type(2 words) */ #define ZRTP_MESSAGE_HEADER_LENGTH 12 /* length of the non optional and fixed part of all messages, in bytes */ #define ZRTP_HELLOMESSAGE_FIXED_LENGTH 88 #define ZRTP_HELLOACKMESSAGE_FIXED_LENGTH 12 #define ZRTP_COMMITMESSAGE_FIXED_LENGTH 84 #define ZRTP_DHPARTMESSAGE_FIXED_LENGTH 84 #define ZRTP_CONFIRMMESSAGE_FIXED_LENGTH 76 #define ZRTP_CONF2ACKMESSAGE_FIXED_LENGTH 12 #define ZRTP_ERRORMESSAGE_FIXED_LENGTH 16 #define ZRTP_ERRORACKMESSAGE_FIXED_LENGTH 12 #define ZRTP_GOCLEARMESSAGE_FIXED_LENGTH 20 #define ZRTP_CLEARACKMESSAGE_FIXED_LENGTH 12 #define ZRTP_SASRELAYMESSAGE_FIXED_LENGTH 76 #define ZRTP_RELAYACKMESSAGE_FIXED_LENGTH 12 #define ZRTP_PINGMESSAGE_FIXED_LENGTH 24 #define ZRTP_PINGACKMESSAGE_FIXED_LENGTH 36 /*** local functions prototypes ***/ /** * Return the variable private value length in bytes according to given key agreement algorythm * * @param[in] keyAgreementAlgo The key agreement algo mapped to an integer as defined in cryptoWrapper.h * * @return the private value length in bytes * */ uint16_t computeKeyAgreementPrivateValueLength(uint8_t keyAgreementAlgo); /** * @brief Retrieve the 8 char string value message type from the int32_t code * * @param[in] messageType The messageType code * * @return an 9 char string : 8 chars message type as specified in rfc section 5.1.1 + string terminating char */ uint8_t *messageTypeInttoString(uint32_t messageType); /** * @brief Map the 8 char string value message type to an int32_t * * @param[in] messageTypeString an 8 bytes string matching a zrtp message type * * @return a 32-bits unsigned integer mapping the message type */ int32_t messageTypeStringtoInt(uint8_t messageTypeString[8]); /** * @brief Write the message header(preambule, length, message type) into the given output buffer * * @param[out] outputBuffer Message starts at the begining of this buffer * @param[in] messageLength Message length in bytes! To be converted into 32bits words before being inserted in the message header * @param[in] messageType An 8 chars string for the message type (validity is not checked by this function) * */ void zrtpMessageSetHeader(uint8_t *outputBuffer, uint16_t messageLength, uint8_t messageType[8]); /*** Public functions implementation ***/ /* First call this function to check packet validity and create the packet structure */ bzrtpPacket_t *bzrtp_packetCheck(const uint8_t * input, uint16_t inputLength, uint16_t lastValidSequenceNumber, int *exitCode) { bzrtpPacket_t *zrtpPacket; uint16_t sequenceNumber; uint32_t packetCRC; uint16_t messageLength; uint32_t messageType; /* first check that the packet is a ZRTP one */ /* is the length compatible with a ZRTP packet */ if ((inputLengthZRTP_MAX_PACKET_LENGTH)) { *exitCode = BZRTP_PARSER_ERROR_INVALIDPACKET; return NULL; } /* check ZRTP packet format from rfc section 5 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0 0 0 1|Not Used (set to zero) | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Magic Cookie 'ZRTP' (0x5a525450) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Identifier | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | ZRTP Message (length depends on Message Type) | | . . . | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | CRC (1 word) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/ if ((input[0]>>4 != 0x01) || (input[4]!= (uint8_t)((ZRTP_MAGIC_COOKIE>>24)&0xFF)) || (input[5]!= (uint8_t)((ZRTP_MAGIC_COOKIE>>16)&0xFF)) || (input[6]!= (uint8_t)((ZRTP_MAGIC_COOKIE>>8)&0xFF)) || (input[7]!= (uint8_t)(ZRTP_MAGIC_COOKIE&0xFF))) { *exitCode = BZRTP_PARSER_ERROR_INVALIDPACKET; return NULL; } /* Check the sequence number : it must be > to the last valid one (given in parameter) to discard out of order packets * TODO: what if we got a Sequence Number overflowing the 16 bits ? */ sequenceNumber = (((uint16_t)input[2])<<8) | ((uint16_t)input[3]); if (sequenceNumber <= lastValidSequenceNumber) { *exitCode = BZRTP_PARSER_ERROR_OUTOFORDER; return NULL; } /* Check the CRC : The CRC is calculated across the entire ZRTP packet, including the ZRTP header and the ZRTP message, but not including the CRC field.*/ packetCRC = ((((uint32_t)input[inputLength-4])<<24)&0xFF000000) | ((((uint32_t)input[inputLength-3])<<16)&0x00FF0000) | ((((uint32_t)input[inputLength-2])<<8)&0x0000FF00) | (((uint32_t)input[inputLength-1])&0x000000FF); if (bzrtp_CRC32((uint8_t *)input, inputLength - 4) != packetCRC) { *exitCode = BZRTP_PARSER_ERROR_INVALIDCRC; return NULL; } /* check message header : * 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0 1 0 1 0 0 0 0 0 1 0 1 1 0 1 0| length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Message Type Block (2 words) | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/ if ((input[ZRTP_PACKET_HEADER_LENGTH]!=0x50) || (input[ZRTP_PACKET_HEADER_LENGTH+1]!=0x5a)) { *exitCode = BZRTP_PARSER_ERROR_INVALIDMESSAGE; return NULL; } /* get the length from the message: it is expressed in 32bits words, convert it to bytes (4*) */ messageLength = 4*(((((uint16_t)input[ZRTP_PACKET_HEADER_LENGTH+2])<<8)&0xFF00) | (((uint16_t)input[ZRTP_PACKET_HEADER_LENGTH+3])&0x00FF)); /* get the message Type */ messageType = messageTypeStringtoInt((uint8_t *)(input+ZRTP_PACKET_HEADER_LENGTH+4)); if (messageType == MSGTYPE_INVALID) { *exitCode = BZRTP_PARSER_ERROR_INVALIDMESSAGE; return NULL; } /* packet and message seems to be valid, so allocate a structure and parse it */ zrtpPacket = (bzrtpPacket_t *)malloc(sizeof(bzrtpPacket_t)); memset(zrtpPacket, 0, sizeof(bzrtpPacket_t)); zrtpPacket->sequenceNumber = sequenceNumber; zrtpPacket->messageLength = messageLength; zrtpPacket->messageType = messageType; zrtpPacket->messageData = NULL; zrtpPacket->packetString = NULL; /* get the SSRC */ zrtpPacket->sourceIdentifier = ((((uint32_t)input[8])<<24)&0xFF000000) | ((((uint32_t)input[9])<<16)&0x00FF0000) | ((((uint32_t)input[10])<<8)&0x0000FF00) | (((uint32_t)input[11])&0x000000FF); *exitCode = 0; return zrtpPacket; } /* Call this function after the packetCheck one, to actually parse the packet : create and fill the messageData structure */ int bzrtp_packetParser(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext, const uint8_t * input, uint16_t inputLength, bzrtpPacket_t *zrtpPacket) { int i; /* now allocate and fill the correct message structure according to the message type */ /* messageContent points to the begining of the ZRTP message */ uint8_t *messageContent = (uint8_t *)(input+ZRTP_PACKET_HEADER_LENGTH+ZRTP_MESSAGE_HEADER_LENGTH); switch (zrtpPacket->messageType) { case MSGTYPE_HELLO : { bzrtpHelloMessage_t *messageData; /* Do we have a peerHelloHash to check */ if (zrtpChannelContext->peerHelloHash != NULL) { uint8_t computedPeerHelloHash[32]; /* compute hash using implicit hash function: SHA256, skip packet header in the packetString buffer as the hash must be computed on message only */ bctbx_sha256(input+ZRTP_PACKET_HEADER_LENGTH, inputLength - ZRTP_PACKET_OVERHEAD, 32, computedPeerHelloHash); /* check they are the same */ if (memcmp(computedPeerHelloHash, zrtpChannelContext->peerHelloHash, 32)!=0) { return BZRTP_ERROR_HELLOHASH_MISMATCH; } } /* allocate a Hello message structure */ messageData = (bzrtpHelloMessage_t *)malloc(sizeof(bzrtpHelloMessage_t)); /* fill it */ memcpy(messageData->version, messageContent, 4); messageContent +=4; memcpy(messageData->clientIdentifier, messageContent, 16); messageData->clientIdentifier[16] = '\0'; /* be sure the clientIdentifier is a NULL terminated string */ messageContent +=16; memcpy(messageData->H3, messageContent, 32); messageContent +=32; memcpy(messageData->ZID, messageContent, 12); messageContent +=12; messageData->S = ((*messageContent)>>6)&0x01; messageData->M = ((*messageContent)>>5)&0x01; messageData->P = ((*messageContent)>>4)&0x01; messageContent +=1; messageData->hc = MIN((*messageContent)&0x0F, 7); messageContent +=1; messageData->cc = MIN(((*messageContent)>>4)&0x0F, 7); messageData->ac = MIN((*messageContent)&0x0F, 7); messageContent +=1; messageData->kc = MIN(((*messageContent)>>4)&0x0F, 7); messageData->sc = MIN((*messageContent)&0x0F, 7); messageContent +=1; /* Check message length according to value in hc, cc, ac, kc and sc */ if (zrtpPacket->messageLength != ZRTP_HELLOMESSAGE_FIXED_LENGTH + 4*((uint16_t)(messageData->hc)+(uint16_t)(messageData->cc)+(uint16_t)(messageData->ac)+(uint16_t)(messageData->kc)+(uint16_t)(messageData->sc))) { free(messageData); return BZRTP_PARSER_ERROR_INVALIDMESSAGE; } /* parse the variable length part: algorithms types */ for (i=0; ihc; i++) { messageData->supportedHash[i] = bzrtp_cryptoAlgoTypeStringToInt(messageContent, ZRTP_HASH_TYPE); messageContent +=4; } for (i=0; icc; i++) { messageData->supportedCipher[i] = bzrtp_cryptoAlgoTypeStringToInt(messageContent, ZRTP_CIPHERBLOCK_TYPE); messageContent +=4; } for (i=0; iac; i++) { messageData->supportedAuthTag[i] = bzrtp_cryptoAlgoTypeStringToInt(messageContent, ZRTP_AUTHTAG_TYPE); messageContent +=4; } for (i=0; ikc; i++) { messageData->supportedKeyAgreement[i] = bzrtp_cryptoAlgoTypeStringToInt(messageContent, ZRTP_KEYAGREEMENT_TYPE); messageContent +=4; } for (i=0; isc; i++) { messageData->supportedSas[i] = bzrtp_cryptoAlgoTypeStringToInt(messageContent, ZRTP_SAS_TYPE); messageContent +=4; } bzrtp_addMandatoryCryptoTypesIfNeeded(ZRTP_HASH_TYPE, messageData->supportedHash, &messageData->hc); bzrtp_addMandatoryCryptoTypesIfNeeded(ZRTP_CIPHERBLOCK_TYPE, messageData->supportedCipher, &messageData->cc); bzrtp_addMandatoryCryptoTypesIfNeeded(ZRTP_AUTHTAG_TYPE, messageData->supportedAuthTag, &messageData->ac); bzrtp_addMandatoryCryptoTypesIfNeeded(ZRTP_KEYAGREEMENT_TYPE, messageData->supportedKeyAgreement, &messageData->kc); bzrtp_addMandatoryCryptoTypesIfNeeded(ZRTP_SAS_TYPE, messageData->supportedSas, &messageData->sc); memcpy(messageData->MAC, messageContent, 8); /* attach the message structure to the packet one */ zrtpPacket->messageData = (void *)messageData; /* the parsed Hello packet must be saved as it may be used to generate commit message or the total_hash */ zrtpPacket->packetString = (uint8_t *)malloc(inputLength*sizeof(uint8_t)); memcpy(zrtpPacket->packetString, input, inputLength); /* store the whole packet even if we may use the message only */ } break; /* MSGTYPE_HELLO */ case MSGTYPE_HELLOACK : { /* check message length */ if (zrtpPacket->messageLength != ZRTP_HELLOACKMESSAGE_FIXED_LENGTH) { return BZRTP_PARSER_ERROR_INVALIDMESSAGE; } } break; /* MSGTYPE_HELLOACK */ case MSGTYPE_COMMIT: { uint8_t checkH3[32]; uint8_t checkMAC[32]; bzrtpHelloMessage_t *peerHelloMessageData; uint16_t variableLength = 0; /* allocate a commit message structure */ bzrtpCommitMessage_t *messageData; messageData = (bzrtpCommitMessage_t *)malloc(sizeof(bzrtpCommitMessage_t)); /* fill the structure */ memcpy(messageData->H2, messageContent, 32); messageContent +=32; /* We have now H2, check it matches the H3 we had in the hello message H3=SHA256(H2) and that the Hello message MAC is correct */ if (zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID] == NULL) { free (messageData); /* we have no Hello message in this channel, this commit shall never have arrived, discard it as invalid */ return BZRTP_PARSER_ERROR_UNEXPECTEDMESSAGE; } peerHelloMessageData = (bzrtpHelloMessage_t *)zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->messageData; /* Check H3 = SHA256(H2) */ bctbx_sha256(messageData->H2, 32, 32, checkH3); if (memcmp(checkH3, peerHelloMessageData->H3, 32) != 0) { free (messageData); return BZRTP_PARSER_ERROR_UNMATCHINGHASHCHAIN; } /* Check the hello MAC message. * MAC is 8 bytes long and is computed on the message(skip the ZRTP_PACKET_HEADER) and exclude the mac itself (-8 bytes from message Length) */ bctbx_hmacSha256(messageData->H2, 32, zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->messageLength-8, 8, checkMAC); if (memcmp(checkMAC, peerHelloMessageData->MAC, 8) != 0) { free (messageData); return BZRTP_PARSER_ERROR_UNMATCHINGMAC; } memcpy(messageData->ZID, messageContent, 12); messageContent +=12; messageData->hashAlgo = bzrtp_cryptoAlgoTypeStringToInt(messageContent, ZRTP_HASH_TYPE); messageContent += 4; messageData->cipherAlgo = bzrtp_cryptoAlgoTypeStringToInt(messageContent, ZRTP_CIPHERBLOCK_TYPE); messageContent += 4; messageData->authTagAlgo = bzrtp_cryptoAlgoTypeStringToInt(messageContent, ZRTP_AUTHTAG_TYPE); messageContent += 4; messageData->keyAgreementAlgo = bzrtp_cryptoAlgoTypeStringToInt(messageContent, ZRTP_KEYAGREEMENT_TYPE); messageContent += 4; /* commit message length depends on the key agreement type choosen (and set in the zrtpContext->keyAgreementAlgo) */ switch(messageData->keyAgreementAlgo) { case ZRTP_KEYAGREEMENT_DH2k : case ZRTP_KEYAGREEMENT_EC25 : case ZRTP_KEYAGREEMENT_DH3k : case ZRTP_KEYAGREEMENT_EC38 : case ZRTP_KEYAGREEMENT_EC52 : variableLength = 32; /* hvi is 32 bytes length in DH Commit message format */ break; case ZRTP_KEYAGREEMENT_Prsh : variableLength = 24; /* nonce (16 bytes) and keyID(8 bytes) are 24 bytes length in preshared Commit message format */ break; case ZRTP_KEYAGREEMENT_Mult : variableLength = 16; /* nonce is 24 bytes length in multistream Commit message format */ break; default: free(messageData); return BZRTP_PARSER_ERROR_INVALIDMESSAGE; } if (zrtpPacket->messageLength != ZRTP_COMMITMESSAGE_FIXED_LENGTH + variableLength) { free(messageData); return BZRTP_PARSER_ERROR_INVALIDMESSAGE; } messageData->sasAlgo = bzrtp_cryptoAlgoTypeStringToInt(messageContent, ZRTP_SAS_TYPE); messageContent += 4; /* if it is a multistream or preshared commit, get the 16 bytes nonce */ if ((messageData->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Prsh) || (messageData->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Mult)) { memcpy(messageData->nonce, messageContent, 16); messageContent +=16; /* and the keyID for preshared commit only */ if (messageData->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Prsh) { memcpy(messageData->keyID, messageContent, 8); messageContent +=8; } } else { /* it's a DH commit message, get the hvi */ memcpy(messageData->hvi, messageContent, 32); messageContent +=32; } /* get the MAC and attach the message data to the packet structure */ memcpy(messageData->MAC, messageContent, 8); zrtpPacket->messageData = (void *)messageData; /* the parsed commit packet must be saved as it is used to generate the total_hash */ zrtpPacket->packetString = (uint8_t *)malloc(inputLength*sizeof(uint8_t)); memcpy(zrtpPacket->packetString, input, inputLength); /* store the whole packet even if we may use the message only */ } break; /* MSGTYPE_COMMIT */ case MSGTYPE_DHPART1 : case MSGTYPE_DHPART2 : { bzrtpDHPartMessage_t *messageData; /*check message length, depends on the selected key agreement algo set in zrtpContext */ uint16_t pvLength = computeKeyAgreementPrivateValueLength(zrtpChannelContext->keyAgreementAlgo); if (pvLength == 0) { return BZRTP_PARSER_ERROR_INVALIDCONTEXT; } if (zrtpPacket->messageLength != ZRTP_DHPARTMESSAGE_FIXED_LENGTH+pvLength) { return BZRTP_PARSER_ERROR_INVALIDMESSAGE; } /* allocate a DHPart message structure and pv */ messageData = (bzrtpDHPartMessage_t *)malloc(sizeof(bzrtpDHPartMessage_t)); messageData->pv = (uint8_t *)malloc(pvLength*sizeof(uint8_t)); /* fill the structure */ memcpy(messageData->H1, messageContent, 32); messageContent +=32; /* We have now H1, check it matches the H2 we had in the commit message H2=SHA256(H1) and that the Commit message MAC is correct */ if ( zrtpChannelContext->role == BZRTP_ROLE_RESPONDER) { /* do it only if we are responder (we received a commit packet) */ uint8_t checkH2[32]; uint8_t checkMAC[32]; bzrtpCommitMessage_t *peerCommitMessageData; if (zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID] == NULL) { free (messageData); /* we have no Commit message in this channel, this DHPart2 shall never have arrived, discard it as invalid */ return BZRTP_PARSER_ERROR_UNEXPECTEDMESSAGE; } peerCommitMessageData = (bzrtpCommitMessage_t *)zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID]->messageData; /* Check H2 = SHA256(H1) */ bctbx_sha256(messageData->H1, 32, 32, checkH2); if (memcmp(checkH2, peerCommitMessageData->H2, 32) != 0) { free (messageData); return BZRTP_PARSER_ERROR_UNMATCHINGHASHCHAIN; } /* Check the Commit MAC message. * MAC is 8 bytes long and is computed on the message(skip the ZRTP_PACKET_HEADER) and exclude the mac itself (-8 bytes from message Length) */ bctbx_hmacSha256(messageData->H1, 32, zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID]->messageLength-8, 8, checkMAC); if (memcmp(checkMAC, peerCommitMessageData->MAC, 8) != 0) { free (messageData); return BZRTP_PARSER_ERROR_UNMATCHINGMAC; } /* Check the hvi received in the commit message - RFC section 4.4.1.1*/ /* First compute the expected hvi */ /* hvi = hash(initiator's DHPart2 message(current zrtpPacket)) || responder's Hello message) using the agreed hash function truncated to 256 bits */ /* create a string with the messages concatenated */ { uint8_t computedHvi[32]; uint16_t HelloMessageLength = zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID]->messageLength; uint16_t DHPartHelloMessageStringLength = zrtpPacket->messageLength + HelloMessageLength; uint8_t *DHPartHelloMessageString = (uint8_t *)malloc(DHPartHelloMessageStringLength*sizeof(uint8_t)); memcpy(DHPartHelloMessageString, input+ZRTP_PACKET_HEADER_LENGTH, zrtpPacket->messageLength); memcpy(DHPartHelloMessageString+zrtpPacket->messageLength, zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, HelloMessageLength); zrtpChannelContext->hashFunction(DHPartHelloMessageString, DHPartHelloMessageStringLength, 32, computedHvi); free(DHPartHelloMessageString); /* Compare computed and received hvi */ if (memcmp(computedHvi, peerCommitMessageData->hvi, 32)!=0) { free (messageData); return BZRTP_PARSER_ERROR_UNMATCHINGHVI; } } } else { /* if we are initiator(we didn't received any commit message and then no H2), we must check that H3=SHA256(SHA256(H1)) and the Hello message MAC */ uint8_t checkH2[32]; uint8_t checkH3[32]; uint8_t checkMAC[32]; bzrtpHelloMessage_t *peerHelloMessageData; if (zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID] == NULL) { free (messageData); /* we have no Hello message in this channel, this DHPart1 shall never have arrived, discard it as invalid */ return BZRTP_PARSER_ERROR_UNEXPECTEDMESSAGE; } peerHelloMessageData = (bzrtpHelloMessage_t *)zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->messageData; /* Check H3 = SHA256(SHA256(H1)) */ bctbx_sha256(messageData->H1, 32, 32, checkH2); bctbx_sha256(checkH2, 32, 32, checkH3); if (memcmp(checkH3, peerHelloMessageData->H3, 32) != 0) { free (messageData); return BZRTP_PARSER_ERROR_UNMATCHINGHASHCHAIN; } /* Check the hello MAC message. * MAC is 8 bytes long and is computed on the message(skip the ZRTP_PACKET_HEADER) and exclude the mac itself (-8 bytes from message Length) */ bctbx_hmacSha256(checkH2, 32, zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->messageLength-8, 8, checkMAC); if (memcmp(checkMAC, peerHelloMessageData->MAC, 8) != 0) { free (messageData); return BZRTP_PARSER_ERROR_UNMATCHINGMAC; } } memcpy(messageData->rs1ID, messageContent, 8); messageContent +=8; memcpy(messageData->rs2ID, messageContent, 8); messageContent +=8; memcpy(messageData->auxsecretID, messageContent, 8); messageContent +=8; memcpy(messageData->pbxsecretID, messageContent, 8); messageContent +=8; memcpy(messageData->pv, messageContent, pvLength); messageContent +=pvLength; memcpy(messageData->MAC, messageContent, 8); /* attach the message structure to the packet one */ zrtpPacket->messageData = (void *)messageData; /* the parsed packet must be saved as it is used to generate the total_hash */ zrtpPacket->packetString = (uint8_t *)malloc(inputLength*sizeof(uint8_t)); memcpy(zrtpPacket->packetString, input, inputLength); /* store the whole packet even if we may use the message only */ } break; /* MSGTYPE_DHPART1 and MSGTYPE_DHPART2 */ case MSGTYPE_CONFIRM1: case MSGTYPE_CONFIRM2: { uint8_t *confirmMessageKey = NULL; uint8_t *confirmMessageMacKey = NULL; bzrtpConfirmMessage_t *messageData; uint16_t cipherTextLength; uint8_t computedHmac[8]; uint8_t *confirmPlainMessageBuffer; uint8_t *confirmPlainMessage; /* we shall first decrypt and validate the message, check we have the keys to do it */ if (zrtpChannelContext->role == BZRTP_ROLE_RESPONDER) { /* responder uses initiator's keys to decrypt */ if ((zrtpChannelContext->zrtpkeyi == NULL) || (zrtpChannelContext->mackeyi == NULL)) { return BZRTP_PARSER_ERROR_INVALIDCONTEXT; } confirmMessageKey = zrtpChannelContext->zrtpkeyi; confirmMessageMacKey = zrtpChannelContext->mackeyi; } if (zrtpChannelContext->role == BZRTP_ROLE_INITIATOR) { /* the iniator uses responder's keys to decrypt */ if ((zrtpChannelContext->zrtpkeyr == NULL) || (zrtpChannelContext->mackeyr == NULL)) { return BZRTP_PARSER_ERROR_INVALIDCONTEXT; } confirmMessageKey = zrtpChannelContext->zrtpkeyr; confirmMessageMacKey = zrtpChannelContext->mackeyr; } /* allocate a confirm message structure */ messageData = (bzrtpConfirmMessage_t *)malloc(sizeof(bzrtpConfirmMessage_t)); /* get the mac and the IV */ memcpy(messageData->confirm_mac, messageContent, 8); messageContent +=8; memcpy(messageData->CFBIV, messageContent, 16); messageContent +=16; /* get the cipher text length */ cipherTextLength = zrtpPacket->messageLength - ZRTP_MESSAGE_HEADER_LENGTH - 24; /* confirm message is header, confirm_mac(8 bytes), CFB IV(16 bytes), encrypted part */ /* validate the mac over the cipher text */ zrtpChannelContext->hmacFunction(confirmMessageMacKey, zrtpChannelContext->hashLength, messageContent, cipherTextLength, 8, computedHmac); if (memcmp(computedHmac, messageData->confirm_mac, 8) != 0) { /* confirm_mac doesn't match */ free(messageData); return BZRTP_PARSER_ERROR_UNMATCHINGCONFIRMMAC; } /* get plain message */ confirmPlainMessageBuffer = (uint8_t *)malloc(cipherTextLength*sizeof(uint8_t)); zrtpChannelContext->cipherDecryptionFunction(confirmMessageKey, messageData->CFBIV, messageContent, cipherTextLength, confirmPlainMessageBuffer); confirmPlainMessage = confirmPlainMessageBuffer; /* point into the allocated buffer */ /* parse it */ memcpy(messageData->H0, confirmPlainMessage, 32); confirmPlainMessage +=33; /* +33 because next 8 bits are unused */ /* Hash chain checking: if we are in multichannel or shared mode, we had not DHPart and then no H1 */ if (zrtpChannelContext->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Prsh || zrtpChannelContext->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Mult) { /* compute the H1=SHA256(H0) we never received */ uint8_t checkH1[32]; bctbx_sha256(messageData->H0, 32, 32, checkH1); /* if we are responder, we received a commit packet with H2 then check that H2=SHA256(H1) and that the commit message MAC keyed with H1 match */ if ( zrtpChannelContext->role == BZRTP_ROLE_RESPONDER) { uint8_t checkH2[32]; uint8_t checkMAC[32]; bzrtpCommitMessage_t *peerCommitMessageData; if (zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID] == NULL) { free (messageData); /* we have no Commit message in this channel, this Confirm2 shall never have arrived, discard it as invalid */ return BZRTP_PARSER_ERROR_UNEXPECTEDMESSAGE; } peerCommitMessageData = (bzrtpCommitMessage_t *)zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID]->messageData; /* Check H2 = SHA256(H1) */ bctbx_sha256(checkH1, 32, 32, checkH2); if (memcmp(checkH2, peerCommitMessageData->H2, 32) != 0) { free (messageData); return BZRTP_PARSER_ERROR_UNMATCHINGHASHCHAIN; } /* Check the Commit MAC message. * MAC is 8 bytes long and is computed on the message(skip the ZRTP_PACKET_HEADER) and exclude the mac itself (-8 bytes from message Length) */ bctbx_hmacSha256(checkH1, 32, zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID]->messageLength-8, 8, checkMAC); if (memcmp(checkMAC, peerCommitMessageData->MAC, 8) != 0) { free (messageData); return BZRTP_PARSER_ERROR_UNMATCHINGMAC; } } else { /* if we are initiator(we didn't received any commit message and then no H2), we must check that H3=SHA256(SHA256(H1)) and the Hello message MAC */ uint8_t checkH2[32]; uint8_t checkH3[32]; uint8_t checkMAC[32]; bzrtpHelloMessage_t *peerHelloMessageData; if (zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID] == NULL) { free (messageData); /* we have no Hello message in this channel, this Confirm1 shall never have arrived, discard it as invalid */ return BZRTP_PARSER_ERROR_UNEXPECTEDMESSAGE; } peerHelloMessageData = (bzrtpHelloMessage_t *)zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->messageData; /* Check H3 = SHA256(SHA256(H1)) */ bctbx_sha256(checkH1, 32, 32, checkH2); bctbx_sha256(checkH2, 32, 32, checkH3); if (memcmp(checkH3, peerHelloMessageData->H3, 32) != 0) { free (messageData); return BZRTP_PARSER_ERROR_UNMATCHINGHASHCHAIN; } /* Check the hello MAC message. * MAC is 8 bytes long and is computed on the message(skip the ZRTP_PACKET_HEADER) and exclude the mac itself (-8 bytes from message Length) */ bctbx_hmacSha256(checkH2, 32, zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->messageLength-8, 8, checkMAC); if (memcmp(checkMAC, peerHelloMessageData->MAC, 8) != 0) { free (messageData); return BZRTP_PARSER_ERROR_UNMATCHINGMAC; } } } else { /* we are in DHM mode */ /* We have now H0, check it matches the H1 we had in the DHPart message H1=SHA256(H0) and that the DHPart message MAC is correct */ uint8_t checkH1[32]; uint8_t checkMAC[32]; bzrtpDHPartMessage_t *peerDHPartMessageData; if (zrtpChannelContext->peerPackets[DHPART_MESSAGE_STORE_ID] == NULL) { free (messageData); /* we have no DHPART message in this channel, this confirm shall never have arrived, discard it as invalid */ return BZRTP_PARSER_ERROR_UNEXPECTEDMESSAGE; } peerDHPartMessageData = (bzrtpDHPartMessage_t *)zrtpChannelContext->peerPackets[DHPART_MESSAGE_STORE_ID]->messageData; /* Check H1 = SHA256(H0) */ bctbx_sha256(messageData->H0, 32, 32, checkH1); if (memcmp(checkH1, peerDHPartMessageData->H1, 32) != 0) { free (messageData); return BZRTP_PARSER_ERROR_UNMATCHINGHASHCHAIN; } /* Check the DHPart message. * MAC is 8 bytes long and is computed on the message(skip the ZRTP_PACKET_HEADER) and exclude the mac itself (-8 bytes from message Length) */ bctbx_hmacSha256(messageData->H0, 32, zrtpChannelContext->peerPackets[DHPART_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[DHPART_MESSAGE_STORE_ID]->messageLength-8, 8, checkMAC); if (memcmp(checkMAC, peerDHPartMessageData->MAC, 8) != 0) { free (messageData); return BZRTP_PARSER_ERROR_UNMATCHINGMAC; } } messageData->sig_len = ((uint16_t)(confirmPlainMessage[0]&0x01))<<8 | (((uint16_t)confirmPlainMessage[1])&0x00FF); confirmPlainMessage += 2; messageData->E = ((*confirmPlainMessage)&0x08)>>3; messageData->V = ((*confirmPlainMessage)&0x04)>>2; messageData->A = ((*confirmPlainMessage)&0x02)>>1; messageData->D = (*confirmPlainMessage)&0x01; confirmPlainMessage += 1; messageData->cacheExpirationInterval = (((uint32_t)confirmPlainMessage[0])<<24) | (((uint32_t)confirmPlainMessage[1])<<16) | (((uint32_t)confirmPlainMessage[2])<<8) | ((uint32_t)confirmPlainMessage[3]); confirmPlainMessage += 4; /* if sig_len indicate a signature, parse it */ if (messageData->sig_len>0) { memcpy(messageData->signatureBlockType, confirmPlainMessage, 4); confirmPlainMessage += 4; /* allocate memory for the signature block, sig_len is in words(32 bits) and includes the signature block type word */ messageData->signatureBlock = (uint8_t *)malloc(4*(messageData->sig_len-1)*sizeof(uint8_t)); memcpy(messageData->signatureBlock, confirmPlainMessage, 4*(messageData->sig_len-1)); } else { messageData->signatureBlock = NULL; } /* free plain buffer */ free(confirmPlainMessageBuffer); /* the parsed commit packet must be saved as it is used to check correct packet repetition */ zrtpPacket->packetString = (uint8_t *)malloc(inputLength*sizeof(uint8_t)); memcpy(zrtpPacket->packetString, input, inputLength); /* store the whole packet even if we may use the message only */ /* attach the message structure to the packet one */ zrtpPacket->messageData = (void *)messageData; } break; /* MSGTYPE_CONFIRM1 and MSGTYPE_CONFIRM2 */ case MSGTYPE_CONF2ACK: /* nothing to do for this one */ break; /* MSGTYPE_CONF2ACK */ case MSGTYPE_PING: { /* allocate a ping message structure */ bzrtpPingMessage_t *messageData; messageData = (bzrtpPingMessage_t *)malloc(sizeof(bzrtpPingMessage_t)); /* fill the structure */ memcpy(messageData->version, messageContent, 4); messageContent +=4; memcpy(messageData->endpointHash, messageContent, 8); /* attach the message structure to the packet one */ zrtpPacket->messageData = (void *)messageData; } break; /* MSGTYPE_PING */ } return 0; } /* Create the packet string from the messageData contained into the zrtp Packet structure */ int bzrtp_packetBuild(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext, bzrtpPacket_t *zrtpPacket, uint16_t sequenceNumber) { int i; uint8_t *messageTypeString; uint8_t *messageString = NULL; /* will point directly to the begining of the message within the packetString buffer */ uint8_t *MACbuffer = NULL; /* if needed this will point to the beginin of the MAC in the packetString buffer */ /*uint8_t *MACMessageData = NULL; */ /* if needed this will point to the MAC field in the message Data structure */ uint8_t *MACkey = NULL; /* checks */ if (zrtpPacket==NULL) { return BZRTP_BUILDER_ERROR_INVALIDPACKET; } /* get the message type (and check it is valid) */ messageTypeString = messageTypeInttoString(zrtpPacket->messageType); if (messageTypeString == NULL) { return BZRTP_BUILDER_ERROR_INVALIDMESSAGETYPE; } /* create first the message. Header and CRC will be added afterward */ switch (zrtpPacket->messageType) { case MSGTYPE_HELLO : { bzrtpHelloMessage_t *messageData; /* get the Hello message structure */ if (zrtpPacket->messageData == NULL) { return BZRTP_BUILDER_ERROR_INVALIDMESSAGE; } messageData = (bzrtpHelloMessage_t *)zrtpPacket->messageData; /* compute the message length in bytes : fixed length and optionnal algorithms parts */ zrtpPacket->messageLength = ZRTP_HELLOMESSAGE_FIXED_LENGTH + 4*((uint16_t)(messageData->hc)+(uint16_t)(messageData->cc)+(uint16_t)(messageData->ac)+(uint16_t)(messageData->kc)+(uint16_t)(messageData->sc)); /* allocate the packetString buffer : packet is header+message+crc */ zrtpPacket->packetString = (uint8_t *)malloc((ZRTP_PACKET_HEADER_LENGTH+zrtpPacket->messageLength+ZRTP_PACKET_CRC_LENGTH)*sizeof(uint8_t)); /* have the messageString pointer to the begining of message(after the message header wich is computed for all messages after the switch) * within the packetString buffer*/ messageString = zrtpPacket->packetString + ZRTP_PACKET_HEADER_LENGTH + ZRTP_MESSAGE_HEADER_LENGTH; /* set the version (shall be 1.10), Client identifier, H3, ZID, S,M,P flags and hc,cc,ac,kc,sc */ memcpy(messageString, messageData->version, 4); messageString += 4; memcpy(messageString, messageData->clientIdentifier, 16); messageString += 16; memcpy(messageString, messageData->H3, 32); messageString += 32; memcpy(messageString, messageData->ZID, 12); messageString += 12; *messageString = ((((messageData->S)&0x01)<<6) | (((messageData->M)&0x01)<<5) | (((messageData->P)&0x01)<<4))&0x70; messageString += 1; *messageString = (messageData->hc)&0x0F; messageString += 1; *messageString = (((messageData->cc)<<4)&0xF0) | ((messageData->ac)&0x0F) ; messageString += 1; *messageString = (((messageData->kc)<<4)&0xF0) | ((messageData->sc)&0x0F) ; messageString += 1; /* now set optionnal supported algorithms */ for (i=0; ihc; i++) { bzrtp_cryptoAlgoTypeIntToString(messageData->supportedHash[i], messageString); messageString +=4; } for (i=0; icc; i++) { bzrtp_cryptoAlgoTypeIntToString(messageData->supportedCipher[i], messageString); messageString +=4; } for (i=0; iac; i++) { bzrtp_cryptoAlgoTypeIntToString(messageData->supportedAuthTag[i], messageString); messageString +=4; } for (i=0; ikc; i++) { bzrtp_cryptoAlgoTypeIntToString(messageData->supportedKeyAgreement[i], messageString); messageString +=4; } for (i=0; isc; i++) { bzrtp_cryptoAlgoTypeIntToString(messageData->supportedSas[i], messageString); messageString +=4; } /* there is a MAC to compute, set the pointers to the key and MAC output buffer */ MACbuffer = messageString; MACkey = zrtpChannelContext->selfH[2]; /* HMAC of Hello packet is keyed by H2 which have been set at context initialising */ } break; /* MSGTYPE_HELLO */ case MSGTYPE_HELLOACK : { /* the message length is fixed */ zrtpPacket->messageLength = ZRTP_HELLOACKMESSAGE_FIXED_LENGTH; /* allocate the packetString buffer : packet is header+message+crc */ zrtpPacket->packetString = (uint8_t *)malloc((ZRTP_PACKET_HEADER_LENGTH+ZRTP_HELLOACKMESSAGE_FIXED_LENGTH+ZRTP_PACKET_CRC_LENGTH)*sizeof(uint8_t)); } break; /* MSGTYPE_HELLOACK */ case MSGTYPE_COMMIT : { bzrtpCommitMessage_t *messageData; uint16_t variableLength = 0; /* get the Commit message structure */ if (zrtpPacket->messageData == NULL) { return BZRTP_BUILDER_ERROR_INVALIDMESSAGE; } messageData = (bzrtpCommitMessage_t *)zrtpPacket->messageData; /* compute message length */ switch(messageData->keyAgreementAlgo) { case ZRTP_KEYAGREEMENT_DH2k : case ZRTP_KEYAGREEMENT_EC25 : case ZRTP_KEYAGREEMENT_DH3k : case ZRTP_KEYAGREEMENT_EC38 : case ZRTP_KEYAGREEMENT_EC52 : variableLength = 32; /* hvi is 32 bytes length in DH Commit message format */ break; case ZRTP_KEYAGREEMENT_Prsh : variableLength = 24; /* nonce (16 bytes) and keyID(8 bytes) are 24 bytes length in preshared Commit message format */ break; case ZRTP_KEYAGREEMENT_Mult : variableLength = 16; /* nonce is 24 bytes length in multistream Commit message format */ break; default: return BZRTP_BUILDER_ERROR_INVALIDMESSAGE; } zrtpPacket->messageLength = ZRTP_COMMITMESSAGE_FIXED_LENGTH + variableLength; /* allocate the packetString buffer : packet is header+message+crc */ zrtpPacket->packetString = (uint8_t *)malloc((ZRTP_PACKET_HEADER_LENGTH+zrtpPacket->messageLength+ZRTP_PACKET_CRC_LENGTH)*sizeof(uint8_t)); /* have the messageString pointer to the begining of message(after the message header wich is computed for all messages after the switch) * within the packetString buffer*/ messageString = zrtpPacket->packetString + ZRTP_PACKET_HEADER_LENGTH + ZRTP_MESSAGE_HEADER_LENGTH; /* now insert the different message parts into the packetString */ memcpy(messageString, messageData->H2, 32); messageString += 32; memcpy(messageString, messageData->ZID, 12); messageString += 12; bzrtp_cryptoAlgoTypeIntToString(messageData->hashAlgo, messageString); messageString += 4; bzrtp_cryptoAlgoTypeIntToString(messageData->cipherAlgo, messageString); messageString += 4; bzrtp_cryptoAlgoTypeIntToString(messageData->authTagAlgo, messageString); messageString += 4; bzrtp_cryptoAlgoTypeIntToString(messageData->keyAgreementAlgo, messageString); messageString += 4; bzrtp_cryptoAlgoTypeIntToString(messageData->sasAlgo, messageString); messageString += 4; /* if it is a multistream or preshared commit insert the 16 bytes nonce */ if ((messageData->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Prsh) || (messageData->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Mult)) { memcpy(messageString, messageData->nonce, 16); messageString += 16; /* and the keyID for preshared commit only */ if (messageData->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Prsh) { memcpy(messageString, messageData->keyID, 8); messageString +=8; } } else { /* it's a DH commit message, set the hvi */ memcpy(messageString, messageData->hvi, 32); messageString +=32; } /* there is a MAC to compute, set the pointers to the key and MAC output buffer */ MACbuffer = messageString; MACkey = zrtpChannelContext->selfH[1]; /* HMAC of Hello packet is keyed by H1 which have been set at context initialising */ } break; /*MSGTYPE_COMMIT */ case MSGTYPE_DHPART1 : case MSGTYPE_DHPART2 : { bzrtpDHPartMessage_t *messageData; uint16_t pvLength; /* get the DHPart message structure */ if (zrtpPacket->messageData == NULL) { return BZRTP_BUILDER_ERROR_INVALIDMESSAGE; } messageData = (bzrtpDHPartMessage_t *)zrtpPacket->messageData; /* compute message length */ pvLength = computeKeyAgreementPrivateValueLength(zrtpChannelContext->keyAgreementAlgo); if (pvLength==0) { return BZRTP_BUILDER_ERROR_INVALIDCONTEXT; } zrtpPacket->messageLength = ZRTP_DHPARTMESSAGE_FIXED_LENGTH + pvLength; /* allocate the packetString buffer : packet is header+message+crc */ zrtpPacket->packetString = (uint8_t *)malloc((ZRTP_PACKET_HEADER_LENGTH+zrtpPacket->messageLength+ZRTP_PACKET_CRC_LENGTH)*sizeof(uint8_t)); /* have the messageString pointer to the begining of message(after the message header wich is computed for all messages after the switch) * within the packetString buffer*/ messageString = zrtpPacket->packetString + ZRTP_PACKET_HEADER_LENGTH + ZRTP_MESSAGE_HEADER_LENGTH; /* now insert the different message parts into the packetString */ memcpy(messageString, messageData->H1, 32); messageString += 32; memcpy(messageString, messageData->rs1ID, 8); messageString += 8; memcpy(messageString, messageData->rs2ID, 8); messageString += 8; memcpy(messageString, messageData->auxsecretID, 8); messageString += 8; memcpy(messageString, messageData->pbxsecretID, 8); messageString += 8; memcpy(messageString, messageData->pv, pvLength); messageString += pvLength; /* there is a MAC to compute, set the pointers to the key and MAC output buffer */ MACbuffer = messageString; MACkey = zrtpChannelContext->selfH[0]; /* HMAC of Hello packet is keyed by H0 which have been set at context initialising */ } break; /* MSGTYPE_DHPART1 and 2 */ case MSGTYPE_CONFIRM1: case MSGTYPE_CONFIRM2: { uint8_t *confirmMessageKey = NULL; uint8_t *confirmMessageMacKey = NULL; bzrtpConfirmMessage_t *messageData; uint16_t encryptedPartLength; uint8_t *plainMessageString; uint16_t plainMessageStringIndex = 0; /* we will have to encrypt and validate the message, check we have the keys to do it */ if (zrtpChannelContext->role == BZRTP_ROLE_INITIATOR) { if ((zrtpChannelContext->zrtpkeyi == NULL) || (zrtpChannelContext->mackeyi == NULL)) { return BZRTP_BUILDER_ERROR_INVALIDCONTEXT; } confirmMessageKey = zrtpChannelContext->zrtpkeyi; confirmMessageMacKey = zrtpChannelContext->mackeyi; } if (zrtpChannelContext->role == BZRTP_ROLE_RESPONDER) { if ((zrtpChannelContext->zrtpkeyr == NULL) || (zrtpChannelContext->mackeyr == NULL)) { return BZRTP_BUILDER_ERROR_INVALIDCONTEXT; } confirmMessageKey = zrtpChannelContext->zrtpkeyr; confirmMessageMacKey = zrtpChannelContext->mackeyr; } /* get the Confirm message structure */ if (zrtpPacket->messageData == NULL) { return BZRTP_BUILDER_ERROR_INVALIDMESSAGE; } messageData = (bzrtpConfirmMessage_t *)zrtpPacket->messageData; /* compute message length */ zrtpPacket->messageLength = ZRTP_CONFIRMMESSAGE_FIXED_LENGTH + messageData->sig_len*4; /* sig_len is in word of 4 bytes */ /* allocate the packetString buffer : packet is header+message+crc */ zrtpPacket->packetString = (uint8_t *)malloc((ZRTP_PACKET_HEADER_LENGTH+zrtpPacket->messageLength+ZRTP_PACKET_CRC_LENGTH)*sizeof(uint8_t)); /* have the messageString pointer to the begining of message(after the message header wich is computed for all messages after the switch) * within the packetString buffer*/ messageString = zrtpPacket->packetString + ZRTP_PACKET_HEADER_LENGTH + ZRTP_MESSAGE_HEADER_LENGTH; /* allocate a temporary buffer to store the plain text */ encryptedPartLength = zrtpPacket->messageLength - ZRTP_MESSAGE_HEADER_LENGTH - 24; /* message header, confirm_mac(8 bytes) and CFB IV(16 bytes) are not encrypted */ plainMessageString = (uint8_t *)malloc(encryptedPartLength*sizeof(uint8_t)); /* fill the plain message buffer with data from the message structure */ memcpy(plainMessageString, messageData->H0, 32); plainMessageStringIndex += 32; plainMessageString[plainMessageStringIndex++] = 0x00; plainMessageString[plainMessageStringIndex++] = (uint8_t)(((messageData->sig_len)>>8)&0x0001); plainMessageString[plainMessageStringIndex++] = (uint8_t)((messageData->sig_len)&0x00FF); plainMessageString[plainMessageStringIndex++] = (uint8_t)((messageData->E&0x01)<<3) | (uint8_t)((messageData->V&0x01)<<2) | (uint8_t)((messageData->A&0x01)<<1) | (uint8_t)(messageData->D&0x01) ; /* cache expiration in a 32 bits unsigned int */ plainMessageString[plainMessageStringIndex++] = (uint8_t)((messageData->cacheExpirationInterval>>24)&0xFF); plainMessageString[plainMessageStringIndex++] = (uint8_t)((messageData->cacheExpirationInterval>>16)&0xFF); plainMessageString[plainMessageStringIndex++] = (uint8_t)((messageData->cacheExpirationInterval>>8)&0xFF); plainMessageString[plainMessageStringIndex++] = (uint8_t)((messageData->cacheExpirationInterval)&0xFF); if (messageData->sig_len>0) { memcpy(plainMessageString+plainMessageStringIndex, messageData->signatureBlockType, 4); plainMessageStringIndex += 4; /* sig_len is in 4 bytes words and include the 1 word of signature block type */ memcpy(plainMessageString+plainMessageStringIndex, messageData->signatureBlock, (messageData->sig_len-1)*4); } /* encrypt the buffer, set the output directly in the messageString buffer at the correct position(+24 after message header) */ zrtpChannelContext->cipherEncryptionFunction(confirmMessageKey, messageData->CFBIV, plainMessageString, encryptedPartLength, messageString+24); free(plainMessageString); /* free the plain message string temporary buffer */ /* compute the mac over the encrypted part of the message and set the result in the messageString */ zrtpChannelContext->hmacFunction(confirmMessageMacKey, zrtpChannelContext->hashLength, messageString+24, encryptedPartLength, 8, messageString); messageString += 8; /* add the CFB IV */ memcpy(messageString, messageData->CFBIV, 16); } break; /* MSGTYPE_CONFIRM1 and MSGTYPE_CONFIRM2 */ case MSGTYPE_CONF2ACK: { /* the message length is fixed */ zrtpPacket->messageLength = ZRTP_CONF2ACKMESSAGE_FIXED_LENGTH; /* allocate the packetString buffer : packet is header+message+crc */ zrtpPacket->packetString = (uint8_t *)malloc((ZRTP_PACKET_HEADER_LENGTH+ZRTP_CONF2ACKMESSAGE_FIXED_LENGTH+ZRTP_PACKET_CRC_LENGTH)*sizeof(uint8_t)); } break; /* MSGTYPE_CONF2ACK */ case MSGTYPE_PINGACK: { bzrtpPingAckMessage_t *messageData; /* the message length is fixed */ zrtpPacket->messageLength = ZRTP_PINGACKMESSAGE_FIXED_LENGTH; /* allocate the packetString buffer : packet is header+message+crc */ zrtpPacket->packetString = (uint8_t *)malloc((ZRTP_PACKET_HEADER_LENGTH+ZRTP_PINGACKMESSAGE_FIXED_LENGTH+ZRTP_PACKET_CRC_LENGTH)*sizeof(uint8_t)); messageString = zrtpPacket->packetString + ZRTP_PACKET_HEADER_LENGTH + ZRTP_MESSAGE_HEADER_LENGTH; /* now insert the different message parts into the packetString */ messageData = (bzrtpPingAckMessage_t *)zrtpPacket->messageData; memcpy(messageString, messageData->version, 4); messageString += 4; memcpy(messageString, messageData->endpointHash, 8); messageString += 8; memcpy(messageString, messageData->endpointHashReceived, 8); messageString += 8; *messageString++ = (uint8_t)((messageData->SSRC>>24)&0xFF); *messageString++ = (uint8_t)((messageData->SSRC>>16)&0xFF); *messageString++ = (uint8_t)((messageData->SSRC>>8)&0xFF); *messageString++ = (uint8_t)(messageData->SSRC&0xFF); } break; /* MSGTYPE_PINGACK */ } /* write headers only if we have a packet string */ if (zrtpPacket->packetString != NULL) { uint32_t CRC; uint8_t *CRCbuffer; zrtpMessageSetHeader(zrtpPacket->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpPacket->messageLength, messageTypeString); /* Do we have a MAC to compute on the message ? */ if (MACbuffer != NULL) { /* compute the MAC(64 bits only) using the implicit HMAC function for ZRTP v1.10: HMAC-SHA256 */ /* HMAC is computed on the whole message except the MAC itself so a length of zrtpPacket->messageLength-8 */ bctbx_hmacSha256(MACkey, 32, zrtpPacket->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpPacket->messageLength-8, 8, MACbuffer); } /* set packet header and CRC */ /* preambule */ zrtpPacket->packetString[0] = 0x10; zrtpPacket->packetString[1] = 0x00; /* Sequence number */ zrtpPacket->packetString[2] = (uint8_t)((sequenceNumber>>8)&0x00FF); zrtpPacket->packetString[3] = (uint8_t)(sequenceNumber&0x00FF); /* ZRTP magic cookie */ zrtpPacket->packetString[4] = (uint8_t)((ZRTP_MAGIC_COOKIE>>24)&0xFF); zrtpPacket->packetString[5] = (uint8_t)((ZRTP_MAGIC_COOKIE>>16)&0xFF); zrtpPacket->packetString[6] = (uint8_t)((ZRTP_MAGIC_COOKIE>>8)&0xFF); zrtpPacket->packetString[7] = (uint8_t)(ZRTP_MAGIC_COOKIE&0xFF); /* Source Identifier */ zrtpPacket->packetString[8] = (uint8_t)(((zrtpPacket->sourceIdentifier)>>24)&0xFF); zrtpPacket->packetString[9] = (uint8_t)(((zrtpPacket->sourceIdentifier)>>16)&0xFF); zrtpPacket->packetString[10] = (uint8_t)(((zrtpPacket->sourceIdentifier)>>8)&0xFF); zrtpPacket->packetString[11] = (uint8_t)((zrtpPacket->sourceIdentifier)&0xFF); /* CRC */ CRC = bzrtp_CRC32(zrtpPacket->packetString, zrtpPacket->messageLength+ZRTP_PACKET_HEADER_LENGTH); CRCbuffer = (zrtpPacket->packetString)+(zrtpPacket->messageLength)+ZRTP_PACKET_HEADER_LENGTH; *CRCbuffer = (uint8_t)((CRC>>24)&0xFF); CRCbuffer++; *CRCbuffer = (uint8_t)((CRC>>16)&0xFF); CRCbuffer++; *CRCbuffer = (uint8_t)((CRC>>8)&0xFF); CRCbuffer++; *CRCbuffer = (uint8_t)(CRC&0xFF); return 0; } else { /* no packetString allocated something wen't wrong but we shall never arrive here */ return BZRTP_BUILDER_ERROR_UNKNOWN; } } /* create a zrtpPacket and initialise it's structures */ bzrtpPacket_t *bzrtp_createZrtpPacket(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext, uint32_t messageType, int *exitCode) { /* allocate packet */ bzrtpPacket_t *zrtpPacket = (bzrtpPacket_t *)malloc(sizeof(bzrtpPacket_t)); memset(zrtpPacket, 0, sizeof(bzrtpPacket_t)); zrtpPacket->messageData = NULL; zrtpPacket->packetString = NULL; /* initialise it */ switch(messageType) { case MSGTYPE_HELLO: { int i; bzrtpHelloMessage_t *zrtpHelloMessage = (bzrtpHelloMessage_t *)malloc(sizeof(bzrtpHelloMessage_t)); memset(zrtpHelloMessage, 0, sizeof(bzrtpHelloMessage_t)); /* initialise some fields using zrtp context data */ memcpy(zrtpHelloMessage->version, ZRTP_VERSION, 4); strncpy((char*)zrtpHelloMessage->clientIdentifier, ZRTP_CLIENT_IDENTIFIER, 16); zrtpHelloMessage->clientIdentifier[16]='\0'; /* be sure the clientIdentifier filed is a NULL terminated string */ memcpy(zrtpHelloMessage->H3, zrtpChannelContext->selfH[3], 32); memcpy(zrtpHelloMessage->ZID, zrtpContext->selfZID, 12); /* set all S,M,P flags to zero as we're not able to verify signatures, we're not a PBX(TODO: implement?), we're not passive */ zrtpHelloMessage->S = 0; zrtpHelloMessage->M = 0; zrtpHelloMessage->P = 0; /* get the algorithm availabilities from the context */ zrtpHelloMessage->hc = zrtpContext->hc; zrtpHelloMessage->cc = zrtpContext->cc; zrtpHelloMessage->ac = zrtpContext->ac; zrtpHelloMessage->kc = zrtpContext->kc; zrtpHelloMessage->sc = zrtpContext->sc; for (i=0; ihc; i++) { zrtpHelloMessage->supportedHash[i] = zrtpContext->supportedHash[i]; } for (i=0; icc; i++) { zrtpHelloMessage->supportedCipher[i] = zrtpContext->supportedCipher[i]; } for (i=0; iac; i++) { zrtpHelloMessage->supportedAuthTag[i] = zrtpContext->supportedAuthTag[i]; } for (i=0; ikc; i++) { zrtpHelloMessage->supportedKeyAgreement[i] = zrtpContext->supportedKeyAgreement[i]; } for (i=0; isc; i++) { zrtpHelloMessage->supportedSas[i] = zrtpContext->supportedSas[i]; } /* attach the message data to the packet */ zrtpPacket->messageData = zrtpHelloMessage; } break; /* MSGTYPE_HELLO */ case MSGTYPE_HELLOACK : { /* nothing to do for the Hello ACK packet as it just contains it's type */ } break; /* MSGTYPE_HELLOACK */ /* In case of DH commit, this one must be called after the DHPart build and the self DH message and peer Hello message are stored in the context */ case MSGTYPE_COMMIT : { bzrtpCommitMessage_t *zrtpCommitMessage = (bzrtpCommitMessage_t *)malloc(sizeof(bzrtpCommitMessage_t)); memset(zrtpCommitMessage, 0, sizeof(bzrtpCommitMessage_t)); /* initialise some fields using zrtp context data */ memcpy(zrtpCommitMessage->H2, zrtpChannelContext->selfH[2], 32); memcpy(zrtpCommitMessage->ZID, zrtpContext->selfZID, 12); zrtpCommitMessage->hashAlgo = zrtpChannelContext->hashAlgo; zrtpCommitMessage->cipherAlgo = zrtpChannelContext->cipherAlgo; zrtpCommitMessage->authTagAlgo = zrtpChannelContext->authTagAlgo; zrtpCommitMessage->keyAgreementAlgo = zrtpChannelContext->keyAgreementAlgo; zrtpCommitMessage->sasAlgo = zrtpChannelContext->sasAlgo; /* if it is a multistream or preshared commit create a 16 random bytes nonce */ if ((zrtpCommitMessage->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Prsh) || (zrtpCommitMessage->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Mult)) { bctbx_rng_get(zrtpContext->RNGContext, zrtpCommitMessage->nonce, 16); /* and the keyID for preshared commit only */ if (zrtpCommitMessage->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Prsh) { /* TODO at this point we must first compute the preShared key - make sure at least rs1 is present */ /* preshared_key = hash(len(rs1) || rs1 || len(auxsecret) || auxsecret || len(pbxsecret) || pbxsecret) using the agreed hash and store it into the env */ /* and then the keyID : MAC(preshared_key, "Prsh") truncated to 64 bits using the agreed MAC */ } } else { /* it's a DH commit message, set the hvi */ /* hvi = hash(initiator's DHPart2 message || responder's Hello message) using the agreed hash function truncated to 256 bits */ /* create a string with the messages concatenated */ uint16_t DHPartMessageLength = zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID]->messageLength; uint16_t HelloMessageLength = zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->messageLength; uint16_t DHPartHelloMessageStringLength = DHPartMessageLength + HelloMessageLength; uint8_t *DHPartHelloMessageString = (uint8_t *)malloc(DHPartHelloMessageStringLength*sizeof(uint8_t)); memcpy(DHPartHelloMessageString, zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, DHPartMessageLength); memcpy(DHPartHelloMessageString+DHPartMessageLength, zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, HelloMessageLength); zrtpChannelContext->hashFunction(DHPartHelloMessageString, DHPartHelloMessageStringLength, 32, zrtpCommitMessage->hvi); free(DHPartHelloMessageString); } /* attach the message data to the packet */ zrtpPacket->messageData = zrtpCommitMessage; } break; /* MSGTYPE_COMMIT */ /* this one is called after the exchange of Hello messages when the crypto algo agreement have been performed */ case MSGTYPE_DHPART1 : case MSGTYPE_DHPART2 : { uint8_t secretLength; /* is in bytes */ uint8_t bctbx_keyAgreementAlgo = BCTBX_DHM_UNSET; bzrtpDHPartMessage_t *zrtpDHPartMessage = (bzrtpDHPartMessage_t *)malloc(sizeof(bzrtpDHPartMessage_t)); memset(zrtpDHPartMessage, 0, sizeof(bzrtpDHPartMessage_t)); /* initialise some fields using zrtp context data */ memcpy(zrtpDHPartMessage->H1, zrtpChannelContext->selfH[1], 32); /* get the retained secret from context, we anyway create a DHPart2 packet that we may turn into a DHPart1 packet if we end to * be the responder and not the initiator, use the initiator retained secret hashes */ memcpy(zrtpDHPartMessage->rs1ID, zrtpContext->initiatorCachedSecretHash.rs1ID, 8); memcpy(zrtpDHPartMessage->rs2ID, zrtpContext->initiatorCachedSecretHash.rs2ID, 8); memcpy(zrtpDHPartMessage->auxsecretID, zrtpChannelContext->initiatorAuxsecretID, 8); memcpy(zrtpDHPartMessage->pbxsecretID, zrtpContext->initiatorCachedSecretHash.pbxsecretID, 8); /* compute the public value and insert it in the message, will then be used whatever role - initiator or responder - we assume */ /* initialise the dhm context, secret length shall be twice the size of cipher block key length - rfc section 5.1.5 */ switch (zrtpChannelContext->cipherAlgo) { case ZRTP_CIPHER_AES3: case ZRTP_CIPHER_2FS3: secretLength = 64; break; case ZRTP_CIPHER_AES2: case ZRTP_CIPHER_2FS2: secretLength = 48; break; case ZRTP_CIPHER_AES1: case ZRTP_CIPHER_2FS1: default: secretLength = 32; break; } switch (zrtpChannelContext->keyAgreementAlgo) { case ZRTP_KEYAGREEMENT_DH2k: bctbx_keyAgreementAlgo = BCTBX_DHM_2048; break; case ZRTP_KEYAGREEMENT_DH3k: bctbx_keyAgreementAlgo = BCTBX_DHM_3072; break; default: free(zrtpPacket); free(zrtpDHPartMessage); *exitCode = BZRTP_CREATE_ERROR_UNABLETOCREATECRYPTOCONTEXT; return NULL; break; } zrtpContext->DHMContext = bctbx_CreateDHMContext(bctbx_keyAgreementAlgo, secretLength); if (zrtpContext->DHMContext == NULL) { free(zrtpPacket); free(zrtpDHPartMessage); *exitCode = BZRTP_CREATE_ERROR_UNABLETOCREATECRYPTOCONTEXT; return NULL; } /* now compute the public value */ bctbx_DHMCreatePublic(zrtpContext->DHMContext, (int (*)(void *, uint8_t *, size_t))bctbx_rng_get, zrtpContext->RNGContext); zrtpDHPartMessage->pv = (uint8_t *)malloc((zrtpChannelContext->keyAgreementLength)*sizeof(uint8_t)); memcpy(zrtpDHPartMessage->pv, zrtpContext->DHMContext->self, zrtpChannelContext->keyAgreementLength); /* attach the message data to the packet */ zrtpPacket->messageData = zrtpDHPartMessage; } break; /* MSGTYPE_DHPART1 and MSGTYPE_DHPART2 */ case MSGTYPE_CONFIRM1: case MSGTYPE_CONFIRM2: { bzrtpConfirmMessage_t *zrtpConfirmMessage = (bzrtpConfirmMessage_t *)malloc(sizeof(bzrtpConfirmMessage_t)); memset(zrtpConfirmMessage, 0, sizeof(bzrtpConfirmMessage_t)); /* initialise some fields using zrtp context data */ memcpy(zrtpConfirmMessage->H0, zrtpChannelContext->selfH[0], 32); zrtpConfirmMessage->sig_len = 0; /* signature is not supported */ zrtpConfirmMessage->cacheExpirationInterval = 0xFFFFFFFF; /* expiration interval is set to unlimited as recommended in rfc section 4.9 */ zrtpConfirmMessage->E = 0; /* we are not a PBX and then will never signal an enrollment - rfc section 7.3.1 */ zrtpConfirmMessage->V = zrtpContext->cachedSecret.previouslyVerifiedSas; zrtpConfirmMessage->A = 0; /* Go clear message is not supported - rfc section 4.7.2 */ zrtpConfirmMessage->D = 0; /* The is no backdoor in our implementation of ZRTP - rfc section 11 */ /* generate a random CFB IV */ bctbx_rng_get(zrtpContext->RNGContext, zrtpConfirmMessage->CFBIV, 16); /* attach the message data to the packet */ zrtpPacket->messageData = zrtpConfirmMessage; } break; /* MSGTYPE_CONFIRM1 and MSGTYPE_CONFIRM2 */ case MSGTYPE_CONF2ACK : { /* nothing to do for the conf2ACK packet as it just contains it's type */ } break; /* MSGTYPE_CONF2ACK */ case MSGTYPE_PINGACK: { bzrtpPingMessage_t *pingMessage; bzrtpPingAckMessage_t *zrtpPingAckMessage; /* to create a pingACK we must have a ping packet in the channel context, check it */ bzrtpPacket_t *pingPacket = zrtpChannelContext->pingPacket; if (pingPacket == NULL) { *exitCode = BZRTP_CREATE_ERROR_INVALIDCONTEXT; return NULL; } pingMessage = (bzrtpPingMessage_t *)pingPacket->messageData; /* create the message */ zrtpPingAckMessage = (bzrtpPingAckMessage_t *)malloc(sizeof(bzrtpPingAckMessage_t)); memset(zrtpPingAckMessage, 0, sizeof(bzrtpPingAckMessage_t)); /* initialise all fields using zrtp context data and the received ping message */ memcpy(zrtpPingAckMessage->version,ZRTP_VERSION , 4); /* we support version 1.10 only, so no need to even check what was sent in the ping */ memcpy(zrtpPingAckMessage->endpointHash, zrtpContext->selfZID, 8); /* as suggested in rfc section 5.16, use the truncated ZID as endPoint hash */ memcpy(zrtpPingAckMessage->endpointHashReceived, pingMessage->endpointHash, 8); zrtpPingAckMessage->SSRC = pingPacket->sourceIdentifier; /* attach the message data to the packet */ zrtpPacket->messageData = zrtpPingAckMessage; } /* MSGTYPE_PINGACK */ break; default: free(zrtpPacket); *exitCode = BZRTP_CREATE_ERROR_INVALIDMESSAGETYPE; return NULL; break; } zrtpPacket->sequenceNumber = 0; /* this field is not used buy the packet creator, sequence number is given as a parameter when converting the message to a packet string(packet build). Used only when parsing a string into a packet struct */ zrtpPacket->messageType = messageType; zrtpPacket->sourceIdentifier = zrtpChannelContext->selfSSRC; zrtpPacket->messageLength = 0; /* length will be computed at packet build */ zrtpPacket->packetString = NULL; *exitCode=0; return zrtpPacket; } void bzrtp_freeZrtpPacket(bzrtpPacket_t *zrtpPacket) { if (zrtpPacket != NULL) { /* some messages have fields to be freed */ if (zrtpPacket->messageData != NULL) { switch(zrtpPacket->messageType) { case MSGTYPE_DHPART1 : case MSGTYPE_DHPART2 : { bzrtpDHPartMessage_t *typedMessageData = (bzrtpDHPartMessage_t *)(zrtpPacket->messageData); if (typedMessageData != NULL) { free(typedMessageData->pv); } } break; case MSGTYPE_CONFIRM1: case MSGTYPE_CONFIRM2: { bzrtpConfirmMessage_t *typedMessageData = (bzrtpConfirmMessage_t *)(zrtpPacket->messageData); if (typedMessageData != NULL) { free(typedMessageData->signatureBlock); } } break; } } free(zrtpPacket->messageData); free(zrtpPacket->packetString); free(zrtpPacket); } } /** * @brief Modify the current sequence number of the packet in the packetString and sequenceNumber fields * The CRC at the end of packetString is also updated * * param[in/out] zrtpPacket The zrtpPacket to modify, the packetString must have been generated by * a call to bzrtp_packetBuild on this packet * param[in] sequenceNumber The new sequence number to insert in the packetString * * return 0 on succes, error code otherwise */ int bzrtp_packetUpdateSequenceNumber(bzrtpPacket_t *zrtpPacket, uint16_t sequenceNumber) { uint32_t CRC; uint8_t *CRCbuffer; if (zrtpPacket == NULL) { return BZRTP_BUILDER_ERROR_INVALIDPACKET; } if (zrtpPacket->packetString == NULL) { return BZRTP_BUILDER_ERROR_INVALIDPACKET; } /* update the sequence number field (even if it is probably useless as this function is called just before sending the DHPart2 packet only)*/ zrtpPacket->sequenceNumber = sequenceNumber; /* update hte sequence number in the packetString */ *(zrtpPacket->packetString+2)= (uint8_t)((sequenceNumber>>8)&0x00FF); *(zrtpPacket->packetString+3)= (uint8_t)(sequenceNumber&0x00FF); /* update the CRC */ CRC = bzrtp_CRC32(zrtpPacket->packetString, zrtpPacket->messageLength+ZRTP_PACKET_HEADER_LENGTH); CRCbuffer = (zrtpPacket->packetString)+(zrtpPacket->messageLength)+ZRTP_PACKET_HEADER_LENGTH; *CRCbuffer = (uint8_t)((CRC>>24)&0xFF); CRCbuffer++; *CRCbuffer = (uint8_t)((CRC>>16)&0xFF); CRCbuffer++; *CRCbuffer = (uint8_t)((CRC>>8)&0xFF); CRCbuffer++; *CRCbuffer = (uint8_t)(CRC&0xFF); return 0; } /*** Local functions implementation ***/ uint8_t *messageTypeInttoString(uint32_t messageType) { switch(messageType) { case MSGTYPE_HELLO : return (uint8_t *)"Hello "; break; case MSGTYPE_HELLOACK : return (uint8_t *)"HelloACK"; break; case MSGTYPE_COMMIT : return (uint8_t *)"Commit "; break; case MSGTYPE_DHPART1 : return (uint8_t *)"DHPart1 "; break; case MSGTYPE_DHPART2 : return (uint8_t *)"DHPart2 "; break; case MSGTYPE_CONFIRM1 : return (uint8_t *)"Confirm1"; break; case MSGTYPE_CONFIRM2 : return (uint8_t *)"Confirm2"; break; case MSGTYPE_CONF2ACK : return (uint8_t *)"Conf2ACK"; break; case MSGTYPE_ERROR : return (uint8_t *)"Error "; break; case MSGTYPE_ERRORACK : return (uint8_t *)"ErrorACK"; break; case MSGTYPE_GOCLEAR : return (uint8_t *)"GoClear "; break; case MSGTYPE_CLEARACK : return (uint8_t *)"ClearACK"; break; case MSGTYPE_SASRELAY : return (uint8_t *)"SASrelay"; break; case MSGTYPE_RELAYACK : return (uint8_t *)"RelayACK"; break; case MSGTYPE_PING : return (uint8_t *)"Ping "; break; case MSGTYPE_PINGACK : return (uint8_t *)"PingACK "; break; } return NULL; } /* * @brief Map the 8 char string value message type to an int32_t * * @param[in] messageTypeString an 8 bytes string matching a zrtp message type * * @return a 32-bits unsigned integer mapping the message type */ int32_t messageTypeStringtoInt(uint8_t messageTypeString[8]) { if (memcmp(messageTypeString, "Hello ", 8) == 0) { return MSGTYPE_HELLO; } else if (memcmp(messageTypeString, "HelloACK", 8) == 0) { return MSGTYPE_HELLOACK; } else if (memcmp(messageTypeString, "Commit ", 8) == 0) { return MSGTYPE_COMMIT; } else if (memcmp(messageTypeString, "DHPart1 ", 8) == 0) { return MSGTYPE_DHPART1; } else if (memcmp(messageTypeString, "DHPart2 ", 8) == 0) { return MSGTYPE_DHPART2; } else if (memcmp(messageTypeString, "Confirm1", 8) == 0) { return MSGTYPE_CONFIRM1; } else if (memcmp(messageTypeString, "Confirm2", 8) == 0) { return MSGTYPE_CONFIRM2; } else if (memcmp(messageTypeString, "Conf2ACK", 8) == 0) { return MSGTYPE_CONF2ACK; } else if (memcmp(messageTypeString, "Error ", 8) == 0) { return MSGTYPE_ERROR; } else if (memcmp(messageTypeString, "ErrorACK", 8) == 0) { return MSGTYPE_ERRORACK; } else if (memcmp(messageTypeString, "GoClear ", 8) == 0) { return MSGTYPE_GOCLEAR; } else if (memcmp(messageTypeString, "ClearACK", 8) == 0) { return MSGTYPE_CLEARACK; } else if (memcmp(messageTypeString, "SASrelay", 8) == 0) { return MSGTYPE_SASRELAY; } else if (memcmp(messageTypeString, "RelayACK", 8) == 0) { return MSGTYPE_RELAYACK; } else if (memcmp(messageTypeString, "Ping ", 8) == 0) { return MSGTYPE_PING; } else if (memcmp(messageTypeString, "PingACK ", 8) == 0) { return MSGTYPE_PINGACK; } else { return MSGTYPE_INVALID; } } /* * @brief Write the message header(preambule, length, message type) into the given output buffer * * @param[out] outputBuffer Message starts at the begining of this buffer * @param[in] messageLength Message length in bytes! To be converted into 32bits words before being inserted in the message header * @param[in] messageType An 8 chars string for the message type (validity is not checked by this function) * */ void zrtpMessageSetHeader(uint8_t *outputBuffer, uint16_t messageLength, uint8_t messageType[8]) { /* insert the preambule */ outputBuffer[0] = 0x50; outputBuffer[1] = 0x5a; /* then the length in 32 bits words (param is in bytes, so >> 2) */ outputBuffer[2] = (uint8_t)((messageLength>>10)&0x00FF); outputBuffer[3] = (uint8_t)((messageLength>>2)&0x00FF); /* the message type */ memcpy(outputBuffer+4, messageType, 8); } /* * Return the variable private value length in bytes according to given key agreement algorythm * * @param[in] keyAgreementAlgo The key agreement algo mapped to an integer as defined in cryptoWrapper.h * * @return the private value length in bytes * */ uint16_t computeKeyAgreementPrivateValueLength(uint8_t keyAgreementAlgo) { uint16_t pvLength = 0; switch (keyAgreementAlgo) { case ZRTP_KEYAGREEMENT_DH3k : pvLength = 384; break; case ZRTP_KEYAGREEMENT_DH2k : pvLength = 256; break; case ZRTP_KEYAGREEMENT_EC25 : pvLength = 64; break; case ZRTP_KEYAGREEMENT_EC38 : pvLength = 96; break; case ZRTP_KEYAGREEMENT_EC52 : pvLength = 132; break; default : pvLength = 0; break; } return pvLength; } bzrtp-1.0.6/src/pgpwords.c000066400000000000000000000202011313411235300154460ustar00rootroot00000000000000// https://tools.ietf.org/html/rfc6189 // For the SAS Type of "B256", the most-significant (leftmost) 16 bits // of the 32-bit sasvalue are rendered in network byte order using the // PGP Word List [pgpwordlist] [Juola1][Juola2]. const char * pgpWordsEven[] = { "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" }; const char * pgpWordsOdd[] = { "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" }; bzrtp-1.0.6/src/stateMachine.c000066400000000000000000003316441313411235300162260ustar00rootroot00000000000000/** @file stateMachine.c @brief The state machine implementing the ZRTP protocol each state is defined as u function pointer and on arrival of a new event after sanity checks, the state function is called giving the event as parameter @author Johan Pascal @copyright Copyright (C) 2014 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include "typedef.h" #include "packetParser.h" #include "cryptoUtils.h" #include "zidCache.h" #include #include "stateMachine.h" /* Local functions prototypes */ int bzrtp_turnIntoResponder(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext, bzrtpPacket_t *zrtpPacket, bzrtpCommitMessage_t *commitMessage); int bzrtp_responseToHelloMessage(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext, bzrtpPacket_t *zrtpPacket); int bzrtp_computeS0DHMMode(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext); int bzrtp_computeS0MultiStreamMode(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext); int bzrtp_deriveKeysFromS0(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext); int bzrtp_deriveSrtpKeysFromS0(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext); int bzrtp_updateCachedSecrets(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext); /* * @brief This is the initial state * On first call, we will create the Hello message and start sending it until we receive an helloACK or a hello message from peer * * Arrives from : * - This is the initial state * Goes to: * - state_discovery_waitingForHello upon HelloACK reception * - state_discovery_waitingForHelloAck upon Hello reception * Send : * - Hello until timer's end or transition */ int state_discovery_init(bzrtpEvent_t event) { /* get the contextes from the event */ bzrtpContext_t *zrtpContext = event.zrtpContext; bzrtpChannelContext_t *zrtpChannelContext = event.zrtpChannelContext; int retval; /*** Manage the first call to this function ***/ /* We are supposed to send Hello packet, it shall be already present int the selfPackets(created at channel init) */ if (event.eventType == BZRTP_EVENT_INIT) { if (zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID] == NULL) { /* We shall never go through this one because Hello packet shall be created at channel init */ int retval; /* create the Hello packet */ bzrtpPacket_t *helloPacket = bzrtp_createZrtpPacket(zrtpContext, zrtpChannelContext, MSGTYPE_HELLO, &retval); if (retval != 0) { return retval; } /* build the packet string */ if (bzrtp_packetBuild(zrtpContext, zrtpChannelContext, helloPacket, zrtpChannelContext->selfSequenceNumber) ==0) { zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID] = helloPacket; } else { bzrtp_freeZrtpPacket(helloPacket); return retval; } /* TODO: Shall add a warning trace here */ } /* it is the first call to this function, so we must also set the timer for retransmissions */ zrtpChannelContext->timer.status = BZRTP_TIMER_ON; zrtpChannelContext->timer.firingTime = 0; /* we must send a first hello message as soon as possible, to do it at first timer tick, we can't do it now because still in initialisation phase and the RTP session may not be ready to send a message */ zrtpChannelContext->timer.firingCount = 0; zrtpChannelContext->timer.timerStep = HELLO_BASE_RETRANSMISSION_STEP; zrtpChannelContext->selfSequenceNumber++; return 0; } /*** Manage message event ***/ if (event.eventType == BZRTP_EVENT_MESSAGE) { bzrtpPacket_t *zrtpPacket = event.bzrtpPacket; /* now check the type of packet received, we're expecting either Hello or HelloACK */ if ((zrtpPacket->messageType != MSGTYPE_HELLO) && (zrtpPacket->messageType != MSGTYPE_HELLOACK)) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_PARSER_ERROR_UNEXPECTEDMESSAGE; } /* parse the packet */ retval = bzrtp_packetParser(zrtpContext, zrtpChannelContext, event.bzrtpPacketString, event.bzrtpPacketStringLength, zrtpPacket); if (retval != 0) { bzrtp_freeZrtpPacket(zrtpPacket); return retval; } /* packet is valid, set the sequence Number in channel context */ zrtpChannelContext->peerSequenceNumber = zrtpPacket->sequenceNumber; /* if we have an Hello packet, we must use it to determine which algo we will agree on */ if (zrtpPacket->messageType == MSGTYPE_HELLO) { retval = bzrtp_responseToHelloMessage(zrtpContext, zrtpChannelContext, zrtpPacket); if (retval != 0) { return retval; } /* reset the sending Hello timer as peer may have started slowly and lost all our Hello packets */ zrtpChannelContext->timer.status = BZRTP_TIMER_ON; zrtpChannelContext->timer.firingTime = 0; zrtpChannelContext->timer.firingCount = 0; zrtpChannelContext->timer.timerStep = HELLO_BASE_RETRANSMISSION_STEP; /* set next state (do not call it as we will just be waiting for a HelloACK packet from peer, nothing to do) */ zrtpChannelContext->stateMachine = state_discovery_waitingForHelloAck; } /* if we have a HelloACK packet, stop the timer and set next state to state_discovery_waitingForHello */ if (zrtpPacket->messageType == MSGTYPE_HELLOACK) { /* stop the timer */ zrtpChannelContext->timer.status = BZRTP_TIMER_OFF; /* Hello ACK packet is not stored, free it */ bzrtp_freeZrtpPacket(zrtpPacket); /* set next state (do not call it as we will just be waiting for a Hello packet from peer, nothing to do) */ zrtpChannelContext->stateMachine = state_discovery_waitingForHello; return 0; } } /*** Manage timer event ***/ if (event.eventType == BZRTP_EVENT_TIMER) { /* adjust timer for next time : check we didn't reach the max retransmissions adjust the step(double it until reaching the cap) */ if (zrtpChannelContext->timer.firingCount<=HELLO_MAX_RETRANSMISSION_NUMBER) { if (2*zrtpChannelContext->timer.timerStep<=HELLO_CAP_RETRANSMISSION_STEP) { zrtpChannelContext->timer.timerStep *= 2; } zrtpChannelContext->timer.firingTime = zrtpContext->timeReference + zrtpChannelContext->timer.timerStep; } else { /* we have done enough retransmissions, stop it */ zrtpChannelContext->timer.status = BZRTP_TIMER_OFF; } /* We must resend a Hello packet */ retval = bzrtp_packetUpdateSequenceNumber(zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID], zrtpChannelContext->selfSequenceNumber); if (retval == 0) { if (zrtpContext->zrtpCallbacks.bzrtp_sendData!=NULL) { zrtpContext->zrtpCallbacks.bzrtp_sendData(zrtpChannelContext->clientData, zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID]->packetString, zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID]->messageLength+ZRTP_PACKET_OVERHEAD); zrtpChannelContext->selfSequenceNumber++; } } else { return retval; } } return 0; } /* * @brief Arrives in this state coming from init upon reception on Hello ACK, we are now waiting for the Hello packet from peer * * Arrives from : * - state_discovery_init upon HelloACK reception * Goes to: * - state_keyAgreement_sendingCommit upon Hello reception * Send : * - HelloACK on Hello reception * */ int state_discovery_waitingForHello(bzrtpEvent_t event) { /* get the contextes from the event */ bzrtpContext_t *zrtpContext = event.zrtpContext; bzrtpChannelContext_t *zrtpChannelContext = event.zrtpChannelContext; /*** Manage the first call to this function ***/ /* no init event for this state */ /*** Manage message event ***/ if (event.eventType == BZRTP_EVENT_MESSAGE) { bzrtpEvent_t initEvent; int retval; bzrtpPacket_t *zrtpPacket = event.bzrtpPacket; /* now check the type of packet received, we're expecting either Hello, HelloACK may arrive but will be discarded as useless now */ if (zrtpPacket->messageType != MSGTYPE_HELLO) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_PARSER_ERROR_UNEXPECTEDMESSAGE; } /* parse the packet */ retval = bzrtp_packetParser(zrtpContext, zrtpChannelContext, event.bzrtpPacketString, event.bzrtpPacketStringLength, zrtpPacket); if (retval != 0) { bzrtp_freeZrtpPacket(zrtpPacket); return retval; } /* packet is valid, set the sequence Number in channel context */ zrtpChannelContext->peerSequenceNumber = zrtpPacket->sequenceNumber; retval = bzrtp_responseToHelloMessage(zrtpContext, zrtpChannelContext, zrtpPacket); if (retval != 0) { return retval; } /* set next state state_keyAgreement_sendingCommit */ zrtpChannelContext->stateMachine = state_keyAgreement_sendingCommit; /* create the init event for next state */ initEvent.eventType = BZRTP_EVENT_INIT; initEvent.bzrtpPacketString = NULL; initEvent.bzrtpPacketStringLength = 0; initEvent.bzrtpPacket = NULL; initEvent.zrtpContext = zrtpContext; initEvent.zrtpChannelContext = zrtpChannelContext; /* call the next state */ return zrtpChannelContext->stateMachine(initEvent); } /*** Manage timer event ***/ /* no timer event for this state*/ return 0; } /* * @brief We are now waiting for the HelloACK packet from peer or a Commit packet * * Arrives from : * - state_discovery_init upon Hello reception * Goes to: * - state_keyAgreement_sendingCommit upon HelloACK reception * - state_keyAgreement_responderSendingDHPart1 upon Commit reception in DHM mode * - state_confirmation_responderSendingConfirm1 upon Commit reception in non DHM mode * Send : * - Hello until timer's end or transition * - HelloACK on Hello reception * */ int state_discovery_waitingForHelloAck(bzrtpEvent_t event) { /* get the contextes from the event */ bzrtpContext_t *zrtpContext = event.zrtpContext; bzrtpChannelContext_t *zrtpChannelContext = event.zrtpChannelContext; int retval; /*** Manage message event ***/ if (event.eventType == BZRTP_EVENT_MESSAGE) { bzrtpPacket_t *zrtpPacket = event.bzrtpPacket; /* we can receive either a Hello, HelloACK or Commit packets, others will be ignored */ if ((zrtpPacket->messageType != MSGTYPE_HELLO) && (zrtpPacket->messageType != MSGTYPE_HELLOACK) && (zrtpPacket->messageType != MSGTYPE_COMMIT)) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_PARSER_ERROR_UNEXPECTEDMESSAGE; } /* We do not need to parse the packet if it is an Hello one as it shall be the duplicate of one we received earlier */ /* we must check it is the same we initially received, and send a HelloACK */ if (zrtpPacket->messageType == MSGTYPE_HELLO) { bzrtpPacket_t *helloACKPacket; if (zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->messageLength != zrtpPacket->messageLength) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_ERROR_UNMATCHINGPACKETREPETITION; } if (memcmp(event.bzrtpPacketString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->messageLength) != 0) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_ERROR_UNMATCHINGPACKETREPETITION; } /* incoming packet is valid, set the sequence Number in channel context */ zrtpChannelContext->peerSequenceNumber = zrtpPacket->sequenceNumber; /* free the incoming packet */ bzrtp_freeZrtpPacket(zrtpPacket); /* build and send the HelloACK packet */ helloACKPacket = bzrtp_createZrtpPacket(zrtpContext, zrtpChannelContext, MSGTYPE_HELLOACK, &retval); if (retval != 0) { return retval; /* no need to free the Hello message as it is attached to the context, it will be freed when destroying it */ } retval = bzrtp_packetBuild(zrtpContext, zrtpChannelContext, helloACKPacket, zrtpChannelContext->selfSequenceNumber); if (retval != 0) { bzrtp_freeZrtpPacket(helloACKPacket); return retval; } else { /* send the message */ zrtpContext->zrtpCallbacks.bzrtp_sendData(zrtpChannelContext->clientData, helloACKPacket->packetString, helloACKPacket->messageLength+ZRTP_PACKET_OVERHEAD); zrtpChannelContext->selfSequenceNumber++; /* sent HelloACK is not stored, free it */ bzrtp_freeZrtpPacket(helloACKPacket); } return 0; } /* parse the packet wich is either HelloACK or Commit */ retval = bzrtp_packetParser(zrtpContext, zrtpChannelContext, event.bzrtpPacketString, event.bzrtpPacketStringLength, zrtpPacket); if (retval != 0) { bzrtp_freeZrtpPacket(zrtpPacket); return retval; } /* packet is valid, set the sequence Number in channel context */ zrtpChannelContext->peerSequenceNumber = zrtpPacket->sequenceNumber; /* if we have an HelloACK packet, transit to state_keyAgreement_sendingCommit and execute it with an init event */ if (zrtpPacket->messageType == MSGTYPE_HELLOACK) { bzrtpEvent_t initEvent; /* stop the timer */ zrtpChannelContext->timer.status = BZRTP_TIMER_OFF; /* set next state to state_keyAgreement_sendingCommit */ zrtpChannelContext->stateMachine = state_keyAgreement_sendingCommit; /* the HelloACK packet is not stored in context, free it */ bzrtp_freeZrtpPacket(zrtpPacket); /* create the init event for next state and call the next state */ initEvent.eventType = BZRTP_EVENT_INIT; initEvent.bzrtpPacketString = NULL; initEvent.bzrtpPacketStringLength = 0; initEvent.bzrtpPacket = NULL; initEvent.zrtpContext = zrtpContext; initEvent.zrtpChannelContext = zrtpChannelContext; return zrtpChannelContext->stateMachine(initEvent); } /* if we have a Commit packet we shall turn into responder role * then transit to state_keyAgreement_responderSendingDHPart1 or state_confirmation_responderSendingConfirm1 depending on which mode (Multi/PreShared or DHM) we are using and execute it with an init event */ if (zrtpPacket->messageType == MSGTYPE_COMMIT) { bzrtpCommitMessage_t *commitMessage = (bzrtpCommitMessage_t *)zrtpPacket->messageData; /* this will stop the timer, update the context channel and run the next state according to current mode */ return bzrtp_turnIntoResponder(zrtpContext, zrtpChannelContext, zrtpPacket, commitMessage); } } /*** Manage timer event ***/ if (event.eventType == BZRTP_EVENT_TIMER) { /* adjust timer for next time : check we didn't reach the max retransmissions adjust the step(double it until reaching the cap) */ if (zrtpChannelContext->timer.firingCount<=HELLO_MAX_RETRANSMISSION_NUMBER) { if (2*zrtpChannelContext->timer.timerStep<=HELLO_CAP_RETRANSMISSION_STEP) { zrtpChannelContext->timer.timerStep *= 2; } zrtpChannelContext->timer.firingTime = zrtpContext->timeReference + zrtpChannelContext->timer.timerStep; } else { /* we have done enough retransmissions, stop it */ zrtpChannelContext->timer.status = BZRTP_TIMER_OFF; } /* We must resend a Hello packet */ retval = bzrtp_packetUpdateSequenceNumber(zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID], zrtpChannelContext->selfSequenceNumber); if (retval == 0) { zrtpContext->zrtpCallbacks.bzrtp_sendData(zrtpChannelContext->clientData, zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID]->packetString, zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID]->messageLength+ZRTP_PACKET_OVERHEAD); zrtpChannelContext->selfSequenceNumber++; } else { return retval; } } return 0; } /* * @brief For any kind of key agreement (DHM, Mult, PreShared), we keep sending commit. * * Arrives from : * - state_discovery_waitingForHello upon Hello received * - state_discovery_waitingForHelloAck upon HelloACK received * Goes to: * - state_keyAgreement_initiatorSendingDHPart2 upon DHPart1 reception in DHM mode * - state_confirmation_initiatorSendingConfirm2 upon Confirm1 reception in non DHM mode * - state_keyAgreement_responderSendingDHPart1 upon Commit reception in DHM mode and commit contention gives us the responder role * - state_confirmation_responderSendingConfirm1 upon Commit reception in non DHM mode and commit contention gives us the responder role * Send : * - Commit until timer's end or transition * - HelloACK on Hello reception * */ int state_keyAgreement_sendingCommit(bzrtpEvent_t event) { /* get the contextes from the event */ bzrtpContext_t *zrtpContext = event.zrtpContext; bzrtpChannelContext_t *zrtpChannelContext = event.zrtpChannelContext; int retval; /*** Manage the first call to this function ***/ /* We are supposed to send commit packet, check if we have one in the channel Context, the event type shall be INIT in this case */ if ((event.eventType == BZRTP_EVENT_INIT) && (zrtpChannelContext->selfPackets[COMMIT_MESSAGE_STORE_ID] == NULL)) { int retval; /* create the commit packet */ bzrtpPacket_t *commitPacket = bzrtp_createZrtpPacket(zrtpContext, zrtpChannelContext, MSGTYPE_COMMIT, &retval); if (retval != 0) { return retval; } /* build the packet string */ if (bzrtp_packetBuild(zrtpContext, zrtpChannelContext, commitPacket, zrtpChannelContext->selfSequenceNumber) ==0) { zrtpChannelContext->selfPackets[COMMIT_MESSAGE_STORE_ID] = commitPacket; } else { bzrtp_freeZrtpPacket(commitPacket); return retval; } /* it is the first call to this state function, so we must also set the timer for retransmissions */ zrtpChannelContext->timer.status = BZRTP_TIMER_ON; zrtpChannelContext->timer.firingTime = zrtpContext->timeReference + NON_HELLO_BASE_RETRANSMISSION_STEP; zrtpChannelContext->timer.firingCount = 0; zrtpChannelContext->timer.timerStep = NON_HELLO_BASE_RETRANSMISSION_STEP; /* now send the first Commit message */ zrtpContext->zrtpCallbacks.bzrtp_sendData(zrtpChannelContext->clientData, zrtpChannelContext->selfPackets[COMMIT_MESSAGE_STORE_ID]->packetString, zrtpChannelContext->selfPackets[COMMIT_MESSAGE_STORE_ID]->messageLength+ZRTP_PACKET_OVERHEAD); zrtpChannelContext->selfSequenceNumber++; return 0; } /*** Manage message event ***/ if (event.eventType == BZRTP_EVENT_MESSAGE) { bzrtpEvent_t initEvent; bzrtpPacket_t *zrtpPacket = event.bzrtpPacket; /* now check the type of packet received, we're expecting a commit or a DHPart1 or a Confirm1 packet */ if ((zrtpPacket->messageType != MSGTYPE_COMMIT) && (zrtpPacket->messageType != MSGTYPE_DHPART1) && (zrtpPacket->messageType != MSGTYPE_CONFIRM1)) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_PARSER_ERROR_UNEXPECTEDMESSAGE; } /* DHPART1 can be received only if we are in DHM mode */ if ((zrtpPacket->messageType == MSGTYPE_DHPART1) && ((zrtpChannelContext->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Prsh) || (zrtpChannelContext->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Prsh))) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_PARSER_ERROR_UNEXPECTEDMESSAGE; } /* Confirm1 can be received only if we are in Mult or PreShared mode */ if ((zrtpPacket->messageType == MSGTYPE_CONFIRM1) && (zrtpChannelContext->keyAgreementAlgo != ZRTP_KEYAGREEMENT_Prsh) && (zrtpChannelContext->keyAgreementAlgo != ZRTP_KEYAGREEMENT_Mult)) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_PARSER_ERROR_UNEXPECTEDMESSAGE; } /* if we have a confirm1 and are in multi stream mode, we must first derive s0 and other keys to be able to parse the packet */ if ((zrtpPacket->messageType == MSGTYPE_CONFIRM1) && (zrtpChannelContext->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Mult)) { retval = bzrtp_computeS0MultiStreamMode(zrtpContext, zrtpChannelContext); if (retval!= 0) { return retval; } } /* parse the packet wich is either Commit a DHPart1 or a Confirm1 packet */ retval = bzrtp_packetParser(zrtpContext, zrtpChannelContext, event.bzrtpPacketString, event.bzrtpPacketStringLength, zrtpPacket); if (retval != 0) { bzrtp_freeZrtpPacket(zrtpPacket); return retval; } /* packet is valid, set the sequence Number in channel context */ zrtpChannelContext->peerSequenceNumber = zrtpPacket->sequenceNumber; /* create the init event for next state */ initEvent.eventType = BZRTP_EVENT_INIT; initEvent.bzrtpPacketString = NULL; initEvent.bzrtpPacketStringLength = 0; initEvent.bzrtpPacket = NULL; initEvent.zrtpContext = zrtpContext; initEvent.zrtpChannelContext = zrtpChannelContext; /* we have a DHPart1 - so we are initiator in DHM mode - stop timer and go to state_keyAgreement_initiatorSendingDHPart2 */ if(zrtpPacket->messageType == MSGTYPE_DHPART1) { bzrtpDHPartMessage_t * dhPart1Message; /* stop the timer */ zrtpChannelContext->timer.status = BZRTP_TIMER_OFF; dhPart1Message = (bzrtpDHPartMessage_t *)zrtpPacket->messageData; /* Check shared secret hash found in the DHPart1 message */ /* if we do not have the secret, don't check it as we do not expect the other part to have it neither */ /* check matching secret is: check if locally computed(by the initiator) rs1 matches the responder rs1 or rs2 */ /* if it doesn't check with initiator's rs2 and responder(received in DHPart1) rs1 or rs2 */ /* In case of cache mismatch, warn the user(reset the Previously Verified Sas Flag) and erase secret as it must not be used to compute s0 */ if (zrtpContext->cachedSecret.rs1!=NULL) { /* check if rs1 match peer's one */ if (memcmp(zrtpContext->responderCachedSecretHash.rs1ID, dhPart1Message->rs1ID,8) != 0) { /* they don't match but self rs1 may match peer rs2 */ if (memcmp(zrtpContext->responderCachedSecretHash.rs1ID, dhPart1Message->rs2ID,8) != 0) { /* They don't match either : erase rs1 and set the cache mismatch flag(which may be unset if self rs2 match peer rs1 or peer rs2 */ free(zrtpContext->cachedSecret.rs1); zrtpContext->cachedSecret.rs1= NULL; zrtpContext->cachedSecret.rs1Length = 0; zrtpContext->cacheMismatchFlag = 1; /* Do not trigger cache mismatch message for now as it may match rs2 */ } } } /* we didn't have a match with rs1 and have a rs2; check if it matches responder rs1 or rs2 */ if ((zrtpContext->cacheMismatchFlag == 1) && (zrtpContext->cachedSecret.rs2!=NULL)) { /* does it match rs1 */ if (memcmp(zrtpContext->responderCachedSecretHash.rs2ID, dhPart1Message->rs1ID,8) != 0) { /* it doesn't match rs1 but may match rs2 */ if (memcmp(zrtpContext->responderCachedSecretHash.rs2ID, dhPart1Message->rs2ID,8) != 0) { free(zrtpContext->cachedSecret.rs2); zrtpContext->cachedSecret.rs2= NULL; zrtpContext->cachedSecret.rs2Length = 0; } else { /* it matches rs2, reset the cache mismatch flag */ zrtpContext->cacheMismatchFlag = 0; } } else { /* it matches rs1, reset the cache mismatch flag */ zrtpContext->cacheMismatchFlag = 0; } } if (zrtpContext->cachedSecret.auxsecret!=NULL) { if (memcmp(zrtpChannelContext->responderAuxsecretID, dhPart1Message->auxsecretID,8) != 0) { free(zrtpContext->cachedSecret.auxsecret); zrtpContext->cachedSecret.auxsecret= NULL; zrtpContext->cachedSecret.auxsecretLength = 0; } } if (zrtpContext->cachedSecret.pbxsecret!=NULL) { if (memcmp(zrtpContext->responderCachedSecretHash.pbxsecretID, dhPart1Message->pbxsecretID,8) != 0) { free(zrtpContext->cachedSecret.pbxsecret); zrtpContext->cachedSecret.pbxsecret= NULL; zrtpContext->cachedSecret.pbxsecretLength = 0; } } /* in case of cache mismatch, be sure the Previously Verified Sas flag is reset in cache and in the context */ if (zrtpContext->cacheMismatchFlag == 1) { uint8_t pvsFlag = 0; char *colNames[] = {"pvs"}; uint8_t *colValues[] = {&pvsFlag}; size_t colLength[] = {1}; zrtpContext->cachedSecret.previouslyVerifiedSas = 0; bzrtp_cache_write(zrtpContext->zidCache, zrtpContext->zuid, "zrtp", colNames, colValues, colLength, 1); /* if we have a statusMessage callback, use it to warn user */ if (zrtpContext->zrtpCallbacks.bzrtp_statusMessage!=NULL && zrtpContext->zrtpCallbacks.bzrtp_messageLevel>=BZRTP_MESSAGE_ERROR) { /* use error level as this one MUST (RFC section 4.3.2) be warned */ zrtpContext->zrtpCallbacks.bzrtp_statusMessage(zrtpChannelContext->clientData, BZRTP_MESSAGE_ERROR, BZRTP_MESSAGE_CACHEMISMATCH, NULL); } } /* Check that the received PV is not 1 or Prime-1 TODO*/ /* update context with the information found in the packet */ memcpy(zrtpChannelContext->peerH[1], dhPart1Message->H1, 32); zrtpChannelContext->peerPackets[DHPART_MESSAGE_STORE_ID] = zrtpPacket; /* Compute the shared DH secret */ zrtpContext->DHMContext->peer = (uint8_t *)malloc(zrtpChannelContext->keyAgreementLength*sizeof(uint8_t)); memcpy (zrtpContext->DHMContext->peer, dhPart1Message->pv, zrtpChannelContext->keyAgreementLength); bctbx_DHMComputeSecret(zrtpContext->DHMContext, (int (*)(void *, uint8_t *, size_t))bctbx_rng_get, (void *)zrtpContext->RNGContext); /* Derive the s0 key */ bzrtp_computeS0DHMMode(zrtpContext, zrtpChannelContext); /* set next state to state_keyAgreement_initiatorSendingDHPart2 */ zrtpChannelContext->stateMachine = state_keyAgreement_initiatorSendingDHPart2; /* call it with the init event */ return zrtpChannelContext->stateMachine(initEvent); } /* we have a Confirm1 - so we are initiator and in NON-DHM mode - stop timer and go to state_confirmation_initiatorSendingConfirm2 */ if(zrtpPacket->messageType == MSGTYPE_CONFIRM1) { bzrtpConfirmMessage_t *confirm1Message; /* stop the timer */ zrtpChannelContext->timer.status = BZRTP_TIMER_OFF; /* save the message and extract some information from it to the channel context */ confirm1Message = (bzrtpConfirmMessage_t *)zrtpPacket->messageData; memcpy(zrtpChannelContext->peerH[0], confirm1Message->H0, 32); /* store the packet to check possible repetitions */ zrtpChannelContext->peerPackets[CONFIRM_MESSAGE_STORE_ID] = zrtpPacket; /* set next state to state_confirmation_responderSendingConfirm2 */ zrtpChannelContext->stateMachine = state_confirmation_initiatorSendingConfirm2; /* call it with the init event */ return zrtpChannelContext->stateMachine(initEvent); } /* we have a commit - do commit contention as in rfc section 4.2 - if we are initiator, keep sending Commits, otherwise stop the timer and go to state_keyAgreement_responderSendingDHPart1 if we are DHM mode or state_confirmation_responderSendingConfirm1 in Multi or PreShared mode */ if(zrtpPacket->messageType == MSGTYPE_COMMIT) { bzrtpCommitMessage_t *peerCommitMessage = (bzrtpCommitMessage_t *)zrtpPacket->messageData; bzrtpCommitMessage_t *selfCommitMessage = (bzrtpCommitMessage_t *)zrtpChannelContext->selfPackets[COMMIT_MESSAGE_STORE_ID]->messageData; /* - If one Commit is for a DH mode while the other is for Preshared mode, then the Preshared Commit MUST be discarded and the DH Commit proceeds * * - If the two Commits are both Preshared mode, and one party has set the MiTM (M) flag in the Hello message and the other has not, the Commit message from the party who set the (M) flag MUST be discarded, and the one who has not set the (M) flag becomes the initiator, regardless of the nonce values. In other words, for Preshared mode, the phone is the initiator and the PBX is the responder. * * - If the two Commits are either both DH modes or both non-DH modes, then the Commit message with the lowest hvi (hash value of initiator) value (for DH Commits), or lowest nonce value (for non-DH Commits), MUST be discarded and the other side is the initiator, and the protocol proceeds with the initiator's Commit. The two hvi or nonce values are compared as large unsigned integers in network byte order. */ /* we are by default initiator, so just check the statement which turns us into responder */ if (peerCommitMessage->keyAgreementAlgo != selfCommitMessage->keyAgreementAlgo ) { /* commits have differents modes */ if ((peerCommitMessage->keyAgreementAlgo != ZRTP_KEYAGREEMENT_Prsh) && (selfCommitMessage->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Prsh)) { zrtpChannelContext->role = BZRTP_ROLE_RESPONDER; } } else { /* commit have the same mode */ bzrtpHelloMessage_t *peerHelloMessage = (bzrtpHelloMessage_t *)zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->messageData; bzrtpHelloMessage_t *selfHelloMessage = (bzrtpHelloMessage_t *)zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID]->messageData; if (peerCommitMessage->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Prsh && ((selfHelloMessage->M == 1) || (peerHelloMessage->M == 1)) ) { if (selfHelloMessage->M == 1) { /* we are a PBX -> act as responder */ zrtpChannelContext->role = BZRTP_ROLE_RESPONDER; } } else { /* modes are the same and no one has the MiTM flag set : compare hvi/nonce */ if ((selfCommitMessage->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Prsh) || (selfCommitMessage->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Mult)) { /* non DHM mode, compare the nonce, lower will be responder */ if (memcmp(selfCommitMessage->nonce, peerCommitMessage->nonce, 16) < 0) { /* self nonce < peer nonce */ zrtpChannelContext->role = BZRTP_ROLE_RESPONDER; } } else { /* DHM mode, compare the hvi */ if (memcmp(selfCommitMessage->hvi, peerCommitMessage->hvi, 32) < 0) { /* self hvi < peer hvi */ zrtpChannelContext->role = BZRTP_ROLE_RESPONDER; } } } } /* so now check if we are responder - if we are initiator just do nothing, continue sending the commits and ignore the one we just receive */ if (zrtpChannelContext->role == BZRTP_ROLE_RESPONDER) { /* free the self commit packet as it is now useless */ bzrtp_freeZrtpPacket(zrtpChannelContext->selfPackets[COMMIT_MESSAGE_STORE_ID]); zrtpChannelContext->selfPackets[COMMIT_MESSAGE_STORE_ID] = NULL; /* this will update the context channel and run the next state according to current mode */ return bzrtp_turnIntoResponder(zrtpContext, zrtpChannelContext, zrtpPacket, peerCommitMessage); } else { /* we are iniator, just drop the incoming commit packet and keep send our */ bzrtp_freeZrtpPacket(zrtpPacket); } } return 0; } /*** Manage timer event ***/ if (event.eventType == BZRTP_EVENT_TIMER) { /* adjust timer for next time : check we didn't reach the max retransmissions adjust the step(double it until reaching the cap) */ if (zrtpChannelContext->timer.firingCount<=NON_HELLO_MAX_RETRANSMISSION_NUMBER) { if (2*zrtpChannelContext->timer.timerStep<=NON_HELLO_CAP_RETRANSMISSION_STEP) { zrtpChannelContext->timer.timerStep *= 2; } zrtpChannelContext->timer.firingTime = zrtpContext->timeReference + zrtpChannelContext->timer.timerStep; } else { /* we have done enough retransmissions, stop it */ zrtpChannelContext->timer.status = BZRTP_TIMER_OFF; } /* We must resend a Commit packet */ retval = bzrtp_packetUpdateSequenceNumber(zrtpChannelContext->selfPackets[COMMIT_MESSAGE_STORE_ID], zrtpChannelContext->selfSequenceNumber); if (retval == 0) { zrtpContext->zrtpCallbacks.bzrtp_sendData(zrtpChannelContext->clientData, zrtpChannelContext->selfPackets[COMMIT_MESSAGE_STORE_ID]->packetString, zrtpChannelContext->selfPackets[COMMIT_MESSAGE_STORE_ID]->messageLength+ZRTP_PACKET_OVERHEAD); zrtpChannelContext->selfSequenceNumber++; } else { return retval; } } return 0; } /* * @brief For DHM mode only, responder send DHPart1 packet * * Arrives from: * - state_discovery_waitingForHelloAck upon Commit reception in DHM mode * - state_keyAgreement_sendingCommit upon Commit reception in DHM mode and commit contention gives us the responder role * Goes to: * - state_confirmation_responderSendingConfirm1 upon DHPart2 reception * Send : * - DHPart1 on Commit reception * */ int state_keyAgreement_responderSendingDHPart1(bzrtpEvent_t event) { /* get the contextes from the event */ bzrtpContext_t *zrtpContext = event.zrtpContext; bzrtpChannelContext_t *zrtpChannelContext = event.zrtpChannelContext; int retval; /* We are supposed to send DHPart1 packet and it is already in context(built from DHPart when turning into responder) or it's an error */ if (zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID] == NULL) { return BZRTP_ERROR_INVALIDCONTEXT; } /*** Manage the first call to this function ***/ if (event.eventType == BZRTP_EVENT_INIT) { /* There is no timer in this state, make sure it is off */ zrtpChannelContext->timer.status = BZRTP_TIMER_OFF; /* now send the first DHPart1 message, note the sequence number has already been incremented when turning the DHPart2 message in DHPart1 */ zrtpContext->zrtpCallbacks.bzrtp_sendData(zrtpChannelContext->clientData, zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID]->packetString, zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID]->messageLength+ZRTP_PACKET_OVERHEAD); return 0; } /*** Manage message event ***/ if (event.eventType == BZRTP_EVENT_MESSAGE) { bzrtpPacket_t *zrtpPacket = event.bzrtpPacket; /* now check the type of packet received, we're expecting DHPart2 or a Commit packet */ if ((zrtpPacket->messageType != MSGTYPE_COMMIT) && (zrtpPacket->messageType != MSGTYPE_DHPART2)) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_PARSER_ERROR_UNEXPECTEDMESSAGE; } /* we have a Commit, check it is the same as received previously and resend the DHPart1 packet */ if(zrtpPacket->messageType == MSGTYPE_COMMIT) { if (zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID]->messageLength != zrtpPacket->messageLength) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_ERROR_UNMATCHINGPACKETREPETITION; } if (memcmp(event.bzrtpPacketString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID]->messageLength) != 0) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_ERROR_UNMATCHINGPACKETREPETITION; } /* incoming packet is valid, set the sequence Number in channel context */ zrtpChannelContext->peerSequenceNumber = zrtpPacket->sequenceNumber; /* free the incoming packet */ bzrtp_freeZrtpPacket(zrtpPacket); /* update and send the DHPart1 packet */ retval = bzrtp_packetUpdateSequenceNumber(zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID], zrtpChannelContext->selfSequenceNumber); if (retval != 0) { return retval; } zrtpContext->zrtpCallbacks.bzrtp_sendData(zrtpChannelContext->clientData, zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID]->packetString, zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID]->messageLength+ZRTP_PACKET_OVERHEAD); zrtpChannelContext->selfSequenceNumber++; return 0; } /* we have a DHPart2 go to state_confirmation_responderSendingConfirm1 */ if(zrtpPacket->messageType == MSGTYPE_DHPART2) { bzrtpDHPartMessage_t * dhPart2Message; uint8_t cacheMatchFlag = 0; bzrtpEvent_t initEvent; /* parse the packet */ retval = bzrtp_packetParser(zrtpContext, zrtpChannelContext, event.bzrtpPacketString, event.bzrtpPacketStringLength, zrtpPacket); if (retval != 0) { bzrtp_freeZrtpPacket(zrtpPacket); return retval; } dhPart2Message = (bzrtpDHPartMessage_t *)zrtpPacket->messageData; /* Check shared secret hash found in the DHPart2 message */ /* if we do not have the secret, don't check it as we do not expect the other part to have it neither */ /* shared secret matching is: check if initiator rs1(received in DHPart2) match localy computed(by responder from cache) rs1 or rs2 */ /* of not check if received rs2 match local rs1 or rs2 */ /* keep the rs1 or rs2 in cachedSecret only if it matches the received one, it will the be used to compute s0 */ /* In case of cache mismatch, warn the user(reset the previously verified Sas flag) and erase secret as it must not be used to compute s0 */ if (zrtpContext->cachedSecret.rs1!=NULL) { /* check if rs1 match peer's one */ if (memcmp(zrtpContext->initiatorCachedSecretHash.rs1ID, dhPart2Message->rs1ID,8) != 0) { /* they don't match but self rs2 may match peer rs1 */ if (zrtpContext->cachedSecret.rs2!=NULL) { if (memcmp(zrtpContext->initiatorCachedSecretHash.rs2ID, dhPart2Message->rs1ID,8) == 0) { /* responder rs2 match initiator rs1, erase responder rs1 */ cacheMatchFlag = 1; free(zrtpContext->cachedSecret.rs1); zrtpContext->cachedSecret.rs1= NULL; zrtpContext->cachedSecret.rs1Length = 0; } } } else { /* responder rs1 match initiator rs1 */ cacheMatchFlag = 1; } } /* if we didn't found a match yet(initiator rs1 doesn't match local rs1 or rs2) */ if ((zrtpContext->cachedSecret.rs1!=NULL) && (cacheMatchFlag == 0)) { /* does it match initiator rs2 */ if (memcmp(zrtpContext->initiatorCachedSecretHash.rs1ID, dhPart2Message->rs2ID,8) != 0) { /* it doesn't match rs1 (erase it) but may match rs2 */ free(zrtpContext->cachedSecret.rs1); zrtpContext->cachedSecret.rs1= NULL; zrtpContext->cachedSecret.rs1Length = 0; if (zrtpContext->cachedSecret.rs2!=NULL) { if (memcmp(zrtpContext->initiatorCachedSecretHash.rs2ID, dhPart2Message->rs2ID,8) != 0) { /* no match found erase rs2 and set the cache mismatch flag */ free(zrtpContext->cachedSecret.rs2); zrtpContext->cachedSecret.rs2= NULL; zrtpContext->cachedSecret.rs2Length = 0; zrtpContext->cacheMismatchFlag = 1; } } else { zrtpContext->cacheMismatchFlag = 1; } } } if (zrtpContext->cachedSecret.auxsecret!=NULL) { if (memcmp(zrtpChannelContext->initiatorAuxsecretID, dhPart2Message->auxsecretID,8) != 0) { free(zrtpContext->cachedSecret.auxsecret); zrtpContext->cachedSecret.auxsecret= NULL; zrtpContext->cachedSecret.auxsecretLength = 0; /*bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_ERROR_CACHEMISMATCH;*/ } } if (zrtpContext->cachedSecret.pbxsecret!=NULL) { if (memcmp(zrtpContext->initiatorCachedSecretHash.pbxsecretID, dhPart2Message->pbxsecretID,8) != 0) { free(zrtpContext->cachedSecret.pbxsecret); zrtpContext->cachedSecret.pbxsecret= NULL; zrtpContext->cachedSecret.pbxsecretLength = 0; /*bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_ERROR_CACHEMISMATCH;*/ } } /* in case of cache mismatch, be sure the Previously Verified Sas flag is reset in cache and in the context */ if (zrtpContext->cacheMismatchFlag == 1) { uint8_t pvsFlag = 0; char *colNames[] = {"pvs"}; uint8_t *colValues[] = {&pvsFlag}; size_t colLength[] = {1}; zrtpContext->cachedSecret.previouslyVerifiedSas = 0; bzrtp_cache_write(zrtpContext->zidCache, zrtpContext->zuid, "zrtp", colNames, colValues, colLength, 1); /* if we have a statusMessage callback, use it to warn user */ if (zrtpContext->zrtpCallbacks.bzrtp_statusMessage!=NULL && zrtpContext->zrtpCallbacks.bzrtp_messageLevel>=BZRTP_MESSAGE_ERROR) { /* use error level as this one MUST (RFC section 4.3.2) be warned */ zrtpContext->zrtpCallbacks.bzrtp_statusMessage(zrtpChannelContext->clientData, BZRTP_MESSAGE_ERROR, BZRTP_MESSAGE_CACHEMISMATCH, NULL); } } /* Check that the received PV is not 1 or Prime-1 : is performed by crypto lib */ /* packet is valid, set the sequence Number in channel context */ zrtpChannelContext->peerSequenceNumber = zrtpPacket->sequenceNumber; /* update context with the information found in the packet */ memcpy(zrtpChannelContext->peerH[1], dhPart2Message->H1, 32); zrtpChannelContext->peerPackets[DHPART_MESSAGE_STORE_ID] = zrtpPacket; /* Compute the shared DH secret */ zrtpContext->DHMContext->peer = (uint8_t *)malloc(zrtpChannelContext->keyAgreementLength*sizeof(uint8_t)); memcpy (zrtpContext->DHMContext->peer, dhPart2Message->pv, zrtpChannelContext->keyAgreementLength); bctbx_DHMComputeSecret(zrtpContext->DHMContext, (int (*)(void *, uint8_t *, size_t))bctbx_rng_get, (void *)zrtpContext->RNGContext); /* Derive the s0 key */ bzrtp_computeS0DHMMode(zrtpContext, zrtpChannelContext); /* create the init event for next state */ initEvent.eventType = BZRTP_EVENT_INIT; initEvent.bzrtpPacketString = NULL; initEvent.bzrtpPacketStringLength = 0; initEvent.bzrtpPacket = NULL; initEvent.zrtpContext = zrtpContext; initEvent.zrtpChannelContext = zrtpChannelContext; /* set the next state to state_confirmation_responderSendingConfirm1 */ zrtpChannelContext->stateMachine = state_confirmation_responderSendingConfirm1; /* call it with the init event */ return zrtpChannelContext->stateMachine(initEvent); } } /*** Manage timer event ***/ /* no timer for this state, initiator only retransmit packets, we just send DHPart1 when ever a commit arrives */ return 0; } /* * @brief For DHM mode only, initiator send DHPart2 packet * * Arrives from: * - state_keyAgreement_sendingCommit upon DHPart1 reception * Goes to: * - state_confirmation_initiatorSendingConfirm2 upon reception of Confirm1 * Send : * - DHPart2 until timer's end or transition * */ int state_keyAgreement_initiatorSendingDHPart2(bzrtpEvent_t event) { int retval; /* get the contextes from the event */ bzrtpContext_t *zrtpContext = event.zrtpContext; bzrtpChannelContext_t *zrtpChannelContext = event.zrtpChannelContext; /*** Manage the first call to this function ***/ /* We have to send a DHPart2 packet, it is already present in the context */ if (event.eventType == BZRTP_EVENT_INIT) { /* adjust the sequence number and sennd the packet */ retval = bzrtp_packetUpdateSequenceNumber(zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID], zrtpChannelContext->selfSequenceNumber); if (retval == 0) { zrtpContext->zrtpCallbacks.bzrtp_sendData(zrtpChannelContext->clientData, zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID]->packetString, zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID]->messageLength+ZRTP_PACKET_OVERHEAD); zrtpChannelContext->selfSequenceNumber++; } else { return retval; } /* it is the first call to this state function, so we must set the timer for retransmissions */ zrtpChannelContext->timer.status = BZRTP_TIMER_ON; zrtpChannelContext->timer.firingTime = zrtpContext->timeReference + NON_HELLO_BASE_RETRANSMISSION_STEP; zrtpChannelContext->timer.firingCount = 0; zrtpChannelContext->timer.timerStep = NON_HELLO_BASE_RETRANSMISSION_STEP; return 0; } /*** Manage message event ***/ if (event.eventType == BZRTP_EVENT_MESSAGE) { bzrtpPacket_t *zrtpPacket = event.bzrtpPacket; /* now check the type of packet received, we're expecting a confirm1 packet, DHPart1 packet may arrives, just check they are the same we previously received */ if ((zrtpPacket->messageType != MSGTYPE_DHPART1) && (zrtpPacket->messageType != MSGTYPE_CONFIRM1)) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_PARSER_ERROR_UNEXPECTEDMESSAGE; } /* we have DHPart1 packet, just check it is the same we received previously and do nothing */ if (zrtpPacket->messageType == MSGTYPE_DHPART1) { if (zrtpChannelContext->peerPackets[DHPART_MESSAGE_STORE_ID]->messageLength != zrtpPacket->messageLength) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_ERROR_UNMATCHINGPACKETREPETITION; } if (memcmp(event.bzrtpPacketString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[DHPART_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[DHPART_MESSAGE_STORE_ID]->messageLength) != 0) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_ERROR_UNMATCHINGPACKETREPETITION; } /* incoming packet is valid, set the sequence Number in channel context */ zrtpChannelContext->peerSequenceNumber = zrtpPacket->sequenceNumber; /* free the incoming packet */ bzrtp_freeZrtpPacket(zrtpPacket); return 0; } /* we have a confirm1 packet, go to state_confirmation_initiatorSendingConfirm2 state */ if (zrtpPacket->messageType == MSGTYPE_CONFIRM1) { bzrtpConfirmMessage_t *confirm1Packet; bzrtpEvent_t initEvent; /* parse the packet */ retval = bzrtp_packetParser(zrtpContext, zrtpChannelContext, event.bzrtpPacketString, event.bzrtpPacketStringLength, zrtpPacket); if (retval != 0) { bzrtp_freeZrtpPacket(zrtpPacket); return retval; } /* stop the timer */ zrtpChannelContext->timer.status = BZRTP_TIMER_OFF; /* update context with the information found in the packet */ confirm1Packet = (bzrtpConfirmMessage_t *)zrtpPacket->messageData; memcpy(zrtpChannelContext->peerH[0], confirm1Packet->H0, 32); /* on the first channel, set peerPVS in context */ if (zrtpChannelContext->keyAgreementAlgo != ZRTP_KEYAGREEMENT_Mult) { zrtpContext->peerPVS=confirm1Packet->V; } /* store the packet to check possible repetitions */ zrtpChannelContext->peerPackets[CONFIRM_MESSAGE_STORE_ID] = zrtpPacket; /* packet is valid, set the sequence Number in channel context */ zrtpChannelContext->peerSequenceNumber = zrtpPacket->sequenceNumber; /* create the init event for next state */ initEvent.eventType = BZRTP_EVENT_INIT; initEvent.bzrtpPacketString = NULL; initEvent.bzrtpPacketStringLength = 0; initEvent.bzrtpPacket = NULL; initEvent.zrtpContext = zrtpContext; initEvent.zrtpChannelContext = zrtpChannelContext; /* next state is state_confirmation_initiatorSendingConfirm2*/ zrtpChannelContext->stateMachine = state_confirmation_initiatorSendingConfirm2; /* call the next state with the init event */ return zrtpChannelContext->stateMachine(initEvent); } } /*** Manage timer event ***/ if (event.eventType == BZRTP_EVENT_TIMER) { /* adjust timer for next time : check we didn't reach the max retransmissions adjust the step(double it until reaching the cap) */ if (zrtpChannelContext->timer.firingCount<=NON_HELLO_MAX_RETRANSMISSION_NUMBER) { if (2*zrtpChannelContext->timer.timerStep<=NON_HELLO_CAP_RETRANSMISSION_STEP) { zrtpChannelContext->timer.timerStep *= 2; } zrtpChannelContext->timer.firingTime = zrtpContext->timeReference + zrtpChannelContext->timer.timerStep; } else { /* we have done enough retransmissions, stop it */ zrtpChannelContext->timer.status = BZRTP_TIMER_OFF; } /* We must resend a DHPart1 packet */ retval = bzrtp_packetUpdateSequenceNumber(zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID], zrtpChannelContext->selfSequenceNumber); if (retval == 0) { zrtpContext->zrtpCallbacks.bzrtp_sendData(zrtpChannelContext->clientData, zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID]->packetString, zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID]->messageLength+ZRTP_PACKET_OVERHEAD); zrtpChannelContext->selfSequenceNumber++; } else { return retval; } } return 0; } /* * @brief Responder send the confirm1 message * * Arrives from: * - state_keyAgreement_responderSendingDHPart1 upon DHPart2 reception * - state_keyAgreement_sendingCommit upon Commit reception in non DHM mode and commit contention gives us the responder role * - state_discovery_waitingForHelloAck upon Commit reception in non DHM mode * Goes to: * - state_secure on Confirm2 reception * Send : * - Confirm1 on Commit or DHPart2 reception * */ int state_confirmation_responderSendingConfirm1(bzrtpEvent_t event) { int retval; /* get the contextes from the event */ bzrtpContext_t *zrtpContext = event.zrtpContext; bzrtpChannelContext_t *zrtpChannelContext = event.zrtpChannelContext; /*** Manage the first call to this function ***/ if (event.eventType == BZRTP_EVENT_INIT) { bzrtpPacket_t *confirm1Packet; /* when in multistream mode, we must derive s0 and other keys from ZRTPSess */ if (zrtpChannelContext->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Mult) { /* we need ZRTPSess */ if (zrtpContext->ZRTPSess == NULL) { return BZRTP_ERROR_INVALIDCONTEXT; } retval = bzrtp_computeS0MultiStreamMode(zrtpContext, zrtpChannelContext); if (retval!= 0) { return retval; } } else if (zrtpChannelContext->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Prsh) { /* when in preShared mode: todo */ } else { /* we are in DHM mode, check that we have the keys needed to build the confirm1 packet */ /* we must build the confirm1 packet, check in the channel context if we have the needed keys */ if ((zrtpChannelContext->mackeyr == NULL) || (zrtpChannelContext->zrtpkeyr == NULL)) { return BZRTP_ERROR_INVALIDCONTEXT; } } /* There is no timer in this state, make sure it is off */ zrtpChannelContext->timer.status = BZRTP_TIMER_OFF; /* build the confirm1 packet */ confirm1Packet = bzrtp_createZrtpPacket(zrtpContext, zrtpChannelContext, MSGTYPE_CONFIRM1, &retval); if (retval!=0) { return retval; } retval = bzrtp_packetBuild(zrtpContext, zrtpChannelContext, confirm1Packet, zrtpChannelContext->selfSequenceNumber); if (retval!=0) { bzrtp_freeZrtpPacket(confirm1Packet); return retval; } zrtpChannelContext->selfSequenceNumber++; /* save it so we can send it again if needed */ zrtpChannelContext->selfPackets[CONFIRM_MESSAGE_STORE_ID] = confirm1Packet; /* now send the confirm1 message */ zrtpContext->zrtpCallbacks.bzrtp_sendData(zrtpChannelContext->clientData, zrtpChannelContext->selfPackets[CONFIRM_MESSAGE_STORE_ID]->packetString, zrtpChannelContext->selfPackets[CONFIRM_MESSAGE_STORE_ID]->messageLength+ZRTP_PACKET_OVERHEAD); return 0; } /*** Manage message event ***/ if (event.eventType == BZRTP_EVENT_MESSAGE) { bzrtpPacket_t *zrtpPacket = event.bzrtpPacket; /* we expect packets Confirm2, Commit in NON-DHM mode or DHPart2 in DHM mode */ if ((zrtpPacket->messageType != MSGTYPE_CONFIRM2) && (zrtpPacket->messageType != MSGTYPE_COMMIT) && (zrtpPacket->messageType != MSGTYPE_DHPART2)) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_PARSER_ERROR_UNEXPECTEDMESSAGE; } /* We have a commit packet, check we are in non DHM mode, that the commit is identical to the one we already had and resend the Confirm1 packet */ if (zrtpPacket->messageType == MSGTYPE_COMMIT) { /* Check we are not in DHM mode */ if ((zrtpChannelContext->keyAgreementAlgo != ZRTP_KEYAGREEMENT_Prsh) && (zrtpChannelContext->keyAgreementAlgo != ZRTP_KEYAGREEMENT_Mult)) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_PARSER_ERROR_UNEXPECTEDMESSAGE; } /* Check the commit packet is the same we already had */ if (zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID]->messageLength != zrtpPacket->messageLength) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_ERROR_UNMATCHINGPACKETREPETITION; } if (memcmp(event.bzrtpPacketString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID]->messageLength) != 0) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_ERROR_UNMATCHINGPACKETREPETITION; } /* incoming packet is valid, set the sequence Number in channel context */ zrtpChannelContext->peerSequenceNumber = zrtpPacket->sequenceNumber; /* free the incoming packet */ bzrtp_freeZrtpPacket(zrtpPacket); /* update sequence number and resend confirm1 packet */ retval = bzrtp_packetUpdateSequenceNumber(zrtpChannelContext->selfPackets[CONFIRM_MESSAGE_STORE_ID], zrtpChannelContext->selfSequenceNumber); if (retval!=0) { return retval; } zrtpChannelContext->selfSequenceNumber++; return zrtpContext->zrtpCallbacks.bzrtp_sendData(zrtpChannelContext->clientData, zrtpChannelContext->selfPackets[CONFIRM_MESSAGE_STORE_ID]->packetString, zrtpChannelContext->selfPackets[CONFIRM_MESSAGE_STORE_ID]->messageLength+ZRTP_PACKET_OVERHEAD); } /* We have a DHPart2 packet, check we are in DHM mode, that the DHPart2 is identical to the one we already had and resend the Confirm1 packet */ if (zrtpPacket->messageType == MSGTYPE_DHPART2) { /* Check we are not DHM mode */ if ((zrtpChannelContext->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Prsh) || (zrtpChannelContext->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Mult)) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_PARSER_ERROR_UNEXPECTEDMESSAGE; } /* Check the DHPart2 packet is the same we already had */ if (zrtpChannelContext->peerPackets[DHPART_MESSAGE_STORE_ID]->messageLength != zrtpPacket->messageLength) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_ERROR_UNMATCHINGPACKETREPETITION; } if (memcmp(event.bzrtpPacketString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[DHPART_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[DHPART_MESSAGE_STORE_ID]->messageLength) != 0) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_ERROR_UNMATCHINGPACKETREPETITION; } /* incoming packet is valid, set the sequence Number in channel context */ zrtpChannelContext->peerSequenceNumber = zrtpPacket->sequenceNumber; /* free the incoming packet */ bzrtp_freeZrtpPacket(zrtpPacket); /* update sequence number and resend confirm1 packet */ retval = bzrtp_packetUpdateSequenceNumber(zrtpChannelContext->selfPackets[CONFIRM_MESSAGE_STORE_ID], zrtpChannelContext->selfSequenceNumber); if (retval!=0) { return retval; } zrtpChannelContext->selfSequenceNumber++; return zrtpContext->zrtpCallbacks.bzrtp_sendData(zrtpChannelContext->clientData, zrtpChannelContext->selfPackets[CONFIRM_MESSAGE_STORE_ID]->packetString, zrtpChannelContext->selfPackets[CONFIRM_MESSAGE_STORE_ID]->messageLength+ZRTP_PACKET_OVERHEAD); } /* We have a Confirm2 packet, check it, send a conf2ACK and go to secure state */ if (zrtpPacket->messageType == MSGTYPE_CONFIRM2) { bzrtpConfirmMessage_t *confirm2Packet; bzrtpPacket_t *conf2ACKPacket; bzrtpEvent_t initEvent; /* parse the packet */ retval = bzrtp_packetParser(zrtpContext, zrtpChannelContext, event.bzrtpPacketString, event.bzrtpPacketStringLength, zrtpPacket); if (retval != 0) { bzrtp_freeZrtpPacket(zrtpPacket); return retval; } /* update context with the information found in the packet */ confirm2Packet = (bzrtpConfirmMessage_t *)zrtpPacket->messageData; memcpy(zrtpChannelContext->peerH[0], confirm2Packet->H0, 32); /* on the first channel, set peerPVS in context */ if (zrtpChannelContext->keyAgreementAlgo != ZRTP_KEYAGREEMENT_Mult) { zrtpContext->peerPVS = confirm2Packet->V; } /* store the packet to check possible repetitions : note the storage points to confirm1, delete it as we don't need it anymore */ bzrtp_freeZrtpPacket(zrtpChannelContext->peerPackets[CONFIRM_MESSAGE_STORE_ID]); zrtpChannelContext->peerPackets[CONFIRM_MESSAGE_STORE_ID] = zrtpPacket; /* packet is valid, set the sequence Number in channel context */ zrtpChannelContext->peerSequenceNumber = zrtpPacket->sequenceNumber; /* compute SAS and srtp secrets */ retval = bzrtp_deriveSrtpKeysFromS0(zrtpContext, zrtpChannelContext); if (retval!=0) { return retval; } /* compute and update in cache the retained shared secret */ bzrtp_updateCachedSecrets(zrtpContext, zrtpChannelContext); /* send them to the environment for receiver as we may receive a srtp packet in response to our conf2ACK */ if (zrtpContext->zrtpCallbacks.bzrtp_srtpSecretsAvailable != NULL) { zrtpContext->zrtpCallbacks.bzrtp_srtpSecretsAvailable(zrtpChannelContext->clientData, &zrtpChannelContext->srtpSecrets, ZRTP_SRTP_SECRETS_FOR_RECEIVER); } /* create and send a conf2ACK packet */ conf2ACKPacket = bzrtp_createZrtpPacket(zrtpContext, zrtpChannelContext, MSGTYPE_CONF2ACK, &retval); if (retval!=0) { return retval; } retval = bzrtp_packetBuild(zrtpContext, zrtpChannelContext, conf2ACKPacket, zrtpChannelContext->selfSequenceNumber); if (retval!=0) { bzrtp_freeZrtpPacket(conf2ACKPacket); return retval; } zrtpChannelContext->selfSequenceNumber++; retval = zrtpContext->zrtpCallbacks.bzrtp_sendData(zrtpChannelContext->clientData, conf2ACKPacket->packetString, conf2ACKPacket->messageLength+ZRTP_PACKET_OVERHEAD); bzrtp_freeZrtpPacket(conf2ACKPacket); if (retval!=0) { return retval; } /* send SRTP secrets for sender as we can start sending srtp packets just after sending the conf2ACK */ if (zrtpContext->zrtpCallbacks.bzrtp_srtpSecretsAvailable != NULL) { zrtpContext->zrtpCallbacks.bzrtp_srtpSecretsAvailable(zrtpChannelContext->clientData, &zrtpChannelContext->srtpSecrets, ZRTP_SRTP_SECRETS_FOR_SENDER); } /* create the init event for next state */ initEvent.eventType = BZRTP_EVENT_INIT; initEvent.bzrtpPacketString = NULL; initEvent.bzrtpPacketStringLength = 0; initEvent.bzrtpPacket = NULL; initEvent.zrtpContext = zrtpContext; initEvent.zrtpChannelContext = zrtpChannelContext; /* next state is state_secure */ zrtpChannelContext->stateMachine = state_secure; /* call the next state with the init event */ return zrtpChannelContext->stateMachine(initEvent); } } /*** Manage timer event ***/ /* no timer for this state, initiator only retransmit packets, we just send confirm11 when ever a DHPart2 or commit arrives */ return 0; } /* * @brief Initiator send the confirm2 message * * Arrives from: * - state_keyAgreement_initiatorSendingDHPart2 upon confirm1 reception * - state_keyAgreement_sendingCommit upon Confirm1 reception in non DHM mode * Goes to: * - state_secure on Conf2ACK reception or first SRTP message * Send : * - Confirm2 until timer's end or transition * */ int state_confirmation_initiatorSendingConfirm2(bzrtpEvent_t event) { int retval; /* get the contextes from the event */ bzrtpContext_t *zrtpContext = event.zrtpContext; bzrtpChannelContext_t *zrtpChannelContext = event.zrtpChannelContext; /*** Manage the first call to this function ***/ if (event.eventType == BZRTP_EVENT_INIT) { bzrtpPacket_t *confirm2Packet; /* we must build the confirm2 packet, check in the channel context if we have the needed keys */ if ((zrtpChannelContext->mackeyi == NULL) || (zrtpChannelContext->zrtpkeyi == NULL)) { return BZRTP_ERROR_INVALIDCONTEXT; } /* build the confirm2 packet */ confirm2Packet = bzrtp_createZrtpPacket(zrtpContext, zrtpChannelContext, MSGTYPE_CONFIRM2, &retval); if (retval!=0) { return retval; } retval = bzrtp_packetBuild(zrtpContext, zrtpChannelContext, confirm2Packet, zrtpChannelContext->selfSequenceNumber); if (retval!=0) { bzrtp_freeZrtpPacket(confirm2Packet); return retval; } /* save it so we can send it again if needed */ zrtpChannelContext->selfPackets[CONFIRM_MESSAGE_STORE_ID] = confirm2Packet; /* compute SAS and SRTP secrets as responder may directly send SRTP packets and non conf2ACK */ retval = bzrtp_deriveSrtpKeysFromS0(zrtpContext, zrtpChannelContext); if (retval!=0) { return retval; } /* send them to the environment, but specify they are for receiver only as we must wait for the conf2ACK or the first valid srtp packet from peer * to start sending srtp packets */ if (zrtpContext->zrtpCallbacks.bzrtp_srtpSecretsAvailable != NULL) { zrtpContext->zrtpCallbacks.bzrtp_srtpSecretsAvailable(zrtpChannelContext->clientData, &zrtpChannelContext->srtpSecrets, ZRTP_SRTP_SECRETS_FOR_RECEIVER); } /* now send the confirm2 message */ retval = zrtpContext->zrtpCallbacks.bzrtp_sendData(zrtpChannelContext->clientData, zrtpChannelContext->selfPackets[CONFIRM_MESSAGE_STORE_ID]->packetString, zrtpChannelContext->selfPackets[CONFIRM_MESSAGE_STORE_ID]->messageLength+ZRTP_PACKET_OVERHEAD); if (retval != 0) { return retval; } zrtpChannelContext->selfSequenceNumber++; /* it is the first call to this state function, so we must set the timer for retransmissions */ zrtpChannelContext->timer.status = BZRTP_TIMER_ON; zrtpChannelContext->timer.firingTime = zrtpContext->timeReference + NON_HELLO_BASE_RETRANSMISSION_STEP; zrtpChannelContext->timer.firingCount = 0; zrtpChannelContext->timer.timerStep = NON_HELLO_BASE_RETRANSMISSION_STEP; } /*** Manage message event ***/ if (event.eventType == BZRTP_EVENT_MESSAGE) { bzrtpPacket_t *zrtpPacket = event.bzrtpPacket; /* we expect packets Conf2ACK, or a Confirm1 */ if ((zrtpPacket->messageType != MSGTYPE_CONFIRM1) && (zrtpPacket->messageType != MSGTYPE_CONF2ACK)) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_PARSER_ERROR_UNEXPECTEDMESSAGE; } /* we have confirm1 packet, just check it is the same we received previously and do nothing */ if (zrtpPacket->messageType == MSGTYPE_CONFIRM1) { if (zrtpChannelContext->peerPackets[CONFIRM_MESSAGE_STORE_ID]->messageLength != zrtpPacket->messageLength) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_ERROR_UNMATCHINGPACKETREPETITION; } if (memcmp(event.bzrtpPacketString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[CONFIRM_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[CONFIRM_MESSAGE_STORE_ID]->messageLength) != 0) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_ERROR_UNMATCHINGPACKETREPETITION; } /* incoming packet is valid, set the sequence Number in channel context */ zrtpChannelContext->peerSequenceNumber = zrtpPacket->sequenceNumber; /* free the incoming packet */ bzrtp_freeZrtpPacket(zrtpPacket); return 0; } /* we have a conf2ACK packet, parse it to validate it, stop the timer and go to secure state */ if (zrtpPacket->messageType == MSGTYPE_CONF2ACK) { bzrtpEvent_t initEvent; /* parse the packet */ retval = bzrtp_packetParser(zrtpContext, zrtpChannelContext, event.bzrtpPacketString, event.bzrtpPacketStringLength, zrtpPacket); if (retval != 0) { bzrtp_freeZrtpPacket(zrtpPacket); return retval; } /* free the incoming packet */ bzrtp_freeZrtpPacket(zrtpPacket); /* stop the retransmission timer */ zrtpChannelContext->timer.status = BZRTP_TIMER_OFF; /* compute and update in cache the retained shared secret */ bzrtp_updateCachedSecrets(zrtpContext, zrtpChannelContext); /* send the sender srtp keys to the client(we sent receiver only when the first confirm1 packet arrived) */ if (zrtpContext->zrtpCallbacks.bzrtp_srtpSecretsAvailable != NULL) { zrtpContext->zrtpCallbacks.bzrtp_srtpSecretsAvailable(zrtpChannelContext->clientData, &zrtpChannelContext->srtpSecrets, ZRTP_SRTP_SECRETS_FOR_SENDER); } /* create the init event for next state */ initEvent.eventType = BZRTP_EVENT_INIT; initEvent.bzrtpPacketString = NULL; initEvent.bzrtpPacketStringLength = 0; initEvent.bzrtpPacket = NULL; initEvent.zrtpContext = zrtpContext; initEvent.zrtpChannelContext = zrtpChannelContext; /* next state is state_secure */ zrtpChannelContext->stateMachine = state_secure; /* call the next state with the init event */ return zrtpChannelContext->stateMachine(initEvent); } } /*** Manage timer event ***/ if (event.eventType == BZRTP_EVENT_TIMER) { /* adjust timer for next time : check we didn't reach the max retransmissions adjust the step(double it until reaching the cap) */ if (zrtpChannelContext->timer.firingCount<=NON_HELLO_MAX_RETRANSMISSION_NUMBER) { if (2*zrtpChannelContext->timer.timerStep<=NON_HELLO_CAP_RETRANSMISSION_STEP) { zrtpChannelContext->timer.timerStep *= 2; } zrtpChannelContext->timer.firingTime = zrtpContext->timeReference + zrtpChannelContext->timer.timerStep; } else { /* we have done enough retransmissions, stop it */ zrtpChannelContext->timer.status = BZRTP_TIMER_OFF; } /* We must resend a Confirm2 packet */ retval = bzrtp_packetUpdateSequenceNumber(zrtpChannelContext->selfPackets[CONFIRM_MESSAGE_STORE_ID], zrtpChannelContext->selfSequenceNumber); if (retval == 0) { zrtpContext->zrtpCallbacks.bzrtp_sendData(zrtpChannelContext->clientData, zrtpChannelContext->selfPackets[CONFIRM_MESSAGE_STORE_ID]->packetString, zrtpChannelContext->selfPackets[CONFIRM_MESSAGE_STORE_ID]->messageLength+ZRTP_PACKET_OVERHEAD); zrtpChannelContext->selfSequenceNumber++; } else { return retval; } } return 0; } /* * @brief We are in secure state * * Arrives from: * - state_confirmation_responderSendingConfirm1 on Confirm2 reception * - state_confirmation_initiatorSendingConfirm2 on conf2ACK or first SRTP message * Goes to: * - This is the end(we do not support GoClear message), state machine may be destroyed after going to secure mode * Send : * - Conf2ACK on Confirm2 reception * */ int state_secure(bzrtpEvent_t event) { /* get the contextes from the event */ bzrtpContext_t *zrtpContext = event.zrtpContext; bzrtpChannelContext_t *zrtpChannelContext = event.zrtpChannelContext; /*** Manage the first call to this function ***/ if (event.eventType == BZRTP_EVENT_INIT) { /* there is no timer in this state, turn it off */ zrtpChannelContext->timer.status = BZRTP_TIMER_OFF; /* if we are not in Multistream mode, turn the global context isSecure flag to 1 */ if (zrtpChannelContext->keyAgreementAlgo != ZRTP_KEYAGREEMENT_Mult) { zrtpContext->isSecure = 1; } /* turn channel isSecure flag to 1 */ zrtpChannelContext->isSecure = 1; /* call the environment to signal we're ready to operate */ if (zrtpContext->zrtpCallbacks.bzrtp_startSrtpSession!= NULL) { zrtpContext->zrtpCallbacks.bzrtp_startSrtpSession(zrtpChannelContext->clientData, &(zrtpChannelContext->srtpSecrets), zrtpContext->cachedSecret.previouslyVerifiedSas && zrtpContext->peerPVS); } return 0; } /*** Manage message event ***/ if (event.eventType == BZRTP_EVENT_MESSAGE) { int retval; bzrtpPacket_t *conf2ACKPacket; bzrtpPacket_t *zrtpPacket = event.bzrtpPacket; /* we expect confirm2 packet */ if (zrtpPacket->messageType != MSGTYPE_CONFIRM2) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_PARSER_ERROR_UNEXPECTEDMESSAGE; } /* We have a confirm2 packet, check it is identical to the one we already had and resend the Conf2ACK packet */ /* Check the commit packet is the same we already had */ if (zrtpChannelContext->peerPackets[CONFIRM_MESSAGE_STORE_ID]->messageLength != zrtpPacket->messageLength) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_ERROR_UNMATCHINGPACKETREPETITION; } if (memcmp(event.bzrtpPacketString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[CONFIRM_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[CONFIRM_MESSAGE_STORE_ID]->messageLength) != 0) { bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_ERROR_UNMATCHINGPACKETREPETITION; } /* incoming packet is valid, set the sequence Number in channel context */ zrtpChannelContext->peerSequenceNumber = zrtpPacket->sequenceNumber; /* free the incoming packet */ bzrtp_freeZrtpPacket(zrtpPacket); /* create and send a conf2ACK packet */ conf2ACKPacket = bzrtp_createZrtpPacket(zrtpContext, zrtpChannelContext, MSGTYPE_CONF2ACK, &retval); if (retval!=0) { return retval; } retval = bzrtp_packetBuild(zrtpContext, zrtpChannelContext, conf2ACKPacket, zrtpChannelContext->selfSequenceNumber); if (retval!=0) { bzrtp_freeZrtpPacket(conf2ACKPacket); return retval; } zrtpChannelContext->selfSequenceNumber++; retval = zrtpContext->zrtpCallbacks.bzrtp_sendData(zrtpChannelContext->clientData, conf2ACKPacket->packetString, conf2ACKPacket->messageLength+ZRTP_PACKET_OVERHEAD); /* free the conf2ACK packet */ bzrtp_freeZrtpPacket(conf2ACKPacket); return retval; } /*** Manage timer event ***/ /* no timer in this state */ return 0; } /** * @brief Turn the current Channel into responder role * This happens when receiving a commit message when in state state_discovery_waitingForHelloAck or state_keyAgreement_sendingCommit if commit contention gives us the responder role. * State will be changed to state_confirmation_responderSendingConfirm1 or state_confirmation_responderSendingDHPart1 depending on DHM or non-DHM operation mode * * @param[in] zrtpContext The current zrtp Context * @param[in/out] zrtpChannelContext The channel we are operating * @param[in] zrtpPacket The zrtpPacket receives, it contains the commit message * @param[in] commitMessage A direct pointer to the commitMessage structure contained in the zrtp packet * * @return 0 on succes, error code otherwise */ int bzrtp_turnIntoResponder(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext, bzrtpPacket_t *zrtpPacket, bzrtpCommitMessage_t *commitMessage) { bzrtpEvent_t initEvent; /* kill the ongoing timer */ zrtpChannelContext->timer.status = BZRTP_TIMER_OFF; /* store the commit packet in the channel context as it is needed later to check MAC */ zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID] = zrtpPacket; /* save the peer H2 */ memcpy(zrtpChannelContext->peerH[2], commitMessage->H2, 32); /* H2 */ /* we are receiver, set it in the context and update our selected algos */ zrtpChannelContext->role = BZRTP_ROLE_RESPONDER; zrtpChannelContext->hashAlgo = commitMessage->hashAlgo; zrtpChannelContext->cipherAlgo = commitMessage->cipherAlgo; zrtpChannelContext->authTagAlgo = commitMessage->authTagAlgo; zrtpChannelContext->keyAgreementAlgo = commitMessage->keyAgreementAlgo; zrtpChannelContext->sasAlgo = commitMessage->sasAlgo; bzrtp_updateCryptoFunctionPointers(zrtpChannelContext); /* if we have a self DHPart packet (means we are in DHM mode) we must rebuild the self DHPart packet to be responder and not initiator */ /* as responder we must swap the aux shared secret between responder and initiator as they are computed using the H3 and not a constant string */ if (zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID] != NULL) { uint8_t tmpBuffer[8]; bzrtpDHPartMessage_t *selfDHPart1Packet; int retval; memcpy(tmpBuffer, zrtpChannelContext->initiatorAuxsecretID, 8); memcpy(zrtpChannelContext->initiatorAuxsecretID, zrtpChannelContext->responderAuxsecretID, 8); memcpy(zrtpChannelContext->responderAuxsecretID, tmpBuffer, 8); /* responder self DHPart packet is DHPart1, change the type (we created a DHPart2) */ zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID]->messageType = MSGTYPE_DHPART1; /* change the shared secret ID to the responder one (we set them by default to the initiator's one) */ selfDHPart1Packet = (bzrtpDHPartMessage_t *)zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID]->messageData; memcpy(selfDHPart1Packet->rs1ID, zrtpContext->responderCachedSecretHash.rs1ID, 8); memcpy(selfDHPart1Packet->rs2ID, zrtpContext->responderCachedSecretHash.rs2ID, 8); memcpy(selfDHPart1Packet->auxsecretID, zrtpChannelContext->responderAuxsecretID, 8); memcpy(selfDHPart1Packet->pbxsecretID, zrtpContext->responderCachedSecretHash.pbxsecretID, 8); /* free the packet string and rebuild the packet */ free(zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID]->packetString); zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID]->packetString = NULL; retval = bzrtp_packetBuild(zrtpContext, zrtpChannelContext, zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID], zrtpChannelContext->selfSequenceNumber); if (retval == 0) { zrtpChannelContext->selfSequenceNumber++; } else { return retval; } } /* create the init event for next state */ initEvent.eventType = BZRTP_EVENT_INIT; initEvent.bzrtpPacketString = NULL; initEvent.bzrtpPacketStringLength = 0; initEvent.bzrtpPacket = NULL; initEvent.zrtpContext = zrtpContext; initEvent.zrtpChannelContext = zrtpChannelContext; /* if we are in PreShared or Multi mode, go to state_confirmation_responderSendingConfirm1 */ if ((zrtpChannelContext->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Prsh) || (zrtpChannelContext->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Mult)) { /* set next state to state_confirmation_responderSendingConfirm1 */ zrtpChannelContext->stateMachine = state_confirmation_responderSendingConfirm1; /* call it with the init event */ return zrtpChannelContext->stateMachine(initEvent); } else {/* if we are in DHM mode, goes to state_keyAgreement_responderSendingDHPart1 */ /* set next state to state_keyAgreement_responderSendingDHPart1 */ zrtpChannelContext->stateMachine = state_keyAgreement_responderSendingDHPart1; /* call it with the init event */ return zrtpChannelContext->stateMachine(initEvent); } } /** * @brief When a Hello message arrive from peer for the first time, we shall parse it to check if it match our configuration and act on the context * This message may arrives when in state state_discovery_init or state_discovery_waitingForHello. * - Find agreement on algo to use * - Check if we have retained secrets in cache matching the peer ZID * - if agreed on a DHM mode : compute the public value and prepare a DHPart2 packet(assume we are initiator, change later if needed) * - if agreed on a non-DHM mode : compute s0 and derive keys from it TODO * * @param[in] zrtpContext The current zrtp Context * @param[in/out] zrtpChannelContext The channel we are operating * @param[in] zrtpPacket The zrtpPacket received, it contains the hello message * * @return 0 on succes, error code otherwise */ int bzrtp_responseToHelloMessage(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext, bzrtpPacket_t *zrtpPacket) { int retval; int i; uint8_t peerSupportMultiChannel = 0; bzrtpPacket_t *helloACKPacket; bzrtpHelloMessage_t *helloMessage = (bzrtpHelloMessage_t *)zrtpPacket->messageData; /* check supported version of ZRTP protocol */ if (memcmp(helloMessage->version, ZRTP_VERSION, 3) != 0) { /* we support version 1.10 only but checking is done on 1.1? as explained in rfc section 4.1.1 */ bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_ERROR_UNSUPPORTEDZRTPVERSION; /* packet shall be ignored*/ } /* now check we have some algo in common. zrtpChannelContext will be updated with common algos if found */ retval = bzrtp_cryptoAlgoAgreement(zrtpContext, zrtpChannelContext, helloMessage); if(retval != 0) { bzrtp_freeZrtpPacket(zrtpPacket); return retval; } /* check if the peer accept MultiChannel */ for (i=0; ikc; i++) { if (helloMessage->supportedKeyAgreement[i] == ZRTP_KEYAGREEMENT_Mult) { peerSupportMultiChannel = 1; } } zrtpContext->peerSupportMultiChannel = peerSupportMultiChannel; /* copy into the channel context the relevant informations */ memcpy(zrtpContext->peerZID, helloMessage->ZID, 12); /* peer ZID */ memcpy(zrtpChannelContext->peerH[3], helloMessage->H3, 32); /* H3 */ zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID] = zrtpPacket; /* peer hello packet */ /* Extract from peerHello packet the version of bzrtp used by peer and store it in global context(needed later when exporting keys) * Bzrtp version started to be publicised in version 1.1, before that the client identifier was simply BZRTP and earlier version also have LINPHONE-ZRTPCPP * We must know this version in order to keep export key computation compatible between version as before v1.1 it was badly implemented * So basically check : * if the client identifier is BZRTP or LINPHONE-ZRTPCPP -> version 1.0 (use the old and incorrect way of creating an export key) * if BZRTPv1.1 -> version 1.1 (use RFC compliant way of creating the export key ) * if anything else peer use another library, set version to 0.0 and use RFC compliant way of creating the export key as peer library is expected to be RFC compliant */ /* This is BZRTP in its old version */ if ((strncmp(ZRTP_CLIENT_IDENTIFIERv1_0a, (char *)helloMessage->clientIdentifier, 16)==0) || (strncmp(ZRTP_CLIENT_IDENTIFIERv1_0b, (char *)helloMessage->clientIdentifier, 16)==0)){ zrtpContext->peerBzrtpVersion=10000; if (zrtpContext->zrtpCallbacks.bzrtp_statusMessage!=NULL && zrtpContext->zrtpCallbacks.bzrtp_messageLevel>=BZRTP_MESSAGE_WARNING) { /* use warning level as the client may really wants to know this */ zrtpContext->zrtpCallbacks.bzrtp_statusMessage(zrtpChannelContext->clientData, BZRTP_MESSAGE_WARNING, BZRTP_MESSAGE_PEERVERSIONOBSOLETE, (const char *)helloMessage->clientIdentifier); } } else if (strncmp(ZRTP_CLIENT_IDENTIFIERv1_1, (char *)helloMessage->clientIdentifier, 16)==0) { /* peer has the current version, everything is Ok */ zrtpContext->peerBzrtpVersion=10100; } else { /* peer uses another lib, we're probably not LIME compliant, log it */ zrtpContext->peerBzrtpVersion=0; if (zrtpContext->zrtpCallbacks.bzrtp_statusMessage!=NULL && zrtpContext->zrtpCallbacks.bzrtp_messageLevel>=BZRTP_MESSAGE_LOG) { zrtpContext->zrtpCallbacks.bzrtp_statusMessage(zrtpChannelContext->clientData, BZRTP_MESSAGE_LOG, BZRTP_MESSAGE_PEERNOTBZRTP, (const char *)helloMessage->clientIdentifier); } } /* now select mode according to context */ if ((zrtpContext->peerSupportMultiChannel) == 1 && (zrtpContext->ZRTPSess != NULL)) { /* if we support multichannel and already have a ZRTPSess key, switch to multichannel mode */ zrtpChannelContext->keyAgreementAlgo = ZRTP_KEYAGREEMENT_Mult; zrtpChannelContext->keyAgreementLength = 0; } else { /* we are not in multiStream mode, so we shall compute the hash of shared secrets */ /* get from cache, if relevant, the retained secrets associated to the peer ZID */ if (zrtpContext->cachedSecret.rs1 == NULL) { /* if we do not have already secret hashes in this session context. Note, they may be updated in cache file but they also will be in the context at the same time, so no need to parse the cache again */ bzrtp_getPeerAssociatedSecrets(zrtpContext, helloMessage->ZID); } /* now compute the retained secret hashes (secrets may be updated but not their hash) as in rfc section 4.3.1 */ if (zrtpContext->cachedSecret.rs1!=NULL) { zrtpChannelContext->hmacFunction(zrtpContext->cachedSecret.rs1, zrtpContext->cachedSecret.rs1Length, (uint8_t *)"Initiator", 9, 8, zrtpContext->initiatorCachedSecretHash.rs1ID); zrtpChannelContext->hmacFunction(zrtpContext->cachedSecret.rs1, zrtpContext->cachedSecret.rs1Length, (uint8_t *)"Responder", 9, 8, zrtpContext->responderCachedSecretHash.rs1ID); } else { /* we have no secret, generate a random */ bctbx_rng_get(zrtpContext->RNGContext, zrtpContext->initiatorCachedSecretHash.rs1ID, 8); bctbx_rng_get(zrtpContext->RNGContext, zrtpContext->responderCachedSecretHash.rs1ID, 8); } if (zrtpContext->cachedSecret.rs2!=NULL) { zrtpChannelContext->hmacFunction(zrtpContext->cachedSecret.rs2, zrtpContext->cachedSecret.rs2Length, (uint8_t *)"Initiator", 9, 8, zrtpContext->initiatorCachedSecretHash.rs2ID); zrtpChannelContext->hmacFunction(zrtpContext->cachedSecret.rs2, zrtpContext->cachedSecret.rs2Length, (uint8_t *)"Responder", 9, 8, zrtpContext->responderCachedSecretHash.rs2ID); } else { /* we have no secret, generate a random */ bctbx_rng_get(zrtpContext->RNGContext, zrtpContext->initiatorCachedSecretHash.rs2ID, 8); bctbx_rng_get(zrtpContext->RNGContext, zrtpContext->responderCachedSecretHash.rs2ID, 8); } if (zrtpContext->cachedSecret.pbxsecret!=NULL) { zrtpChannelContext->hmacFunction(zrtpContext->cachedSecret.pbxsecret, zrtpContext->cachedSecret.pbxsecretLength, (uint8_t *)"Initiator", 9, 8, zrtpContext->initiatorCachedSecretHash.pbxsecretID); zrtpChannelContext->hmacFunction(zrtpContext->cachedSecret.pbxsecret, zrtpContext->cachedSecret.pbxsecretLength, (uint8_t *)"Responder", 9, 8, zrtpContext->responderCachedSecretHash.pbxsecretID); } else { /* we have no secret, generate a random */ bctbx_rng_get(zrtpContext->RNGContext, zrtpContext->initiatorCachedSecretHash.pbxsecretID, 8); bctbx_rng_get(zrtpContext->RNGContext, zrtpContext->responderCachedSecretHash.pbxsecretID, 8); } if (zrtpContext->cachedSecret.auxsecret!=NULL) { zrtpChannelContext->hmacFunction(zrtpContext->cachedSecret.auxsecret, zrtpContext->cachedSecret.auxsecretLength, zrtpChannelContext->selfH[3], 32, 8, zrtpChannelContext->initiatorAuxsecretID); zrtpChannelContext->hmacFunction(zrtpContext->cachedSecret.auxsecret, zrtpContext->cachedSecret.auxsecretLength, zrtpChannelContext->peerH[3], 32, 8, zrtpChannelContext->responderAuxsecretID); } else { /* we have no secret, generate a random */ bctbx_rng_get(zrtpContext->RNGContext, zrtpChannelContext->initiatorAuxsecretID, 8); bctbx_rng_get(zrtpContext->RNGContext, zrtpChannelContext->responderAuxsecretID, 8); } } /* When in PreShared mode Derive ZRTPSess, s0 from the retained secret and then all the other keys */ if (zrtpChannelContext->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Prsh) { /*TODO*/ } else if (zrtpChannelContext->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Mult) { /* when in Multistream mode, do nothing, will derive s0 from ZRTPSess when we know who is initiator */ } else { /* when in DHM mode : Create the DHPart2 packet (that we then may change to DHPart1 if we ended to be the responder)*/ bzrtpPacket_t *selfDHPartPacket = bzrtp_createZrtpPacket(zrtpContext, zrtpChannelContext, MSGTYPE_DHPART2, &retval); if (retval != 0) { return retval; /* no need to free the Hello message as it is attached to the context, it will be freed when destroying it */ } retval = bzrtp_packetBuild(zrtpContext, zrtpChannelContext, selfDHPartPacket, 0); /* we don't care now about sequence number as we just need to build the message to be able to insert a hash of it into the commit packet */ if (retval == 0) { /* ok, insert it in context as we need it to build the commit packet */ zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID] = selfDHPartPacket; } else { return retval; /* no need to free the Hello message as it is attached to the context, it will be freed when destroying it */ } } /* now respond to this Hello packet sending a Hello ACK */ helloACKPacket = bzrtp_createZrtpPacket(zrtpContext, zrtpChannelContext, MSGTYPE_HELLOACK, &retval); if (retval != 0) { return retval; /* no need to free the Hello message as it is attached to the context, it will be freed when destroying it */ } retval = bzrtp_packetBuild(zrtpContext, zrtpChannelContext, helloACKPacket, zrtpChannelContext->selfSequenceNumber); if (retval != 0) { bzrtp_freeZrtpPacket(helloACKPacket); return retval; } else { /* send the message */ zrtpContext->zrtpCallbacks.bzrtp_sendData(zrtpChannelContext->clientData, helloACKPacket->packetString, helloACKPacket->messageLength+ZRTP_PACKET_OVERHEAD); zrtpChannelContext->selfSequenceNumber++; bzrtp_freeZrtpPacket(helloACKPacket); } return 0; } /** * @brief After the DHPart1 or DHPart2 arrives from peer, validity check and shared secret computation * call this function to compute s0, KDF Context, ZRTPSess, * * param[in] zrtpContext The context we are operation on(where to find the DHM context with the shared secret ready) * param[in] zrtpChannelContext The channel context we are operation on * * return 0 on success, error code otherwise */ int bzrtp_computeS0DHMMode(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext) { uint8_t *dataToHash; /* a buffer used to store concatened data to be hashed */ uint16_t hashDataLength; /* Length of the buffer */ uint16_t hashDataIndex; /* an index used while filling the buffer */ uint8_t *ZIDi; /* a pointer to the 12 bytes string initiator's ZID */ uint8_t *ZIDr; /* a pointer to the 12 bytes string responder's ZID */ uint8_t *totalHash; uint8_t *s1=NULL; /* s1 is rs1 if we have it, rs2 otherwise, or null if we do not have rs2 too */ uint32_t s1Length=0; uint8_t *s2=NULL; /* s2 is aux secret if we have it, null otherwise */ uint32_t s2Length=0; uint8_t *s3=NULL; /* s3 is pbx secret if we have it, null otherwise */ uint32_t s3Length=0; /* first compute the total_hash as in rfc section 4.4.1.4 * total_hash = hash(Hello of responder || Commit || DHPart1 || DHPart2) * total_hash length depends on the agreed hash algo */ if (zrtpChannelContext->role == BZRTP_ROLE_RESPONDER) { hashDataLength = zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID]->messageLength + zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID]->messageLength + zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID]->messageLength + zrtpChannelContext->peerPackets[DHPART_MESSAGE_STORE_ID]->messageLength; dataToHash = (uint8_t *)malloc(hashDataLength*sizeof(uint8_t)); hashDataIndex = 0; memcpy(dataToHash+hashDataIndex, zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID]->messageLength); hashDataIndex +=zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID]->messageLength; memcpy(dataToHash+hashDataIndex, zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID]->messageLength); hashDataIndex +=zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID]->messageLength; memcpy(dataToHash+hashDataIndex, zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID]->messageLength); hashDataIndex +=zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID]->messageLength; memcpy(dataToHash+hashDataIndex, zrtpChannelContext->peerPackets[DHPART_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[DHPART_MESSAGE_STORE_ID]->messageLength); ZIDi = zrtpContext->peerZID; ZIDr = zrtpContext->selfZID; } else { /* we are initiator */ hashDataLength = zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->messageLength + zrtpChannelContext->selfPackets[COMMIT_MESSAGE_STORE_ID]->messageLength + zrtpChannelContext->peerPackets[DHPART_MESSAGE_STORE_ID]->messageLength + zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID]->messageLength; dataToHash = (uint8_t *)malloc(hashDataLength*sizeof(uint8_t)); hashDataIndex = 0; memcpy(dataToHash+hashDataIndex, zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->messageLength); hashDataIndex +=zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->messageLength; memcpy(dataToHash+hashDataIndex, zrtpChannelContext->selfPackets[COMMIT_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->selfPackets[COMMIT_MESSAGE_STORE_ID]->messageLength); hashDataIndex +=zrtpChannelContext->selfPackets[COMMIT_MESSAGE_STORE_ID]->messageLength; memcpy(dataToHash+hashDataIndex, zrtpChannelContext->peerPackets[DHPART_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[DHPART_MESSAGE_STORE_ID]->messageLength); hashDataIndex +=zrtpChannelContext->peerPackets[DHPART_MESSAGE_STORE_ID]->messageLength; memcpy(dataToHash+hashDataIndex, zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->selfPackets[DHPART_MESSAGE_STORE_ID]->messageLength); ZIDi = zrtpContext->selfZID; ZIDr = zrtpContext->peerZID; } totalHash = (uint8_t *)malloc(zrtpChannelContext->hashLength); zrtpChannelContext->hashFunction(dataToHash, hashDataLength, zrtpChannelContext->hashLength, totalHash); free(dataToHash); /* compute KDFContext = (ZIDi || ZIDr || total_hash) and set it in the channel context */ zrtpChannelContext->KDFContextLength = 24+zrtpChannelContext->hashLength; /* 24 for two 12 bytes ZID */ zrtpChannelContext->KDFContext = (uint8_t *)malloc(zrtpChannelContext->KDFContextLength*sizeof(uint8_t)); memcpy(zrtpChannelContext->KDFContext, ZIDi, 12); /* ZIDi*/ memcpy(zrtpChannelContext->KDFContext+12, ZIDr, 12); /* ZIDr */ memcpy(zrtpChannelContext->KDFContext+24, totalHash, zrtpChannelContext->hashLength); /* total Hash*/ free(totalHash); /* total hash is not needed anymore, get it from KDF Context in s0 computation */ /* compute s0 = hash(counter || DHResult || "ZRTP-HMAC-KDF" || ZIDi || ZIDr || total_hash || len(s1) || s1 || len(s2) || s2 || len(s3) || s3) * counter is a fixed 32 bits integer in big endian set to 1 : 0x00000001 */ /* get s1 from rs1 or rs2 */ if (zrtpContext->cachedSecret.rs1 != NULL) { /* if there is a s1 (already validated when received the DHpacket) */ s1 = zrtpContext->cachedSecret.rs1; s1Length = zrtpContext->cachedSecret.rs1Length; } else if (zrtpContext->cachedSecret.rs2 != NULL) { /* otherwise if there is a s2 (already validated when received the DHpacket) */ s1 = zrtpContext->cachedSecret.rs2; s1Length = zrtpContext->cachedSecret.rs2Length; } /* s2 is the auxsecret */ s2 = zrtpContext->cachedSecret.auxsecret; /* this may be null if no match or no aux secret where found */ s2Length = zrtpContext->cachedSecret.auxsecretLength; /* this may be 0 if no match or no aux secret where found */ /* s3 is the pbxsecret */ s3 = zrtpContext->cachedSecret.pbxsecret; /* this may be null if no match or no pbx secret where found */ s3Length = zrtpContext->cachedSecret.pbxsecretLength; /* this may be 0 if no match or no pbx secret where found */ hashDataLength = 4/*counter*/ + zrtpChannelContext->keyAgreementLength/*DHResult*/+13/*ZRTP-HMAC-KDF string*/ + 12/*ZIDi*/ + 12/*ZIDr*/ + zrtpChannelContext->hashLength/*total_hash*/ + 4/*len(s1)*/ +s1Length/*s1*/ + 4/*len(s2)*/ +s2Length/*s2*/ + 4/*len(s3)*/ + s3Length/*s3*/; dataToHash = (uint8_t *)malloc(hashDataLength*sizeof(uint8_t)); /* counter */ dataToHash[0] = 0x00; dataToHash[1] = 0x00; dataToHash[2] = 0x00; dataToHash[3] = 0x01; hashDataIndex = 4; memcpy(dataToHash+hashDataIndex, zrtpContext->DHMContext->key, zrtpChannelContext->keyAgreementLength); hashDataIndex += zrtpChannelContext->keyAgreementLength; memcpy(dataToHash+hashDataIndex, "ZRTP-HMAC-KDF", 13); hashDataIndex += 13; /* KDF Context is already ZIDi || ZIDr || total_hash use it directly */ memcpy(dataToHash+hashDataIndex, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength); hashDataIndex += zrtpChannelContext->KDFContextLength; dataToHash[hashDataIndex++] = (uint8_t)((s1Length>>24)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)((s1Length>>16)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)((s1Length>>8)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)(s1Length&0xFF); if (s1!=NULL) { memcpy(dataToHash+hashDataIndex, s1, s1Length); hashDataIndex += s1Length; } dataToHash[hashDataIndex++] = (uint8_t)((s2Length>>24)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)((s2Length>>16)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)((s2Length>>8)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)(s2Length&0xFF); if (s2!=NULL) { memcpy(dataToHash+hashDataIndex, s2, s2Length); hashDataIndex += s2Length; } dataToHash[hashDataIndex++] = (uint8_t)((s3Length>>24)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)((s3Length>>16)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)((s3Length>>8)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)(s3Length&0xFF); if (s3!=NULL) { memcpy(dataToHash+hashDataIndex, s3, s3Length); hashDataIndex += s3Length; } /* clean local s1,s2,s3 pointers as they are not needed anymore */ s1=NULL; s2=NULL; s3=NULL; zrtpChannelContext->s0 = (uint8_t *)malloc(zrtpChannelContext->hashLength*sizeof(uint8_t)); zrtpChannelContext->hashFunction(dataToHash, hashDataLength, zrtpChannelContext->hashLength, zrtpChannelContext->s0); free(dataToHash); /* now compute the ZRTPSession key : section 4.5.2 * ZRTPSess = KDF(s0, "ZRTP Session Key", KDF_Context, negotiated hash length)*/ zrtpContext->ZRTPSessLength=zrtpChannelContext->hashLength; /* must be set to the length of negotiated hash */ zrtpContext->ZRTPSess = (uint8_t *)malloc(zrtpContext->ZRTPSessLength*sizeof(uint8_t)); bzrtp_keyDerivationFunction(zrtpChannelContext->s0, zrtpChannelContext->hashLength, (uint8_t *)"ZRTP Session Key", 16, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, zrtpChannelContext->hashLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, zrtpContext->ZRTPSess); /* clean the DHM context (secret and key shall be erased by this operation) */ bctbx_DestroyDHMContext(zrtpContext->DHMContext); zrtpContext->DHMContext = NULL; /* now derive the other keys */ return bzrtp_deriveKeysFromS0(zrtpContext, zrtpChannelContext); } /** * @brief In multistream mode, when we must send a confirm1 or receive a confirm1 for the first time, call the function to compute * s0, KDF context and derive mac and srtp keys * * param[in] zrtpContext The context we are operation on(where to find the ZRTPSess) * param[in] zrtpChannelContext The channel context we are operation on * * return 0 on success, error code otherwise */ int bzrtp_computeS0MultiStreamMode(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext) { uint8_t *dataToHash; /* a buffer used to store concatened data to be hashed */ uint16_t hashDataLength; /* Length of the buffer */ uint16_t hashDataIndex; /* an index used while filling the buffer */ uint8_t *ZIDi; /* a pointer to the 12 bytes string initiator's ZID */ uint8_t *ZIDr; /* a pointer to the 12 bytes string responder's ZID */ uint8_t *totalHash; int retval; /* compute the total hash as in rfc section 4.4.3.2 total_hash = hash(Hello of responder || Commit) */ if (zrtpChannelContext->role == BZRTP_ROLE_RESPONDER) { /* if we are responder */ hashDataLength = zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID]->messageLength + zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID]->messageLength; dataToHash = (uint8_t *)malloc(hashDataLength*sizeof(uint8_t)); hashDataIndex = 0; memcpy(dataToHash, zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID]->messageLength); hashDataIndex += zrtpChannelContext->selfPackets[HELLO_MESSAGE_STORE_ID]->messageLength; memcpy(dataToHash+hashDataIndex, zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[COMMIT_MESSAGE_STORE_ID]->messageLength); ZIDi = zrtpContext->peerZID; ZIDr = zrtpContext->selfZID; } else { /* if we are initiator */ hashDataLength = zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->messageLength + zrtpChannelContext->selfPackets[COMMIT_MESSAGE_STORE_ID]->messageLength; dataToHash = (uint8_t *)malloc(hashDataLength*sizeof(uint8_t)); hashDataIndex = 0; memcpy(dataToHash, zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->messageLength); hashDataIndex += zrtpChannelContext->peerPackets[HELLO_MESSAGE_STORE_ID]->messageLength; memcpy(dataToHash+hashDataIndex, zrtpChannelContext->selfPackets[COMMIT_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, zrtpChannelContext->selfPackets[COMMIT_MESSAGE_STORE_ID]->messageLength); ZIDi = zrtpContext->selfZID; ZIDr = zrtpContext->peerZID; } totalHash = (uint8_t *)malloc(zrtpChannelContext->hashLength); zrtpChannelContext->hashFunction(dataToHash, hashDataLength, zrtpChannelContext->hashLength, totalHash); free(dataToHash); /* compute KDFContext = (ZIDi || ZIDr || total_hash) and set it in the channel context */ zrtpChannelContext->KDFContextLength = 24+zrtpChannelContext->hashLength; /* 24 for two 12 bytes ZID */ zrtpChannelContext->KDFContext = (uint8_t *)malloc(zrtpChannelContext->KDFContextLength*sizeof(uint8_t)); memcpy(zrtpChannelContext->KDFContext, ZIDi, 12); /* ZIDi*/ memcpy(zrtpChannelContext->KDFContext+12, ZIDr, 12); /* ZIDr */ memcpy(zrtpChannelContext->KDFContext+24, totalHash, zrtpChannelContext->hashLength); /* total Hash*/ free(totalHash); /* total hash is not needed anymore, get it from KDF Context in s0 computation */ /* compute s0 as in rfc section 4.4.3.2 s0 = KDF(ZRTPSess, "ZRTP MSK", KDF_Context, negotiated hash length) */ zrtpChannelContext->s0 = (uint8_t *)malloc(zrtpChannelContext->hashLength*sizeof(uint8_t)); retval = bzrtp_keyDerivationFunction(zrtpContext->ZRTPSess, zrtpContext->ZRTPSessLength, (uint8_t *)"ZRTP MSK", 8, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, zrtpChannelContext->hashLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, zrtpChannelContext->s0); if (retval != 0) { return retval; } /* now derive the other keys */ return bzrtp_deriveKeysFromS0(zrtpContext, zrtpChannelContext); } /** * @brief This function is called after s0 (and ZRTPSess when non in Multistream mode) have been computed to derive the other keys * Keys computed are: mackeyi, mackeyr, zrtpkeyi and zrtpkeyr, srtpkeys and salt * * param[in] zrtpContext The context we are operation on(contains ZRTPSess) * param[in/out] zrtpChannelContext The channel context we are operation on(contains s0 and will get the computed keys) * * return 0 on success, error code otherwise * */ int bzrtp_deriveKeysFromS0(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext) { int retval = 0; /* allocate memory for mackeyi, mackeyr, zrtpkeyi, zrtpkeyr */ zrtpChannelContext->mackeyi = (uint8_t *)malloc(zrtpChannelContext->hashLength*(sizeof(uint8_t))); zrtpChannelContext->mackeyr = (uint8_t *)malloc(zrtpChannelContext->hashLength*(sizeof(uint8_t))); zrtpChannelContext->zrtpkeyi = (uint8_t *)malloc(zrtpChannelContext->cipherKeyLength*(sizeof(uint8_t))); zrtpChannelContext->zrtpkeyr = (uint8_t *)malloc(zrtpChannelContext->cipherKeyLength*(sizeof(uint8_t))); /* derive the keys according to rfc section 4.5.3 */ /* mackeyi = KDF(s0, "Initiator HMAC key", KDF_Context, negotiated hash length)*/ retval = bzrtp_keyDerivationFunction(zrtpChannelContext->s0, zrtpChannelContext->hashLength, (uint8_t *)"Initiator HMAC key", 18, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, zrtpChannelContext->hashLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, zrtpChannelContext->mackeyi); /* mackeyr = KDF(s0, "Responder HMAC key", KDF_Context, negotiated hash length) */ retval += bzrtp_keyDerivationFunction(zrtpChannelContext->s0, zrtpChannelContext->hashLength, (uint8_t *)"Responder HMAC key", 18, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, zrtpChannelContext->hashLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, zrtpChannelContext->mackeyr); /* zrtpkeyi = KDF(s0, "Initiator ZRTP key", KDF_Context, negotiated AES key length) */ retval += bzrtp_keyDerivationFunction(zrtpChannelContext->s0, zrtpChannelContext->hashLength, (uint8_t *)"Initiator ZRTP key", 18, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, zrtpChannelContext->cipherKeyLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, zrtpChannelContext->zrtpkeyi); /* zrtpkeyr = KDF(s0, "Responder ZRTP key", KDF_Context, negotiated AES key length) */ retval += bzrtp_keyDerivationFunction(zrtpChannelContext->s0, zrtpChannelContext->hashLength, (uint8_t *)"Responder ZRTP key", 18, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, zrtpChannelContext->cipherKeyLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, zrtpChannelContext->zrtpkeyr); return retval; } /** * @brief This function is called after confirm1 is received by initiator or confirm2 by responder * Keys computed are: srtp self and peer keys and salt, SAS(if mode is not multistream). * The whole bzrtpSrtpSecrets_t structure is ready after this call * * param[in] zrtpContext The context we are operation on * param[in/out] zrtpChannelContext The channel context we are operation on(contains s0 and will get the computed keys) * * return 0 on success, error code otherwise * */ int bzrtp_deriveSrtpKeysFromS0(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext) { int retval = 0; /* allocate memory */ uint8_t *srtpkeyi = (uint8_t *)malloc(zrtpChannelContext->cipherKeyLength*sizeof(uint8_t)); uint8_t *srtpkeyr = (uint8_t *)malloc(zrtpChannelContext->cipherKeyLength*sizeof(uint8_t)); uint8_t *srtpsalti = (uint8_t *)malloc(14*sizeof(uint8_t));/* salt length is defined to be 112 bits(14 bytes) in rfc section 4.5.3 */ uint8_t *srtpsaltr = (uint8_t *)malloc(14*sizeof(uint8_t));/* salt length is defined to be 112 bits(14 bytes) in rfc section 4.5.3 */ /* compute keys and salts according to rfc section 4.5.3 */ /* srtpkeyi = KDF(s0, "Initiator SRTP master key", KDF_Context, negotiated AES key length) */ retval = bzrtp_keyDerivationFunction(zrtpChannelContext->s0, zrtpChannelContext->hashLength, (uint8_t *)"Initiator SRTP master key", 25, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, zrtpChannelContext->cipherKeyLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, srtpkeyi); /* srtpsalti = KDF(s0, "Initiator SRTP master salt", KDF_Context, 112) */ retval += bzrtp_keyDerivationFunction(zrtpChannelContext->s0, zrtpChannelContext->hashLength, (uint8_t *)"Initiator SRTP master salt", 26, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, 14, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, srtpsalti); /* srtpkeyr = KDF(s0, "Responder SRTP master key", KDF_Context, negotiated AES key length) */ retval += bzrtp_keyDerivationFunction(zrtpChannelContext->s0, zrtpChannelContext->hashLength, (uint8_t *)"Responder SRTP master key", 25, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, zrtpChannelContext->cipherKeyLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, srtpkeyr); /* srtpsaltr = KDF(s0, "Responder SRTP master salt", KDF_Context, 112) */ retval += bzrtp_keyDerivationFunction(zrtpChannelContext->s0, zrtpChannelContext->hashLength, (uint8_t *)"Responder SRTP master salt", 26, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, 14, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, srtpsaltr); if (retval!=0) { free(srtpkeyi); free(srtpkeyr); free(srtpsalti); free(srtpsaltr); return retval; } /* Associate responder or initiator to self or peer. Self is used to locally encrypt and peer to decrypt */ if (zrtpChannelContext->role == BZRTP_ROLE_INITIATOR) { /* we use keyi to encrypt and keyr to decrypt */ zrtpChannelContext->srtpSecrets.selfSrtpKey = srtpkeyi; zrtpChannelContext->srtpSecrets.selfSrtpSalt = srtpsalti; zrtpChannelContext->srtpSecrets.peerSrtpKey = srtpkeyr; zrtpChannelContext->srtpSecrets.peerSrtpSalt = srtpsaltr; } else { /* we use keyr to encrypt and keyi to decrypt */ zrtpChannelContext->srtpSecrets.selfSrtpKey = srtpkeyr; zrtpChannelContext->srtpSecrets.selfSrtpSalt = srtpsaltr; zrtpChannelContext->srtpSecrets.peerSrtpKey = srtpkeyi; zrtpChannelContext->srtpSecrets.peerSrtpSalt = srtpsalti; } /* Set the length in secrets structure */ zrtpChannelContext->srtpSecrets.selfSrtpKeyLength = zrtpChannelContext->cipherKeyLength; zrtpChannelContext->srtpSecrets.selfSrtpSaltLength = 14; /* salt length is defined to be 112 bits(14 bytes) in rfc section 4.5.3 */ zrtpChannelContext->srtpSecrets.peerSrtpKeyLength = zrtpChannelContext->cipherKeyLength; zrtpChannelContext->srtpSecrets.peerSrtpSaltLength = 14; /* salt length is defined to be 112 bits(14 bytes) in rfc section 4.5.3 */ /* Set the used algo in secrets structure */ zrtpChannelContext->srtpSecrets.cipherAlgo = zrtpChannelContext->cipherAlgo; zrtpChannelContext->srtpSecrets.cipherKeyLength = zrtpChannelContext->cipherKeyLength; zrtpChannelContext->srtpSecrets.authTagAlgo = zrtpChannelContext->authTagAlgo; /* for information purpose, add the negotiated algorithm */ zrtpChannelContext->srtpSecrets.hashAlgo = zrtpChannelContext->hashAlgo; zrtpChannelContext->srtpSecrets.keyAgreementAlgo = zrtpChannelContext->keyAgreementAlgo; zrtpChannelContext->srtpSecrets.sasAlgo = zrtpChannelContext->sasAlgo; /* compute the SAS according to rfc section 4.5.2 sashash = KDF(s0, "SAS", KDF_Context, 256) */ if (zrtpChannelContext->keyAgreementAlgo != ZRTP_KEYAGREEMENT_Mult) { /* only when not in Multistream mode */ uint8_t sasHash[32]; /* length of hash is 256 bits -> 32 bytes */ uint32_t sasValue; retval = bzrtp_keyDerivationFunction(zrtpChannelContext->s0, zrtpChannelContext->hashLength, (uint8_t *)"SAS", 3, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, 32, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, sasHash); if (retval!=0) { return retval; } /* now get it into a char according to the selected algo */ sasValue = ((uint32_t)sasHash[0]<<24) | ((uint32_t)sasHash[1]<<16) | ((uint32_t)sasHash[2]<<8) | ((uint32_t)(sasHash[3])); zrtpChannelContext->srtpSecrets.sasLength = zrtpChannelContext->sasLength; zrtpChannelContext->srtpSecrets.sas = (char *)malloc((zrtpChannelContext->sasLength)*sizeof(char)); /*this shall take in account the selected representation algo for SAS */ zrtpChannelContext->sasFunction(sasValue, zrtpChannelContext->srtpSecrets.sas, zrtpChannelContext->sasLength); /* set also the cache mismtach flag in srtpSecrets structure, may occurs only on the first channel */ if (zrtpContext->cacheMismatchFlag!=0) { zrtpChannelContext->srtpSecrets.cacheMismatch = 1; } } return 0; } /* * @brief Compute the new rs1 and update the cached secrets according to rfc section 4.6.1 * * param[in] zrtpContext The context we are operation on * param[in/out] zrtpChannelContext The channel context we are operation on(contains s0) * * return 0 on success, error code otherwise */ int bzrtp_updateCachedSecrets(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext) { char *colNames[] = {"rs1", "rs2"}; uint8_t *colValues[2] = {NULL, NULL}; size_t colLength[2] = {RETAINED_SECRET_LENGTH,0}; /* if this channel context is in multistream mode, do nothing */ if (zrtpChannelContext->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Mult) { /* destroy s0 */ bzrtp_DestroyKey(zrtpChannelContext->s0, zrtpChannelContext->hashLength, zrtpContext->RNGContext); free(zrtpChannelContext->s0); zrtpChannelContext->s0 = NULL; return 0; } /* if we had a cache mismatch, the update must be delayed until Sas confirmation by user, just do nothing, the update function will be called again when done */ if (zrtpContext->cacheMismatchFlag == 1) { return 0; } /* if this channel context is in DHM mode, backup rs1 in rs2 if it exists */ if (zrtpChannelContext->keyAgreementAlgo != ZRTP_KEYAGREEMENT_Prsh) { if (zrtpContext->cachedSecret.rs1 != NULL) { /* store rs2 pointer and length to be passed to cache_write function (otherwise, keep NULL and the rs2 in cache will be erased) */ colValues[1] = zrtpContext->cachedSecret.rs1; colLength[1] = RETAINED_SECRET_LENGTH; } } /* compute rs1 = KDF(s0, "retained secret", KDF_Context, 256) */ zrtpContext->cachedSecret.rs1 = (uint8_t *)malloc(RETAINED_SECRET_LENGTH); /* Allocate a new buffer for rs1, the old one if exists if still pointed at by colValues[1] */ zrtpContext->cachedSecret.rs1Length = RETAINED_SECRET_LENGTH; bzrtp_keyDerivationFunction(zrtpChannelContext->s0, zrtpChannelContext->hashLength, (uint8_t *)"retained secret", 15, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, RETAINED_SECRET_LENGTH, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, zrtpContext->cachedSecret.rs1); colValues[0]=zrtpContext->cachedSecret.rs1; bzrtp_cache_write(zrtpContext->zidCache, zrtpContext->zuid, "zrtp", colNames, colValues, colLength, 2); /* if exist, call the callback function to perform custom cache operation that may use s0(writing exported key into cache) */ if (zrtpContext->zrtpCallbacks.bzrtp_contextReadyForExportedKeys != NULL) { zrtpContext->zrtpCallbacks.bzrtp_contextReadyForExportedKeys(zrtpChannelContext->clientData, zrtpContext->zuid, zrtpChannelContext->role); /* destroy exportedKey if we computed one */ if (zrtpContext->exportedKey!=NULL) { bzrtp_DestroyKey(zrtpContext->exportedKey, zrtpContext->exportedKeyLength, zrtpContext->RNGContext); free(zrtpContext->exportedKey); zrtpContext->exportedKey=NULL; } } /* destroy s0 */ bzrtp_DestroyKey(zrtpChannelContext->s0, zrtpChannelContext->hashLength, zrtpContext->RNGContext); free(zrtpChannelContext->s0); zrtpChannelContext->s0 = NULL; /* destroy all cached keys in context they are not needed anymore (multistream mode doesn't use them to compute s0) */ if (colValues[1] != NULL) { /* destroy the old rs1 whose pointer was saved in colValues[1] before secrets.rs1 being crushed by the new rs1 */ bzrtp_DestroyKey(colValues[1], zrtpContext->cachedSecret.rs1Length, zrtpContext->RNGContext); free(colValues[1]); colValues[1]=NULL; } if (zrtpContext->cachedSecret.rs1!=NULL) { bzrtp_DestroyKey(zrtpContext->cachedSecret.rs1, zrtpContext->cachedSecret.rs1Length, zrtpContext->RNGContext); free(zrtpContext->cachedSecret.rs1); zrtpContext->cachedSecret.rs1 = NULL; } if (zrtpContext->cachedSecret.rs2!=NULL) { bzrtp_DestroyKey(zrtpContext->cachedSecret.rs2, zrtpContext->cachedSecret.rs2Length, zrtpContext->RNGContext); free(zrtpContext->cachedSecret.rs2); zrtpContext->cachedSecret.rs2 = NULL; } if (zrtpContext->cachedSecret.auxsecret!=NULL) { bzrtp_DestroyKey(zrtpContext->cachedSecret.auxsecret, zrtpContext->cachedSecret.auxsecretLength, zrtpContext->RNGContext); free(zrtpContext->cachedSecret.auxsecret); zrtpContext->cachedSecret.auxsecret = NULL; } if (zrtpContext->cachedSecret.pbxsecret!=NULL) { bzrtp_DestroyKey(zrtpContext->cachedSecret.pbxsecret, zrtpContext->cachedSecret.pbxsecretLength, zrtpContext->RNGContext); free(zrtpContext->cachedSecret.pbxsecret); zrtpContext->cachedSecret.pbxsecret = NULL; } return 0; } bzrtp-1.0.6/src/zidCache.c000066400000000000000000001021651313411235300153250ustar00rootroot00000000000000/** @file zidCache.c @brief all ZID and cache related operations are implemented in this file - get or create ZID - get/update associated secrets It supports cacheless implementation when cache file access functions are null @author Johan Pascal @copyright Copyright (C) 2014 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include "typedef.h" #include #include "cryptoUtils.h" #include "zidCache.h" #ifdef ZIDCACHE_ENABLED #include "sqlite3.h" #ifdef HAVE_LIBXML2 #include #include #endif /* HAVE_LIBXML2 */ #ifdef _WIN32 #include #else #include #endif /* define a version number for the DB schema as an interger MMmmpp */ /* current version is 0.0.1 */ #define ZIDCACHE_DBSCHEMA_VERSION_NUMBER 000001 static int callback_getSelfZID(void *data, int argc, char **argv, char **colName){ uint8_t **selfZID = (uint8_t **)data; /* we selected zid only, it must then be in argv[0] */ if (argv[0]) { *selfZID = (uint8_t *)malloc(12*sizeof(uint8_t)); memcpy(*selfZID, argv[0], 12); } return 0; } static int callback_getUserVersion(void *data, int argc, char **argv, char **colName){ int *userVersion = (int *)data; if (argv[0]) { *userVersion = atoi(argv[0]); } return 0; } /* ZID cache is split in several tables * ziduri : zuid(unique key) | ZID | selfuri | peeruri * zuid(ZID/URI binding id) will be used for fastest access to the cache, it binds a local user(self uri/self ZID) to a peer identified both by URI and ZID * self ZID is stored in this table too in a record having 'self' as peer uri, each local user(uri) has a different ZID * * All values except zuid in the following tables are blob, actual integers are split and stored in big endian by callers * zrtp : zuid(as foreign key) | rs1 | rs2 | aux secret | pbx secret | pvs flag * lime : zuid(as foreign key) | sndKey | rcvKey | sndSId | rcvSId | snd Index | rcv Index | valid */ int bzrtp_initCache(void *dbPointer) { char* errmsg=NULL; int ret; char *sql; sqlite3_stmt *stmt = NULL; int userVersion=-1; sqlite3 *db = (sqlite3 *)dbPointer; int retval = 0; if (dbPointer == NULL) { /* we are running cacheless */ return BZRTP_ZIDCACHE_RUNTIME_CACHELESS; } /* get current db schema version (user_version pragma in sqlite )*/ sql = sqlite3_mprintf("PRAGMA user_version;"); ret = sqlite3_exec(db, sql, callback_getUserVersion, &userVersion, &errmsg); sqlite3_free(sql); if (ret!=SQLITE_OK) { sqlite3_free(errmsg); return BZRTP_ZIDCACHE_UNABLETOREAD; } /* Here check version number and provide upgrade is needed */ if (userVersion != ZIDCACHE_DBSCHEMA_VERSION_NUMBER) { if (userVersion > ZIDCACHE_DBSCHEMA_VERSION_NUMBER) { /* nothing to do if we encounter a superior version number than expected, just hope it is compatible */ //TODO: Log this event } else { /* Perform update if needed */ /* update the schema version in DB metadata */ sql = sqlite3_mprintf("PRAGMA user_version = %d;",ZIDCACHE_DBSCHEMA_VERSION_NUMBER); ret = sqlite3_prepare(db, sql, -1, &stmt, NULL); sqlite3_free(sql); if (ret != SQLITE_OK) { return BZRTP_ZIDCACHE_UNABLETOUPDATE; } ret = sqlite3_step(stmt); if (ret != SQLITE_DONE) { return BZRTP_ZIDCACHE_UNABLETOUPDATE; } sqlite3_finalize(stmt); /* setup return value : SETUP for a brand new populated cache, update if we updated the scheme */ if (userVersion == 0) { retval = BZRTP_CACHE_SETUP; } else { retval = BZRTP_CACHE_UPDATE; } } } /* make sure foreign key are turned ON on this connection */ ret = sqlite3_prepare(db, "PRAGMA foreign_keys = ON;", -1, &stmt, NULL); if (ret != SQLITE_OK) { return BZRTP_ZIDCACHE_UNABLETOUPDATE; } ret = sqlite3_step(stmt); if (ret != SQLITE_DONE) { return BZRTP_ZIDCACHE_UNABLETOUPDATE; } sqlite3_finalize(stmt); /* check/create the ziduri table */ ret=sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS ziduri (" "zuid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," "zid BLOB NOT NULL DEFAULT '000000000000'," "selfuri TEXT NOT NULL DEFAULT 'unset'," "peeruri TEXT NOT NULL DEFAULT 'unset'" ");", 0,0,&errmsg); if(ret != SQLITE_OK) { sqlite3_free(errmsg); return BZRTP_ZIDCACHE_UNABLETOUPDATE; } /* check/create the zrtp table */ ret=sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS zrtp (" "zuid INTEGER NOT NULL DEFAULT 0 UNIQUE," "rs1 BLOB DEFAULT NULL," "rs2 BLOB DEFAULT NULL," "aux BLOB DEFAULT NULL," "pbx BLOB DEFAULT NULL," "pvs BLOB DEFAULT NULL," "FOREIGN KEY(zuid) REFERENCES ziduri(zuid) ON UPDATE CASCADE ON DELETE CASCADE" ");", 0,0,&errmsg); if(ret != SQLITE_OK) { sqlite3_free(errmsg); return BZRTP_ZIDCACHE_UNABLETOUPDATE; } /* check/create the lime table */ ret=sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS lime (" "zuid INTEGER NOT NULL DEFAULT 0 UNIQUE," "sndKey BLOB DEFAULT NULL," "rcvKey BLOB DEFAULT NULL," "sndSId BLOB DEFAULT NULL," "rcvSId BLOB DEFAULT NULL," "sndIndex BLOB DEFAULT NULL," "rcvIndex BLOB DEFAULT NULL," "valid BLOB DEFAULT NULL," "FOREIGN KEY(zuid) REFERENCES ziduri(zuid) ON UPDATE CASCADE ON DELETE CASCADE" ");", 0,0,&errmsg); if(ret != SQLITE_OK) { sqlite3_free(errmsg); return BZRTP_ZIDCACHE_UNABLETOUPDATE; } return retval; } int bzrtp_getSelfZID(void *dbPointer, const char *selfURI, uint8_t selfZID[12], bctbx_rng_context_t *RNGContext) { char* errmsg=NULL; int ret; char *stmt; uint8_t *localZID = NULL; sqlite3 *db = (sqlite3 *)dbPointer; if (dbPointer == NULL) { /* we are running cacheless, generate a random ZID if we have a RNG*/ if (RNGContext != NULL) { bctbx_rng_get(RNGContext, selfZID, 12); return 0; } else { return BZRTP_CACHE_DATA_NOTFOUND; } } /* check/create the self zid in ziduri table, ORDER BY is just to ensure consistent return in case of inconsistent table(with several self ZID for the same selfuri) */ stmt = sqlite3_mprintf("SELECT zid FROM ziduri WHERE selfuri=%Q AND peeruri='self' ORDER BY zuid LIMIT 1;",selfURI); ret = sqlite3_exec(db,stmt,callback_getSelfZID,&localZID,&errmsg); if (ret != SQLITE_OK) { sqlite3_free(errmsg); return BZRTP_ZIDCACHE_UNABLETOREAD; } sqlite3_free(stmt); /* Do we have a self ZID in cache? */ if (localZID == NULL) { uint8_t generatedZID[12]; sqlite3_stmt *insertStatement = NULL; /* generate a ZID if we can */ if (RNGContext != NULL) { bctbx_rng_get(RNGContext, generatedZID, 12); } else { return BZRTP_CACHE_DATA_NOTFOUND; } /* insert it in the table */ ret = sqlite3_prepare_v2(db, "INSERT INTO ziduri (zid,selfuri,peeruri) VALUES(?,?,?);", -1, &insertStatement, NULL); if (ret != SQLITE_OK) { return BZRTP_ZIDCACHE_UNABLETOUPDATE; } sqlite3_bind_blob(insertStatement, 1, generatedZID, 12, SQLITE_TRANSIENT); sqlite3_bind_text(insertStatement, 2, selfURI,-1,SQLITE_TRANSIENT); sqlite3_bind_text(insertStatement, 3, "self",-1,SQLITE_TRANSIENT); ret = sqlite3_step(insertStatement); if (ret!=SQLITE_DONE) { return BZRTP_ZIDCACHE_UNABLETOUPDATE; } sqlite3_finalize(insertStatement); /* copy it in the output buffer */ memcpy(selfZID, generatedZID,12); } else { /* we found a ZID, copy it in the output buffer */ memcpy(selfZID, localZID, 12); free(localZID); } return 0; } /** * @brief Parse the cache to find secrets associated to the given ZID, set them and their length in the context if they are found * * @param[in/out] context the current context, used to get the negotiated Hash algorithm, cache db, peerURI and store results * @param[in] peerZID a byte array of the peer ZID * * return 0 on succes, error code otherwise */ int bzrtp_getPeerAssociatedSecrets(bzrtpContext_t *context, uint8_t peerZID[12]) { char *stmt = NULL; int ret; sqlite3_stmt *sqlStmt = NULL; int length =0; if (context == NULL) { return BZRTP_ZIDCACHE_INVALID_CONTEXT; } /* resert cached secret buffer */ free(context->cachedSecret.rs1); free(context->cachedSecret.rs2); free(context->cachedSecret.pbxsecret); free(context->cachedSecret.auxsecret); context->cachedSecret.rs1 = NULL; context->cachedSecret.rs1Length = 0; context->cachedSecret.rs2 = NULL; context->cachedSecret.rs2Length = 0; context->cachedSecret.pbxsecret = NULL; context->cachedSecret.pbxsecretLength = 0; context->cachedSecret.auxsecret = NULL; context->cachedSecret.auxsecretLength = 0; context->cachedSecret.previouslyVerifiedSas = 0; /* are we going cacheless at runtime */ if (context->zidCache == NULL) { /* we are running cacheless */ return BZRTP_ZIDCACHE_RUNTIME_CACHELESS; } /* get all secrets from zrtp table, ORDER BY is just to ensure consistent return in case of inconsistent table) */ stmt = sqlite3_mprintf("SELECT z.zuid, z.rs1, z.rs2, z.aux, z.pbx, z.pvs FROM ziduri as zu LEFT JOIN zrtp as z ON z.zuid=zu.zuid WHERE zu.selfuri=? AND zu.peeruri=? AND zu.zid=? ORDER BY zu.zuid LIMIT 1;"); ret = sqlite3_prepare_v2(context->zidCache, stmt, -1, &sqlStmt, NULL); sqlite3_free(stmt); if (ret != SQLITE_OK) { return BZRTP_ZIDCACHE_UNABLETOREAD; } sqlite3_bind_text(sqlStmt, 1, context->selfURI,-1,SQLITE_TRANSIENT); sqlite3_bind_text(sqlStmt, 2, context->peerURI,-1,SQLITE_TRANSIENT); sqlite3_bind_blob(sqlStmt, 3, peerZID, 12, SQLITE_TRANSIENT); ret = sqlite3_step(sqlStmt); if (ret!=SQLITE_ROW) { sqlite3_finalize(sqlStmt); if (ret == SQLITE_DONE) {/* not found in cache, just leave cached secrets reset, but retrieve (or create) zuid */ return bzrtp_cache_getZuid((void *)context->zidCache, context->selfURI, context->peerURI, context->peerZID, &context->zuid); } else { /* we had an error querying the DB... */ return BZRTP_ZIDCACHE_UNABLETOREAD; } } /* get zuid from column 0 */ context->zuid = sqlite3_column_int(sqlStmt, 0); /* retrieve values : rs1, rs2, aux, pbx, they all are blob, columns 1,2,3,4 */ length = sqlite3_column_bytes(sqlStmt, 1); if (length>0) { /* we have rs1 */ context->cachedSecret.rs1Length = length; context->cachedSecret.rs1 = (uint8_t *)malloc(length*sizeof(uint8_t)); memcpy(context->cachedSecret.rs1, sqlite3_column_blob(sqlStmt, 1), length); } length = sqlite3_column_bytes(sqlStmt, 2); if (length>0) { /* we have rs2 */ context->cachedSecret.rs2Length = length; context->cachedSecret.rs2 = (uint8_t *)malloc(length*sizeof(uint8_t)); memcpy(context->cachedSecret.rs2, sqlite3_column_blob(sqlStmt, 2), length); } length = sqlite3_column_bytes(sqlStmt, 3); if (length>0) { /* we have aux */ context->cachedSecret.auxsecretLength = length; context->cachedSecret.auxsecret = (uint8_t *)malloc(length*sizeof(uint8_t)); memcpy(context->cachedSecret.auxsecret, sqlite3_column_blob(sqlStmt, 3), length); } length = sqlite3_column_bytes(sqlStmt, 4); if (length>0) { /* we have pbx */ context->cachedSecret.pbxsecretLength = length; context->cachedSecret.pbxsecret = (uint8_t *)malloc(length*sizeof(uint8_t)); memcpy(context->cachedSecret.pbxsecret, sqlite3_column_blob(sqlStmt, 4), length); } /* pvs is stored as blob in memory, just get the first byte(length shall be one anyway) and consider */ /* it may be NULL -> consider it 0 */ length = sqlite3_column_bytes(sqlStmt, 5); if (length!=1) { context->cachedSecret.previouslyVerifiedSas = 0; /* anything wich is not 0x01 is considered 0, so none or more than 1 byte is 0 */ } else { if (*((uint8_t *)sqlite3_column_blob(sqlStmt, 5)) == 0x01) { context->cachedSecret.previouslyVerifiedSas = 1; } else { context->cachedSecret.previouslyVerifiedSas = 0; /* anything wich is not 0x01 is considered 0 */ } } sqlite3_finalize(sqlStmt); return 0; } /** * @brief get the cache internal id used to bind local uri(hence local ZID associated to it)<->peer uri/peer ZID. * Providing a valid local URI(already present in cache), a peer ZID and peer URI will return the zuid creating it if needed * Any pair ZID/sipURI shall identify an account on a device. * * @param[in/out] db the opened sqlite database pointer * @param[in] selfURI local URI, must be already associated to a ZID in the DB(association is performed by any call of getSelfZID on this URI) * @param[in] peerURI peer URI * @param[in] peerZID peer ZID * @param[out] zuid the internal db reference to the data row matching this particular pair of correspondant * * @return 0 on success, error code otherwise */ int bzrtp_cache_getZuid(void *dbPointer, const char *selfURI, const char *peerURI, const uint8_t peerZID[12], int *zuid) { char *stmt=NULL; int ret; sqlite3_stmt *sqlStmt = NULL; sqlite3 *db = (sqlite3 *)dbPointer; if (dbPointer == NULL) { /* we are running cacheless */ return BZRTP_ZIDCACHE_RUNTIME_CACHELESS; } /* Try to fetch the requested zuid */ stmt = sqlite3_mprintf("SELECT zuid FROM ziduri WHERE selfuri=? AND peeruri=? AND zid=? ORDER BY zuid LIMIT 1;"); ret = sqlite3_prepare_v2(db, stmt, -1, &sqlStmt, NULL); sqlite3_free(stmt); if (ret != SQLITE_OK) { return BZRTP_ZIDCACHE_UNABLETOREAD; } sqlite3_bind_text(sqlStmt, 1, selfURI,-1,SQLITE_TRANSIENT); sqlite3_bind_text(sqlStmt, 2, peerURI,-1,SQLITE_TRANSIENT); sqlite3_bind_blob(sqlStmt, 3, peerZID, 12, SQLITE_TRANSIENT); ret = sqlite3_step(sqlStmt); if (ret!=SQLITE_ROW) { /* We didn't found this binding in the DB */ sqlite3_finalize(sqlStmt); if (ret == SQLITE_DONE) { /* query executed correctly, just our data is not there */ uint8_t *localZID = NULL; char *errmsg=NULL; /* check that we have a self ZID matching the self URI and insert a new row */ stmt = sqlite3_mprintf("SELECT zid FROM ziduri WHERE selfuri=%Q AND peeruri='self' ORDER BY zuid LIMIT 1;",selfURI); ret = sqlite3_exec(db,stmt,callback_getSelfZID,&localZID,&errmsg); sqlite3_free(stmt); if (ret != SQLITE_OK) { sqlite3_free(errmsg); return BZRTP_ZIDCACHE_UNABLETOREAD; } if (localZID==NULL) { /* this sip URI is not in our DB, do not create an association with the peer ZID/URI binding */ return BZRTP_ZIDCACHE_BADINPUTDATA; } else { /* yes we know this URI on local device, add a row in the ziduri table */ stmt = sqlite3_mprintf("INSERT INTO ziduri (zid,selfuri,peeruri) VALUES(?,?,?);"); ret = sqlite3_prepare_v2(db, stmt, -1, &sqlStmt, NULL); if (ret != SQLITE_OK) { return BZRTP_ZIDCACHE_UNABLETOUPDATE; } sqlite3_free(stmt); sqlite3_bind_blob(sqlStmt, 1, peerZID, 12, SQLITE_TRANSIENT); sqlite3_bind_text(sqlStmt, 2, selfURI,-1,SQLITE_TRANSIENT); sqlite3_bind_text(sqlStmt, 3, peerURI,-1,SQLITE_TRANSIENT); ret = sqlite3_step(sqlStmt); if (ret!=SQLITE_DONE) { return BZRTP_ZIDCACHE_UNABLETOUPDATE; } sqlite3_finalize(sqlStmt); /* get the zuid created */ *zuid = (int)sqlite3_last_insert_rowid(db); return 0; } } else { /* we had an error querying the DB... */ return BZRTP_ZIDCACHE_UNABLETOREAD; } } /* retrieve value in column 0 */ *zuid = sqlite3_column_int(sqlStmt, 0); sqlite3_finalize(sqlStmt); return 0; } /** * @brief Write(insert or update) data in cache, adressing it by zuid (ZID/URI binding id used in cache) * Get arrays of column names, values to be inserted, lengths of theses values * All three arrays must be the same lenght: columnsCount * If the row isn't present in the given table, it will be inserted * * @param[in/out] dbPointer Pointer to an already opened sqlite db * @param[in] zuid The DB internal id to adress the correct row(binding between local uri and peer ZID+URI) * @param[in] tableName The name of the table to write in the db, must already exists. Null terminated string * @param[in] columns An array of null terminated strings containing the name of the columns to update * @param[in] values An array of buffers containing the values to insert/update matching the order of columns array * @param[in] lengths An array of integer containing the lengths of values array buffer matching the order of columns array * @param[in] columnsCount length common to columns,values and lengths arrays * * @return 0 on succes, error code otherwise */ int bzrtp_cache_write(void *dbPointer, int zuid, char *tableName, char **columns, uint8_t **values, size_t *lengths, uint8_t columnsCount) { char *stmt=NULL; int ret,i,j; sqlite3_stmt *sqlStmt = NULL; sqlite3 *db = (sqlite3 *)dbPointer; char *insertColumnsString=NULL; int insertColumnsStringLength=0; if (dbPointer == NULL) { /* we are running cacheless */ return BZRTP_ZIDCACHE_RUNTIME_CACHELESS; } /* As the zuid row may not be already present in the table, we must run an insert or update SQL command which is not provided by sqlite3 */ /* UPSERT strategy: run update first and check for changes */ /* do not perform any check on table name or columns name, the sql statement will just fail when they are wrong */ /* prepare the columns list string, use the %w formatting option as it shall protect us from anything in the column name */ for (i=0; i0) { /* we have rs1 */ lengths[i] = length; values[i] = (uint8_t *)malloc(length*sizeof(uint8_t)); memcpy(values[i], sqlite3_column_blob(sqlStmt, i), length); } else { /* data is null in DB */ values[i] = NULL; lengths[i] = 0; } } sqlite3_finalize(sqlStmt); return 0; } /** * @brief Perform migration from xml version to sqlite3 version of cache * Warning: new version of cache associate a ZID to each local URI, the old one did not * the migration function will associate any data in the cache to the sip URI given in parameter which shall be the default URI * @param[in] cacheXml a pointer to an xmlDocPtr structure containing the old cache to be migrated * @param[in/out] cacheSqlite a pointer to an sqlite3 structure containing a cache initialised using bzrtp_cache_init function * @param[in] selfURI default sip URI for this end point, NULL terminated char * * @return 0 on success, BZRTP_ERROR_CACHEDISABLED when bzrtp was not compiled with cache enabled, BZRTP_ERROR_CACHEMIGRATIONFAILED on error during migration */ int bzrtp_cache_migration(void *cacheXmlPtr, void *cacheSqlite, const char *selfURI) { #ifdef HAVE_LIBXML2 if (cacheXmlPtr) { xmlDocPtr cacheXml = (xmlDocPtr)cacheXmlPtr; xmlNodePtr cur; xmlChar *selfZidHex=NULL; uint8_t selfZID[12]; sqlite3 *db = (sqlite3 *)cacheSqlite; sqlite3_stmt *sqlStmt = NULL; int ret; /* parse the cache to get the selfZID and insert it in sqlcache */ cur = xmlDocGetRootElement(cacheXml); /* if we found a root element, parse its children node */ if (cur!=NULL) { cur = cur->xmlChildrenNode; } selfZidHex = NULL; while (cur!=NULL) { if ((!xmlStrcmp(cur->name, (const xmlChar *)"selfZID"))){ /* self ZID found, extract it */ selfZidHex = xmlNodeListGetString(cacheXml, cur->xmlChildrenNode, 1); bctbx_str_to_uint8(selfZID, selfZidHex, 24); break; } cur = cur->next; } /* did we found a self ZID? */ if (selfZidHex == NULL) { bctbx_warning("ZRTP/LIME cache migration: Failed to parse selfZID"); return BZRTP_ERROR_CACHEMIGRATIONFAILED; } /* insert the selfZID in cache, associate it to default local sip:uri in case we have more than one */ bctbx_message("ZRTP/LIME cache migration: found selfZID %.24s link it to default URI %s in SQL cache", selfZidHex, selfURI); xmlFree(selfZidHex); ret = sqlite3_prepare_v2(db, "INSERT INTO ziduri (zid,selfuri,peeruri) VALUES(?,?,?);", -1, &sqlStmt, NULL); if (ret != SQLITE_OK) { bctbx_warning("ZRTP/LIME cache migration: Failed to insert selfZID"); return BZRTP_ERROR_CACHEMIGRATIONFAILED; } sqlite3_bind_blob(sqlStmt, 1, selfZID, 12, SQLITE_TRANSIENT); sqlite3_bind_text(sqlStmt, 2, selfURI,-1,SQLITE_TRANSIENT); sqlite3_bind_text(sqlStmt, 3, "self",-1,SQLITE_TRANSIENT); ret = sqlite3_step(sqlStmt); if (ret!=SQLITE_DONE) { bctbx_warning("ZRTP/LIME cache migration: Failed to insert selfZID"); return BZRTP_ERROR_CACHEMIGRATIONFAILED; } sqlite3_finalize(sqlStmt); /* loop over all the peer node in the xml cache and get from them : uri(can be more than one), ZID, rs1, rs2, pvs, sndKey, rcvKey, sndSId, rcvSId, sndIndex, rcvIndex, valid */ /* some of these may be missing(pvs, valid, rs2) but we'll consider them NULL */ /* aux and pbx secrets were not used, so don't even bother looking for them */ cur = xmlDocGetRootElement(cacheXml)->xmlChildrenNode; while (cur!=NULL) { /* loop on all peer nodes */ if ((!xmlStrcmp(cur->name, (const xmlChar *)"peer"))) { /* found a peer node, check if there is a sipURI node in it (other nodes are just ignored) */ int i; xmlNodePtr peerNodeChildren = cur->xmlChildrenNode; xmlChar *nodeContent = NULL; xmlChar *peerZIDString = NULL; uint8_t peerZID[12]; uint8_t peerZIDFound=0; xmlChar *peerUri[128]; /* array to contain all the peer uris found in one node */ /* hopefully they won't be more than 128(it would mean some peer has more than 128 accounts and we called all of them...) */ int peerUriIndex=0; /* index of previous array */ char *zrtpColNames[] = {"rs1", "rs2", "pvs"}; uint8_t *zrtpColValues[] = {NULL, NULL, NULL}; size_t zrtpColExpectedLengths[] = {32,32,1}; size_t zrtpColLengths[] = {0,0,0}; char *limeColNames[] = {"sndKey", "rcvKey", "sndSId", "rcvSId", "sndIndex", "rcvIndex", "valid"}; uint8_t *limeColValues[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL}; size_t limeColExpectedLengths[] = {32,32,32,32,4,4,8}; size_t limeColLengths[] = {0,0,0,0,0,0,0}; /* check all the children nodes to retrieve all information we may get */ while (peerNodeChildren!=NULL && peerUriIndex<128) { if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"uri")) { /* found a peer an URI node, get the content */ peerUri[peerUriIndex] = xmlNodeListGetString(cacheXml, peerNodeChildren->xmlChildrenNode, 1); peerUriIndex++; } if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"ZID")) { peerZIDString = xmlNodeListGetString(cacheXml, peerNodeChildren->xmlChildrenNode, 1); bctbx_str_to_uint8(peerZID, peerZIDString, 24); peerZIDFound=1; } for (i=0; i<3; i++) { if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)zrtpColNames[i])) { nodeContent = xmlNodeListGetString(cacheXml, peerNodeChildren->xmlChildrenNode, 1); zrtpColValues[i] = (uint8_t *)bctbx_malloc(zrtpColExpectedLengths[i]); bctbx_str_to_uint8(zrtpColValues[i], nodeContent, 2*zrtpColExpectedLengths[i]); zrtpColLengths[i]=zrtpColExpectedLengths[i]; } } for (i=0; i<7; i++) { if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)limeColNames[i])) { nodeContent = xmlNodeListGetString(cacheXml, peerNodeChildren->xmlChildrenNode, 1); limeColValues[i] = (uint8_t *)bctbx_malloc(limeColExpectedLengths[i]); bctbx_str_to_uint8(limeColValues[i], nodeContent, 2*limeColExpectedLengths[i]); limeColLengths[i]=limeColExpectedLengths[i]; } } peerNodeChildren = peerNodeChildren->next; xmlFree(nodeContent); nodeContent=NULL; } if (peerUriIndex>0 && peerZIDFound==1) { /* we found at least an uri in this peer node, extract the keys all other informations */ /* retrieve all the informations */ /* loop over all the uri founds */ for (i=0; inext; } return 0; } return BZRTP_ERROR_CACHEMIGRATIONFAILED; #else /* HAVE_LIBXML2 */ bctbx_error("ZRTP/LIME cache migration: could not perform migration as LIBMXL2 is not linked to bzrtp."); return BZRTP_ERROR_CACHEMIGRATIONFAILED; #endif /* HAVE_LIBXML2 */ } #else /* ZIDCACHE_ENABLED */ int bzrtp_getSelfZID(void *dbPointer, const char *selfURI, uint8_t selfZID[12], bctbx_rng_context_t *RNGContext) { /* we are running cacheless, return a random number */ if (RNGContext != NULL) { bctbx_rng_get(RNGContext, selfZID, 12); } else { return BZRTP_CACHE_DATA_NOTFOUND; } return 0; } int bzrtp_getPeerAssociatedSecrets(bzrtpContext_t *context, uint8_t peerZID[12]) { if (context == NULL) { return BZRTP_ZIDCACHE_INVALID_CONTEXT; } /* resert cached secret buffer */ free(context->cachedSecret.rs1); free(context->cachedSecret.rs2); free(context->cachedSecret.pbxsecret); free(context->cachedSecret.auxsecret); context->cachedSecret.rs1 = NULL; context->cachedSecret.rs1Length = 0; context->cachedSecret.rs2 = NULL; context->cachedSecret.rs2Length = 0; context->cachedSecret.pbxsecret = NULL; context->cachedSecret.pbxsecretLength = 0; context->cachedSecret.auxsecret = NULL; context->cachedSecret.auxsecretLength = 0; context->cachedSecret.previouslyVerifiedSas = 0; return 0; } int bzrtp_cache_write(void *dbPointer, int zuid, char *tableName, char **columns, uint8_t **values, size_t *lengths, uint8_t columnsCount) { return BZRTP_ERROR_CACHEDISABLED; } int bzrtp_cache_read(void *dbPointer, int zuid, char *tableName, char **columns, uint8_t **values, size_t *lengths, uint8_t columnsCount) { return BZRTP_ERROR_CACHEDISABLED; } int bzrtp_cache_migration(xmlDocPtr cacheXml, void *cacheSqlite, const char *selfURI) { return BZRTP_ERROR_CACHEDISABLED; } #endif /* ZIDCACHE_ENABLED */ bzrtp-1.0.6/test/000077500000000000000000000000001313411235300136325ustar00rootroot00000000000000bzrtp-1.0.6/test/CMakeLists.txt000066400000000000000000000037261313411235300164020ustar00rootroot00000000000000############################################################################ # CMakeLists.txt # Copyright (C) 2014 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################################################ set(TEST_SOURCES bzrtpCryptoTest.c bzrtpParserTest.c bzrtpConfigsTest.c bzrtpZidCacheTest.c bzrtpTest.c testUtils.c ) bc_apply_compile_flags(TEST_SOURCES STRICT_OPTIONS_CPP) add_executable(bzrtpTest ${TEST_SOURCES}) set_target_properties(bzrtpTest PROPERTIES LINK_FLAGS "${LINK_FLAGS}") set_target_properties(bzrtpTest PROPERTIES LINKER_LANGUAGE CXX) target_include_directories(bzrtpTest PUBLIC ${BCTOOLBOX_TESTER_INCLUDE_DIR}) if(ENABLE_STATIC) target_link_libraries(bzrtpTest bzrtp-static) else() target_link_libraries(bzrtpTest bzrtp) endif() target_link_libraries(bzrtpTest ${BCTOOLBOX_LIBRARIES}) if(SQLITE3_FOUND) target_include_directories(bzrtpTest PUBLIC ${SQLITE3_INCLUDE_DIRS}) target_link_libraries(bzrtpTest ${SQLITE3_LIBRARIES}) if(XML2_FOUND) target_link_libraries(bzrtpTest ${XML2_LIBRARIES}) endif() endif() if(HAVE_SQRT) target_link_libraries(bzrtpTest m) endif() unset(PATTERN_FILES_IN_TEST_DIR CACHE) add_test(NAME bzrtpTest COMMAND bzrtpTest) bzrtp-1.0.6/test/Makefile.am000066400000000000000000000007711313411235300156730ustar00rootroot00000000000000if ENABLE_TESTS noinst_PROGRAMS=bzrtpTest bzrtpTest_SOURCES=bzrtpTest.c \ testUtils.c testUtils.h \ bzrtpCryptoTest.c bzrtpCryptoTest.h \ bzrtpParserTest.c bzrtpParserTest.h\ bzrtpConfigsTest.c \ bzrtpZidCacheTest.c bzrtpTest_CFLAGS=$(BCTOOLBOXTESTER_CFLAGS) $(LIBXML2_CFLAGS) bzrtpTest_LDADD=$(top_builddir)/src/libbzrtp.la $(BCTOOLBOX_LIBS) $(BCTOOLBOXTESTER_LIBS) $(SQLITE3_LIBS) $(LIBXML2_LIBS) -lm AM_CPPFLAGS=-I$(top_srcdir)/include test: bzrtpTest ./bzrtpTest endif bzrtp-1.0.6/test/bzrtpConfigsTest.c000066400000000000000000001217741313411235300173240ustar00rootroot00000000000000/** @file bzrtpConfigsTests.c @brief Test complete ZRTP key agreement under differents configurations. @author Johan Pascal @copyright Copyright (C) 2017 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include "bzrtp/bzrtp.h" #include #include "testUtils.h" #define MAX_PACKET_LENGTH 1000 #define MAX_QUEUE_SIZE 10 #define MAX_CRYPTO_ALG 10 #define MAX_NUM_CHANNEL ZRTP_MAX_CHANNEL_NUMBER typedef struct packetDatas_struct { uint8_t packetString[MAX_PACKET_LENGTH]; uint16_t packetLength; } packetDatas_t; typedef struct clientContext_struct { uint8_t id; bzrtpContext_t *bzrtpContext; bzrtpSrtpSecrets_t *secrets; int32_t pvs; uint8_t haveCacheMismatch; uint8_t sendExportedKey[16]; uint8_t recvExportedKey[16]; } clientContext_t; typedef struct cryptoParams_struct { uint8_t cipher[MAX_CRYPTO_ALG] ; uint8_t cipherNb; uint8_t hash[MAX_CRYPTO_ALG] ; uint8_t hashNb; uint8_t keyAgreement[MAX_CRYPTO_ALG] ; uint8_t keyAgreementNb; uint8_t sas[MAX_CRYPTO_ALG] ; uint8_t sasNb; uint8_t authtag[MAX_CRYPTO_ALG] ; uint8_t authtagNb; uint8_t dontValidateSASflag; /**< if set, SAS will not be validated even if matching peer **/ } cryptoParams_t; /* Global vars: message queues for Alice and Bob */ static packetDatas_t aliceQueue[MAX_QUEUE_SIZE]; static packetDatas_t bobQueue[MAX_QUEUE_SIZE]; static uint8_t aliceQueueIndex = 0; static uint8_t bobQueueIndex = 0; /* have ids to represent Alice and Bob */ #define ALICE 0x1 #define BOB 0x2 #define ALICE_SSRC_BASE 0x12345000 #define BOB_SSRC_BASE 0x87654000 static cryptoParams_t defaultCryptoAlgoSelection = {{ZRTP_CIPHER_AES1},1,{ZRTP_HASH_S256},1,{ZRTP_KEYAGREEMENT_DH3k},1,{ZRTP_SAS_B32},1,{ZRTP_AUTHTAG_HS32},1,0}; static cryptoParams_t defaultCryptoAlgoSelectionNoSASValidation = {{ZRTP_CIPHER_AES1},1,{ZRTP_HASH_S256},1,{ZRTP_KEYAGREEMENT_DH3k},1,{ZRTP_SAS_B32},1,{ZRTP_AUTHTAG_HS32},1,1}; /* static global settings and their reset function */ static uint64_t msSTC = 0; /* Simulation Time Coordinated start at 0 and increment it at each sleep, is in milliseconds */ static int loosePacketPercentage=0; /* simulate bd network condition: loose packet */ static uint64_t timeOutLimit=1000; /* in ms, time span given to perform the ZRTP exchange */ static float fadingLostAlice=0.0; /* try not to throw away too many packet in a row */ static float fadingLostBob=0.0; /* try not to throw away too many packet in a row */ static int totalPacketLost=0; /* set a limit to the total number of packet we can loose to enforce completion of the exchange */ static void resetGlobalParams() { msSTC=0; totalPacketLost =0; loosePacketPercentage=0; timeOutLimit = 1000; fadingLostBob=0; fadingLostAlice=0; } /* time functions, we do not run a real time scenario, go for fast test instead */ static uint64_t getSimulatedTime() { return msSTC; } static void STC_sleep(int ms){ msSTC +=ms; } /* routing messages */ static int sendData(void *clientData, const uint8_t *packetString, uint16_t packetLength) { /* get the client context */ clientContext_t *clientContext = (clientContext_t *)clientData; /* manage loosy network simulation */ if (loosePacketPercentage > 0) { /* make sure we cannot loose 10 packets in a row from the same sender */ if ((totalPacketLost<10) && ((float)((rand()%100 )) < loosePacketPercentage-((clientContext->id == ALICE)?fadingLostAlice:fadingLostBob))) { /* randomly discard packets */ //bzrtp_message("%d Loose %.8s from %s - LC %d\n", msSTC, packetString+16, (clientContext->id==ALICE?"Alice":"Bob"), totalPacketLost); if (clientContext->id == ALICE) { fadingLostAlice +=loosePacketPercentage/8; } else { fadingLostBob +=loosePacketPercentage/8; } return 0; } //bzrtp_message("%d Keep %.8s from %s - LC %d\n", msSTC, packetString+16, (clientContext->id==ALICE?"Alice":"Bob"), totalPacketLost); } /* put the message in the message correct queue */ if (clientContext->id == ALICE) { /* message sent by Alice, so put it in Bob's queue */ fadingLostAlice = MAX(0,fadingLostAlice-loosePacketPercentage/2); memcpy(bobQueue[bobQueueIndex].packetString, packetString, packetLength); bobQueue[bobQueueIndex++].packetLength = packetLength; } else { /* Bob sent the message, put it in Alice's queue */ fadingLostBob = MAX(0,fadingLostBob-loosePacketPercentage/2); memcpy(bobQueue[bobQueueIndex].packetString, packetString, packetLength); memcpy(aliceQueue[aliceQueueIndex].packetString, packetString, packetLength); aliceQueue[aliceQueueIndex++].packetLength = packetLength; } return 0; } /* get SAS and SRTP keys */ int getSAS(void *clientData, bzrtpSrtpSecrets_t *secrets, int32_t pvs) { /* get the client context */ clientContext_t *clientContext = (clientContext_t *)clientData; /* store the secret struct */ clientContext->secrets = secrets; /* and the PVS flag */ clientContext->pvs = pvs; return 0; } int getMessage(void *clientData, const uint8_t level, const uint8_t message, const char *messageString) { /* get the client context */ clientContext_t *clientContext = (clientContext_t *)clientData; if (level == BZRTP_MESSAGE_ERROR && message == BZRTP_MESSAGE_CACHEMISMATCH) { clientContext->haveCacheMismatch = 1; } return 0; } int computeExportedKeys(void *clientData, int zuid, uint8_t role) { size_t keyLength = 16; /* get the client context */ clientContext_t *clientContext = (clientContext_t *)clientData; /* compute 2 exported keys with label initiator and responder */ BC_ASSERT_EQUAL(bzrtp_exportKey(clientContext->bzrtpContext, ((role==BZRTP_ROLE_RESPONDER)?"ResponderKey":"InitiatorKey"), 12, clientContext->sendExportedKey, &keyLength), 0, int, "%x"); BC_ASSERT_EQUAL(keyLength, 16, int, "%d"); /* any hash available in the config shall be able to produce a 16 bytes key */ keyLength = 16; BC_ASSERT_EQUAL(bzrtp_exportKey(clientContext->bzrtpContext, ((role==BZRTP_ROLE_INITIATOR)?"ResponderKey":"InitiatorKey"), 12, clientContext->recvExportedKey, &keyLength), 0, int, "%x"); BC_ASSERT_EQUAL(keyLength, 16, int, "%d"); /* any hash available in the config shall be able to produce a 16 bytes key */ return 0; } static int setUpClientContext(clientContext_t *clientContext, uint8_t clientID, uint32_t SSRC, void *zidCache, char *selfURI, char *peerURI, cryptoParams_t *cryptoParams) { int retval; bzrtpCallbacks_t cbs={0} ; /* set Id */ clientContext->id = clientID; clientContext->pvs=0; clientContext->haveCacheMismatch=0; /* create zrtp context */ clientContext->bzrtpContext = bzrtp_createBzrtpContext(); if (clientContext->bzrtpContext==NULL) { bzrtp_message("ERROR: can't create bzrtp context, id client is %d", clientID); return -1; } /* check cache */ if (zidCache != NULL) { #ifdef ZIDCACHE_ENABLED retval = bzrtp_setZIDCache(clientContext->bzrtpContext, zidCache, selfURI, peerURI); if (retval != 0 && retval != BZRTP_CACHE_SETUP) { /* return value is BZRTP_CACHE_SETUP if the cache is populated by this call */ bzrtp_message("ERROR: bzrtp_setZIDCache %0x, client id is %d\n", retval, clientID); return -2; } #else bzrtp_message("ERROR: asking for cache but not enabled at compile time\n"); return -2; #endif } /* assign callbacks */ cbs.bzrtp_sendData=sendData; cbs.bzrtp_startSrtpSession=(int (*)(void *,const bzrtpSrtpSecrets_t *,int32_t) )getSAS; cbs.bzrtp_statusMessage=getMessage; cbs.bzrtp_messageLevel = BZRTP_MESSAGE_ERROR; cbs.bzrtp_contextReadyForExportedKeys = computeExportedKeys; if ((retval = bzrtp_setCallbacks(clientContext->bzrtpContext, &cbs))!=0) { bzrtp_message("ERROR: bzrtp_setCallbacks returned %0x, client id is %d\n", retval, clientID); return -3; } /* set crypto params */ if (cryptoParams != NULL) { bzrtp_setSupportedCryptoTypes(clientContext->bzrtpContext, ZRTP_HASH_TYPE, cryptoParams->hash, cryptoParams->hashNb); bzrtp_setSupportedCryptoTypes(clientContext->bzrtpContext, ZRTP_CIPHERBLOCK_TYPE, cryptoParams->cipher, cryptoParams->cipherNb); bzrtp_setSupportedCryptoTypes(clientContext->bzrtpContext, ZRTP_KEYAGREEMENT_TYPE, cryptoParams->keyAgreement, cryptoParams->keyAgreementNb); bzrtp_setSupportedCryptoTypes(clientContext->bzrtpContext, ZRTP_AUTHTAG_TYPE, cryptoParams->authtag, cryptoParams->authtagNb); bzrtp_setSupportedCryptoTypes(clientContext->bzrtpContext, ZRTP_SAS_TYPE, cryptoParams->sas, cryptoParams->sasNb); } /* init the first channel */ bzrtp_initBzrtpContext(clientContext->bzrtpContext, SSRC); if ((retval = bzrtp_setClientData(clientContext->bzrtpContext, SSRC, (void *)clientContext))!=0) { bzrtp_message("ERROR: bzrtp_setClientData returned %0x, client id is %d\n", retval, clientID); return -4; } /* start the ZRTP engine(it will send a hello packet )*/ if ((retval = bzrtp_startChannelEngine(clientContext->bzrtpContext, SSRC))!=0) { bzrtp_message("ERROR: bzrtp_startChannelEngine returned %0x, client id is %d SSRC is %d\n", retval, clientID, SSRC); return -5; } return 0; } static int addChannel(clientContext_t *clientContext, uint32_t SSRC) { int retval=0; /* add channel */ if ((retval = bzrtp_addChannel(clientContext->bzrtpContext, SSRC))!=0) { bzrtp_message("ERROR: bzrtp_addChannel returned %0x, client id is %d\n", retval, clientContext->id); return -1; } /* associated client data(give the same than for first channel) */ if ((retval = bzrtp_setClientData(clientContext->bzrtpContext, SSRC, (void *)clientContext))!=0) { bzrtp_message("ERROR: bzrtp_setClientData on secondary channel returned %0x, client id is %d\n", retval, clientContext->id); return -2; } /* start the channel */ if ((retval = bzrtp_startChannelEngine(clientContext->bzrtpContext, SSRC))!=0) { bzrtp_message("ERROR: bzrtp_startChannelEngine on secondary channel returned %0x, client id is %d SSRC is %d\n", retval, clientContext->id,SSRC); return -3; } return 0; } /* are all a and b field the same? Check Sas(optionnaly as it is not provided for secondary channel) and srtp keys and choosen algo*/ static int compareSecrets(bzrtpSrtpSecrets_t *a, bzrtpSrtpSecrets_t* b, uint8_t mainChannel) { if (mainChannel==TRUE) { if (strcmp(a->sas,b->sas)!=0) { return -1; } } if (mainChannel == TRUE) { if ((a->authTagAlgo!=b->authTagAlgo) || a->hashAlgo!=b->hashAlgo || a->keyAgreementAlgo!=b->keyAgreementAlgo || a->sasAlgo!=b->sasAlgo || a->cipherAlgo!=b->cipherAlgo) { return -2; } } else { if ((a->authTagAlgo!=b->authTagAlgo) || a->hashAlgo!=b->hashAlgo || a->keyAgreementAlgo!=b->keyAgreementAlgo || a->cipherAlgo!=b->cipherAlgo) { return -2; } } if (a->selfSrtpKeyLength==0 || b->selfSrtpKeyLength==0 || a->selfSrtpSaltLength==0 || b->selfSrtpSaltLength==0 || a->peerSrtpKeyLength==0 || b->peerSrtpKeyLength==0 || a->peerSrtpSaltLength==0 || b->peerSrtpSaltLength==0) { return -3; } if (a->selfSrtpKeyLength != b->peerSrtpKeyLength || a->selfSrtpSaltLength != b->peerSrtpSaltLength || a->peerSrtpKeyLength != b->selfSrtpKeyLength || a->peerSrtpSaltLength != b->selfSrtpSaltLength) { return -4; } if (memcmp (a->selfSrtpKey, b->peerSrtpKey, b->peerSrtpKeyLength) != 0 || memcmp (a->selfSrtpSalt, b->peerSrtpSalt, b->peerSrtpSaltLength) != 0 || memcmp (a->peerSrtpKey, b->selfSrtpKey, b->selfSrtpKeyLength) != 0 || memcmp (a->peerSrtpSalt, b->selfSrtpSalt, b->selfSrtpSaltLength) != 0) { return -5; } return 0; } /* compare algo sets */ static int compareAlgoList(bzrtpSrtpSecrets_t *secrets, cryptoParams_t *cryptoParams) { if (secrets->authTagAlgo != cryptoParams->authtag[0]) return -1; if (secrets->hashAlgo != cryptoParams->hash[0]) return -2; if (secrets->cipherAlgo != cryptoParams->cipher[0]) return -3; if (secrets->keyAgreementAlgo != cryptoParams->keyAgreement[0]) return -4; if (secrets->sasAlgo != cryptoParams->sas[0]) return -5; return 0; } /* defines return values bit flags(on 16 bits, use 32 to return status for Bob(16 MSB) and Alice(16 LSB)) */ #define RET_CACHE_MISMATCH 0x0001 uint32_t multichannel_exchange_pvs_params(cryptoParams_t *aliceCryptoParams, cryptoParams_t *bobCryptoParams, cryptoParams_t *expectedCryptoParams, void *aliceCache, char *aliceURI, void *bobCache, char *bobURI, uint8_t checkPVS, uint8_t expectedAlicePVS, uint8_t expectedBobPVS) { int retval,channelNumber; clientContext_t Alice,Bob; uint64_t initialTime=0; uint64_t lastPacketSentTime=0; uint32_t aliceSSRC = ALICE_SSRC_BASE; uint32_t bobSSRC = BOB_SSRC_BASE; uint32_t ret=0; /*** Create the main channel */ if ((retval=setUpClientContext(&Alice, ALICE, aliceSSRC, aliceCache, aliceURI, bobURI, aliceCryptoParams))!=0) { bzrtp_message("ERROR: can't init setup client context id %d\n", ALICE); BC_ASSERT_EQUAL(retval, 0, uint32_t, "0x%08x"); return retval; } if ((retval=setUpClientContext(&Bob, BOB, bobSSRC, bobCache, bobURI, aliceURI, bobCryptoParams))!=0) { bzrtp_message("ERROR: can't init setup client context id %d\n", BOB); BC_ASSERT_EQUAL(retval, 0, uint32_t, "0x%08x"); return retval; } initialTime = getSimulatedTime(); while ((bzrtp_getChannelStatus(Alice.bzrtpContext, aliceSSRC)!= BZRTP_CHANNEL_SECURE || bzrtp_getChannelStatus(Bob.bzrtpContext, bobSSRC)!= BZRTP_CHANNEL_SECURE) && (getSimulatedTime()-initialTime 1250 ) { /*higher re-emission timeout is 1200ms */ retval = bzrtp_resetRetransmissionTimer(Alice.bzrtpContext, aliceSSRC); retval +=bzrtp_resetRetransmissionTimer(Bob.bzrtpContext, bobSSRC); lastPacketSentTime=getSimulatedTime(); } } if ((retval=bzrtp_getChannelStatus(Alice.bzrtpContext, aliceSSRC))!=BZRTP_CHANNEL_SECURE) { bzrtp_message("Fail Alice on channel1 loss rate is %d", loosePacketPercentage); BC_ASSERT_EQUAL(retval, BZRTP_CHANNEL_SECURE, int, "%0x"); return retval; } if ((retval=bzrtp_getChannelStatus(Bob.bzrtpContext, bobSSRC))!=BZRTP_CHANNEL_SECURE) { bzrtp_message("Fail Bob on channel1 loss rate is %d", loosePacketPercentage); BC_ASSERT_EQUAL(retval, BZRTP_CHANNEL_SECURE, int, "%0x"); return retval; } bzrtp_message("ZRTP algo used during negotiation: Cipher: %s - KeyAgreement: %s - Hash: %s - AuthTag: %s - Sas Rendering: %s\n", bzrtp_cipher_toString(Alice.secrets->cipherAlgo), bzrtp_keyAgreement_toString(Alice.secrets->keyAgreementAlgo), bzrtp_hash_toString(Alice.secrets->hashAlgo), bzrtp_authtag_toString(Alice.secrets->authTagAlgo), bzrtp_sas_toString(Alice.secrets->sasAlgo)); if ((retval=compareSecrets(Alice.secrets, Bob.secrets, TRUE))!=0) { BC_ASSERT_EQUAL(retval, 0, int, "%d"); return retval; } else { /* SAS comparison is Ok, if we have a cache, confirm it */ if (aliceCache != NULL && bobCache != NULL) { if (aliceCryptoParams==NULL || aliceCryptoParams->dontValidateSASflag == 0) { bzrtp_SASVerified(Alice.bzrtpContext); } if (bobCryptoParams==NULL || bobCryptoParams->dontValidateSASflag == 0) { bzrtp_SASVerified(Bob.bzrtpContext); } } } /* shall we check the PVS returned by the SAS callback? */ if (checkPVS==TRUE) { BC_ASSERT_EQUAL(Alice.pvs, expectedAlicePVS, int, "%d"); BC_ASSERT_EQUAL(Bob.pvs, expectedBobPVS, int, "%d"); } /* if we have expected crypto param, check our result */ if (expectedCryptoParams!=NULL) { BC_ASSERT_EQUAL(compareAlgoList(Alice.secrets,expectedCryptoParams), 0, int, "%d"); } /* check exported keys */ BC_ASSERT_EQUAL(memcmp(Alice.sendExportedKey, Bob.recvExportedKey, 16), 0, int, "%d"); BC_ASSERT_EQUAL(memcmp(Alice.recvExportedKey, Bob.sendExportedKey, 16), 0, int, "%d"); /* open as much channels as we can */ for (channelNumber=2; channelNumber<=MAX_NUM_CHANNEL; channelNumber++) { /* increase SSRCs as they are used to identify a channel */ aliceSSRC++; bobSSRC++; /* start a new channel */ if ((retval=addChannel(&Alice, aliceSSRC))!=0) { bzrtp_message("ERROR: can't add a second channel to client context id %d\n", ALICE); BC_ASSERT_EQUAL(retval, 0, uint32_t, "0x%08x"); return retval; } if ((retval=addChannel(&Bob, bobSSRC))!=0) { bzrtp_message("ERROR: can't add a second channel to client context id %d\n", ALICE); BC_ASSERT_EQUAL(retval, 0, uint32_t, "0x%08x"); return retval; } initialTime = getSimulatedTime(); while ((bzrtp_getChannelStatus(Alice.bzrtpContext, aliceSSRC)!= BZRTP_CHANNEL_SECURE || bzrtp_getChannelStatus(Bob.bzrtpContext, bobSSRC)!= BZRTP_CHANNEL_SECURE) && (getSimulatedTime()-initialTime 1250 ) { /*higher re-emission timeout is 1200ms */ retval = bzrtp_resetRetransmissionTimer(Alice.bzrtpContext, aliceSSRC); retval += bzrtp_resetRetransmissionTimer(Bob.bzrtpContext, bobSSRC); lastPacketSentTime=getSimulatedTime(); } } if ((retval=bzrtp_getChannelStatus(Alice.bzrtpContext, aliceSSRC))!=BZRTP_CHANNEL_SECURE) { bzrtp_message("Fail Alice on channel2 loss rate is %d", loosePacketPercentage); BC_ASSERT_EQUAL(retval, BZRTP_CHANNEL_SECURE, int, "%0x"); return retval; } if ((retval=bzrtp_getChannelStatus(Bob.bzrtpContext, bobSSRC))!=BZRTP_CHANNEL_SECURE) { bzrtp_message("Fail Bob on channel2 loss rate is %d", loosePacketPercentage); BC_ASSERT_EQUAL(retval, BZRTP_CHANNEL_SECURE, int, "%0x"); return retval; } bzrtp_message("Channel %d :ZRTP algo used during negotiation: Cipher: %s - KeyAgreement: %s - Hash: %s - AuthTag: %s - Sas Rendering: %s\n", channelNumber, bzrtp_cipher_toString(Alice.secrets->cipherAlgo), bzrtp_keyAgreement_toString(Alice.secrets->keyAgreementAlgo), bzrtp_hash_toString(Alice.secrets->hashAlgo), bzrtp_authtag_toString(Alice.secrets->authTagAlgo), bzrtp_sas_toString(Alice.secrets->sasAlgo)); if ((retval=compareSecrets(Alice.secrets, Bob.secrets, FALSE))!=0) { BC_ASSERT_EQUAL(retval, 0, int, "%d"); } } /*** Destroy Contexts ***/ while (bzrtp_destroyBzrtpContext(Alice.bzrtpContext, aliceSSRC)>0 && aliceSSRC>=ALICE_SSRC_BASE) { aliceSSRC--; } while (bzrtp_destroyBzrtpContext(Bob.bzrtpContext, bobSSRC)>0 && bobSSRC>=BOB_SSRC_BASE) { bobSSRC--; } /** Compute return value **/ if (Alice.haveCacheMismatch==1) { ret |= RET_CACHE_MISMATCH; } if (Bob.haveCacheMismatch==1) { ret |= RET_CACHE_MISMATCH<<16; } return ret; } uint32_t multichannel_exchange(cryptoParams_t *aliceCryptoParams, cryptoParams_t *bobCryptoParams, cryptoParams_t *expectedCryptoParams, void *aliceCache, char *aliceURI, void *bobCache, char *bobURI) { return multichannel_exchange_pvs_params(aliceCryptoParams, bobCryptoParams, expectedCryptoParams, aliceCache, aliceURI, bobCache, bobURI, FALSE, 0, 0); } void test_cacheless_exchange(void) { cryptoParams_t *pattern; /* Reset Global Static settings */ resetGlobalParams(); /* Note: common algo selection is not tested here(this is done in some cryptoUtils tests) here we just perform an exchange with any final configuration avalaible and check it goes well */ cryptoParams_t patterns[] = { {{ZRTP_CIPHER_AES1},1,{ZRTP_HASH_S256},1,{ZRTP_KEYAGREEMENT_DH3k},1,{ZRTP_SAS_B32},1,{ZRTP_AUTHTAG_HS32},1,0}, {{ZRTP_CIPHER_AES1},1,{ZRTP_HASH_S256},1,{ZRTP_KEYAGREEMENT_DH3k},1,{ZRTP_SAS_B32},1,{ZRTP_AUTHTAG_HS80},1,0}, {{ZRTP_CIPHER_AES1},1,{ZRTP_HASH_S256},1,{ZRTP_KEYAGREEMENT_DH3k},1,{ZRTP_SAS_B256},1,{ZRTP_AUTHTAG_HS32},1,0}, {{ZRTP_CIPHER_AES1},1,{ZRTP_HASH_S256},1,{ZRTP_KEYAGREEMENT_DH3k},1,{ZRTP_SAS_B256},1,{ZRTP_AUTHTAG_HS80},1,0}, {{ZRTP_CIPHER_AES1},1,{ZRTP_HASH_S256},1,{ZRTP_KEYAGREEMENT_DH2k},1,{ZRTP_SAS_B32},1,{ZRTP_AUTHTAG_HS32},1,0}, {{ZRTP_CIPHER_AES1},1,{ZRTP_HASH_S256},1,{ZRTP_KEYAGREEMENT_DH2k},1,{ZRTP_SAS_B32},1,{ZRTP_AUTHTAG_HS80},1,0}, {{ZRTP_CIPHER_AES1},1,{ZRTP_HASH_S256},1,{ZRTP_KEYAGREEMENT_DH2k},1,{ZRTP_SAS_B256},1,{ZRTP_AUTHTAG_HS32},1,0}, {{ZRTP_CIPHER_AES1},1,{ZRTP_HASH_S256},1,{ZRTP_KEYAGREEMENT_DH2k},1,{ZRTP_SAS_B256},1,{ZRTP_AUTHTAG_HS80},1,0}, {{ZRTP_CIPHER_AES3},1,{ZRTP_HASH_S256},1,{ZRTP_KEYAGREEMENT_DH3k},1,{ZRTP_SAS_B32},1,{ZRTP_AUTHTAG_HS32},1,0}, {{ZRTP_CIPHER_AES3},1,{ZRTP_HASH_S256},1,{ZRTP_KEYAGREEMENT_DH3k},1,{ZRTP_SAS_B32},1,{ZRTP_AUTHTAG_HS80},1,0}, {{ZRTP_CIPHER_AES3},1,{ZRTP_HASH_S256},1,{ZRTP_KEYAGREEMENT_DH3k},1,{ZRTP_SAS_B256},1,{ZRTP_AUTHTAG_HS32},1,0}, {{ZRTP_CIPHER_AES3},1,{ZRTP_HASH_S256},1,{ZRTP_KEYAGREEMENT_DH3k},1,{ZRTP_SAS_B256},1,{ZRTP_AUTHTAG_HS80},1,0}, {{ZRTP_CIPHER_AES3},1,{ZRTP_HASH_S256},1,{ZRTP_KEYAGREEMENT_DH2k},1,{ZRTP_SAS_B32},1,{ZRTP_AUTHTAG_HS32},1,0}, {{ZRTP_CIPHER_AES3},1,{ZRTP_HASH_S256},1,{ZRTP_KEYAGREEMENT_DH2k},1,{ZRTP_SAS_B32},1,{ZRTP_AUTHTAG_HS80},1,0}, {{ZRTP_CIPHER_AES3},1,{ZRTP_HASH_S256},1,{ZRTP_KEYAGREEMENT_DH2k},1,{ZRTP_SAS_B256},1,{ZRTP_AUTHTAG_HS32},1,0}, {{ZRTP_CIPHER_AES3},1,{ZRTP_HASH_S256},1,{ZRTP_KEYAGREEMENT_DH2k},1,{ZRTP_SAS_B256},1,{ZRTP_AUTHTAG_HS80},1,0}, {{0},0,{0},0,{0},0,{0},0,{0},0,0}, /* this pattern will end the run because cipher nb is 0 */ }; pattern = &patterns[0]; /* pattern is a pointer to current pattern */ while (pattern->cipherNb!=0) { BC_ASSERT_EQUAL(multichannel_exchange(pattern, pattern, pattern, NULL, NULL, NULL, NULL), 0, int, "%x"); pattern++; /* point to next row in the array of patterns */ } BC_ASSERT_EQUAL(multichannel_exchange(NULL, NULL, &defaultCryptoAlgoSelection, NULL, NULL, NULL, NULL), 0, int, "%x"); } void test_loosy_network(void) { int i,j; resetGlobalParams(); srand((unsigned int)time(NULL)); /* run through all the configs 10 times to maximise chance to spot a random error based on a specific packet lost sequence */ for (j=0; j<10; j++) { for (i=1; i<60; i+=1) { resetGlobalParams(); timeOutLimit =100000; //outrageous time limit just to be sure to complete, not run in real time anyway loosePacketPercentage=i; BC_ASSERT_EQUAL(multichannel_exchange(NULL, NULL, &defaultCryptoAlgoSelection, NULL, NULL, NULL, NULL), 0, int, "%x"); } } } void test_cache_enabled_exchange(void) { #ifdef ZIDCACHE_ENABLED sqlite3 *aliceDB=NULL; sqlite3 *bobDB=NULL; uint8_t selfZIDalice[12]; uint8_t selfZIDbob[12]; int zuidAlice=0,zuidBob=0; char *colNames[] = {"rs1", "rs2", "pvs"}; uint8_t *colValuesAlice[3]; size_t colLengthAlice[3]; uint8_t *colValuesBob[3]; size_t colLengthBob[3]; int i; /* create tempory DB files, just try to clean them from dir before, just in case */ remove("tmpZIDAlice_simpleCache.sqlite"); remove("tmpZIDBob_simpleCache.sqlite"); bzrtptester_sqlite3_open(bc_tester_file("tmpZIDAlice_simpleCache.sqlite"), &aliceDB); bzrtptester_sqlite3_open(bc_tester_file("tmpZIDBob_simpleCache.sqlite"), &bobDB); /* make a first exchange */ BC_ASSERT_EQUAL(multichannel_exchange(NULL, NULL, &defaultCryptoAlgoSelection, aliceDB, "alice@sip.linphone.org", bobDB, "bob@sip.linphone.org"), 0, int, "%x"); /* after the first exchange we shall have both pvs values at 1 and both rs1 identical and rs2 null, retrieve them from cache and check it */ /* first get each ZIDs, note give NULL as RNG context may lead to segfault in case of error(caches were not created correctly)*/ BC_ASSERT_EQUAL(bzrtp_getSelfZID((void *)aliceDB, "alice@sip.linphone.org", selfZIDalice, NULL), 0, int, "%x"); BC_ASSERT_EQUAL(bzrtp_getSelfZID((void *)bobDB, "bob@sip.linphone.org", selfZIDbob, NULL), 0, int, "%x"); /* then get the matching zuid in cache */ BC_ASSERT_EQUAL(bzrtp_cache_getZuid((void *)aliceDB, "alice@sip.linphone.org", "bob@sip.linphone.org", selfZIDbob, &zuidAlice), 0, int, "%x"); BC_ASSERT_EQUAL(bzrtp_cache_getZuid((void *)bobDB, "bob@sip.linphone.org", "alice@sip.linphone.org", selfZIDalice, &zuidBob), 0, int, "%x"); /* retrieve the values */ BC_ASSERT_EQUAL(bzrtp_cache_read((void *)aliceDB, zuidAlice, "zrtp", colNames, colValuesAlice, colLengthAlice, 3), 0, int, "%x"); BC_ASSERT_EQUAL(bzrtp_cache_read((void *)bobDB, zuidBob, "zrtp", colNames, colValuesBob, colLengthBob, 3), 0, int, "%x"); /* and compare to expected */ /* rs1 is set and they are both the same */ BC_ASSERT_EQUAL(colLengthAlice[0], 32, int, "%d"); BC_ASSERT_EQUAL(colLengthBob[0], 32, int, "%d"); BC_ASSERT_EQUAL(memcmp(colValuesAlice[0], colValuesBob[0], 32), 0, int, "%d"); /* rs2 is unset(NULL) */ BC_ASSERT_EQUAL(colLengthAlice[1], 0, int, "%d"); BC_ASSERT_EQUAL(colLengthBob[1], 0, int, "%d"); BC_ASSERT_PTR_NULL(colValuesAlice[1]); BC_ASSERT_PTR_NULL(colValuesBob[1]); /* pvs is equal to 1 */ BC_ASSERT_EQUAL(colLengthAlice[2], 1, int, "%d"); BC_ASSERT_EQUAL(colLengthBob[2], 1, int, "%d"); BC_ASSERT_EQUAL(*colValuesAlice[2], 1, int, "%d"); BC_ASSERT_EQUAL(*colValuesBob[2], 1, int, "%d"); /* make a second exchange */ BC_ASSERT_EQUAL(multichannel_exchange(NULL, NULL, &defaultCryptoAlgoSelection, aliceDB, "alice@sip.linphone.org", bobDB, "bob@sip.linphone.org"), 0, int, "%x"); /* read new values in cache, ZIDs and zuids must be identical, read alice first to be able to check rs2 with old rs1 */ BC_ASSERT_EQUAL(bzrtp_cache_read((void *)aliceDB, zuidAlice, "zrtp", colNames, colValuesAlice, colLengthAlice, 3), 0, int, "%x"); /* check what is now rs2 is the old rs1 */ BC_ASSERT_EQUAL(colLengthAlice[0], 32, int, "%d"); BC_ASSERT_EQUAL(colLengthAlice[1], 32, int, "%d"); BC_ASSERT_EQUAL(colLengthAlice[2], 1, int, "%d"); BC_ASSERT_EQUAL(memcmp(colValuesAlice[1], colValuesBob[0], 32), 0, int, "%d"); /* colValuesBob, still old values from before the second exchange */ /* so read bob updated values and compare rs1, rs2 and check pvs is still at 1 */ BC_ASSERT_EQUAL(bzrtp_cache_read((void *)bobDB, zuidBob, "zrtp", colNames, colValuesBob, colLengthBob, 3), 0, int, "%x"); BC_ASSERT_EQUAL(colLengthBob[0], 32, int, "%d"); BC_ASSERT_EQUAL(colLengthBob[1], 32, int, "%d"); BC_ASSERT_EQUAL(colLengthBob[2], 1, int, "%d"); BC_ASSERT_EQUAL(memcmp(colValuesAlice[0], colValuesBob[0], 32), 0, int, "%d"); BC_ASSERT_EQUAL(memcmp(colValuesAlice[1], colValuesBob[1], 32), 0, int, "%d"); BC_ASSERT_EQUAL(*colValuesAlice[2], 1, int, "%d"); BC_ASSERT_EQUAL(*colValuesBob[2], 1, int, "%d"); /* free buffers */ for (i=0; i<3; i++) { free(colValuesAlice[i]); free(colValuesBob[i]); } sqlite3_close(aliceDB); sqlite3_close(bobDB); /* clean temporary files */ remove("tmpZIDAlice_simpleCache.sqlite"); remove("tmpZIDBob_simpleCache.sqlite"); #endif /* ZIDCACHE_ENABLED */ } /* first perform an exchange to establish a correct shared cache, then modify one of them and perform an other exchange to check we have a cache mismatch warning */ void test_cache_mismatch_exchange(void) { #ifdef ZIDCACHE_ENABLED sqlite3 *aliceDB=NULL; sqlite3 *bobDB=NULL; uint8_t selfZIDalice[12]; uint8_t selfZIDbob[12]; int zuidAlice=0,zuidBob=0; char *colNames[] = {"rs1", "rs2", "pvs"}; uint8_t *colValuesAlice[3]; size_t colLengthAlice[3]; uint8_t *colValuesBob[3]; size_t colLengthBob[3]; int i; /* create tempory DB files, just try to clean them from dir before, just in case */ remove("tmpZIDAlice_cacheMismtach.sqlite"); remove("tmpZIDBob_cacheMismatch.sqlite"); bzrtptester_sqlite3_open(bc_tester_file("tmpZIDAlice_cacheMismatch.sqlite"), &aliceDB); bzrtptester_sqlite3_open(bc_tester_file("tmpZIDBob_cacheMismatch.sqlite"), &bobDB); /* make a first exchange */ BC_ASSERT_EQUAL(multichannel_exchange(NULL, NULL, &defaultCryptoAlgoSelection, aliceDB, "alice@sip.linphone.org", bobDB, "bob@sip.linphone.org"), 0, int, "%x"); /* after the first exchange we shall have both pvs values at 1 and both rs1 identical and rs2 null, retrieve them from cache and check it */ /* first get each ZIDs, note give NULL as RNG context may lead to segfault in case of error(caches were not created correctly)*/ BC_ASSERT_EQUAL(bzrtp_getSelfZID((void *)aliceDB, "alice@sip.linphone.org", selfZIDalice, NULL), 0, int, "%x"); BC_ASSERT_EQUAL(bzrtp_getSelfZID((void *)bobDB, "bob@sip.linphone.org", selfZIDbob, NULL), 0, int, "%x"); /* then get the matching zuid in cache */ BC_ASSERT_EQUAL(bzrtp_cache_getZuid((void *)aliceDB, "alice@sip.linphone.org", "bob@sip.linphone.org", selfZIDbob, &zuidAlice), 0, int, "%x"); BC_ASSERT_EQUAL(bzrtp_cache_getZuid((void *)bobDB, "bob@sip.linphone.org", "alice@sip.linphone.org", selfZIDalice, &zuidBob), 0, int, "%x"); /* retrieve the values */ BC_ASSERT_EQUAL(bzrtp_cache_read((void *)aliceDB, zuidAlice, "zrtp", colNames, colValuesAlice, colLengthAlice, 3), 0, int, "%x"); BC_ASSERT_EQUAL(bzrtp_cache_read((void *)bobDB, zuidBob, "zrtp", colNames, colValuesBob, colLengthBob, 3), 0, int, "%x"); /* and compare to expected */ /* rs1 is set and they are both the same */ BC_ASSERT_EQUAL(colLengthAlice[0], 32, int, "%d"); BC_ASSERT_EQUAL(colLengthBob[0], 32, int, "%d"); BC_ASSERT_EQUAL(memcmp(colValuesAlice[0], colValuesBob[0], 32), 0, int, "%d"); /* rs2 is unset(NULL) */ BC_ASSERT_EQUAL(colLengthAlice[1], 0, int, "%d"); BC_ASSERT_EQUAL(colLengthBob[1], 0, int, "%d"); BC_ASSERT_PTR_NULL(colValuesAlice[1]); BC_ASSERT_PTR_NULL(colValuesBob[1]); /* pvs is equal to 1 */ BC_ASSERT_EQUAL(colLengthAlice[2], 1, int, "%d"); BC_ASSERT_EQUAL(colLengthBob[2], 1, int, "%d"); BC_ASSERT_EQUAL(*colValuesAlice[2], 1, int, "%d"); BC_ASSERT_EQUAL(*colValuesBob[2], 1, int, "%d"); /* Modify Alice cache rs1 first byte value, it will cause a cache mismatch at next exchange */ colValuesAlice[0][0] += 1; BC_ASSERT_EQUAL(bzrtp_cache_write((void *)aliceDB, zuidAlice, "zrtp", colNames, colValuesAlice, colLengthAlice, 1), 0, int, "%x"); /* make a second exchange : we have a cache mismatch(both on Bob and Alice side), wich means rs1 will not be backed up in rs2 which shall be NULL again */ /* rs1 will be in sync has the SAS comparison will succeed and pvs will be set to 1*/ BC_ASSERT_EQUAL(multichannel_exchange(NULL, NULL, &defaultCryptoAlgoSelection, aliceDB, "alice@sip.linphone.org", bobDB, "bob@sip.linphone.org"), RET_CACHE_MISMATCH<<16|RET_CACHE_MISMATCH, int, "%x"); BC_ASSERT_EQUAL(bzrtp_cache_read((void *)bobDB, zuidBob, "zrtp", colNames, colValuesBob, colLengthBob, 3), 0, int, "%x"); BC_ASSERT_EQUAL(bzrtp_cache_read((void *)aliceDB, zuidAlice, "zrtp", colNames, colValuesAlice, colLengthAlice, 3), 0, int, "%x"); BC_ASSERT_EQUAL(colLengthAlice[0], 32, int, "%d"); BC_ASSERT_EQUAL(colLengthAlice[1], 0, int, "%d"); BC_ASSERT_EQUAL(colLengthAlice[2], 1, int, "%d"); BC_ASSERT_EQUAL(colLengthBob[0], 32, int, "%d"); BC_ASSERT_EQUAL(colLengthBob[1], 0, int, "%d"); BC_ASSERT_EQUAL(colLengthBob[2], 1, int, "%d"); BC_ASSERT_EQUAL(memcmp(colValuesAlice[0], colValuesBob[0], 32), 0, int, "%d"); BC_ASSERT_PTR_NULL(colValuesAlice[1]); BC_ASSERT_PTR_NULL(colValuesBob[1]); BC_ASSERT_EQUAL(*colValuesAlice[2], 1, int, "%d"); BC_ASSERT_EQUAL(*colValuesBob[2], 1, int, "%d"); /* Delete Alice cache rs1 first byte value, it will cause a cache mismatch at next exchange but only on Bob's side as Alice will not expect any valid cache */ free(colValuesAlice[0]); colValuesAlice[0] = NULL; colLengthAlice[0] = 0; colValuesAlice[2][0] = 0; /* reset pvs to 0 */ BC_ASSERT_EQUAL(bzrtp_cache_write((void *)aliceDB, zuidAlice, "zrtp", colNames, colValuesAlice, colLengthAlice, 3), 0, int, "%x"); /* make a third exchange : we have a cache mismatch(on Bob side only), wich means rs1 will not be backed up in rs2 which shall be NULL again */ /* rs1 will be in sync has the SAS comparison will succeed and pvs will be set to 1*/ BC_ASSERT_EQUAL(multichannel_exchange(NULL, NULL, &defaultCryptoAlgoSelection, aliceDB, "alice@sip.linphone.org", bobDB, "bob@sip.linphone.org"), RET_CACHE_MISMATCH<<16, int, "%x"); BC_ASSERT_EQUAL(bzrtp_cache_read((void *)bobDB, zuidBob, "zrtp", colNames, colValuesBob, colLengthBob, 3), 0, int, "%x"); BC_ASSERT_EQUAL(bzrtp_cache_read((void *)aliceDB, zuidAlice, "zrtp", colNames, colValuesAlice, colLengthAlice, 3), 0, int, "%x"); BC_ASSERT_EQUAL(colLengthAlice[0], 32, int, "%d"); BC_ASSERT_EQUAL(colLengthAlice[1], 0, int, "%d"); BC_ASSERT_EQUAL(colLengthAlice[2], 1, int, "%d"); BC_ASSERT_EQUAL(colLengthBob[0], 32, int, "%d"); BC_ASSERT_EQUAL(colLengthBob[1], 0, int, "%d"); BC_ASSERT_EQUAL(colLengthBob[2], 1, int, "%d"); BC_ASSERT_EQUAL(memcmp(colValuesAlice[0], colValuesBob[0], 32), 0, int, "%d"); BC_ASSERT_PTR_NULL(colValuesAlice[1]); BC_ASSERT_PTR_NULL(colValuesBob[1]); BC_ASSERT_EQUAL(*colValuesAlice[2], 1, int, "%d"); /* free buffers */ for (i=0; i<3; i++) { free(colValuesAlice[i]); free(colValuesBob[i]); } sqlite3_close(aliceDB); sqlite3_close(bobDB); /* clean temporary files */ remove("tmpZIDAlice_cacheMismatch.sqlite"); remove("tmpZIDBob_cacheMismatch.sqlite"); #endif /* ZIDCACHE_ENABLED */ } void test_cache_sas_not_confirmed(void) { #ifdef ZIDCACHE_ENABLED sqlite3 *aliceDB=NULL; sqlite3 *bobDB=NULL; uint8_t selfZIDalice[12]; uint8_t selfZIDbob[12]; int zuidAlice=0,zuidBob=0; char *colNames[] = {"rs1", "rs2", "pvs"}; uint8_t *colValuesAlice[3]; size_t colLengthAlice[3]; uint8_t *colValuesBob[3]; size_t colLengthBob[3]; int i; /* create tempory DB files, just try to clean them from dir before, just in case */ remove("tmpZIDAlice_simpleCache.sqlite"); remove("tmpZIDBob_simpleCache.sqlite"); bzrtptester_sqlite3_open(bc_tester_file("tmpZIDAlice_simpleCache.sqlite"), &aliceDB); bzrtptester_sqlite3_open(bc_tester_file("tmpZIDBob_simpleCache.sqlite"), &bobDB); /* make a first exchange, Alice is instructed to not validate the SAS */ BC_ASSERT_EQUAL(multichannel_exchange_pvs_params(&defaultCryptoAlgoSelectionNoSASValidation, &defaultCryptoAlgoSelection, &defaultCryptoAlgoSelection, aliceDB, "alice@sip.linphone.org", bobDB, "bob@sip.linphone.org", TRUE, 0, 0), 0, int, "%x"); /* after the first exchange we shall have alice pvs at 0 and bob at 1 and both rs1 identical and rs2 null, retrieve them from cache and check it */ /* first get each ZIDs, note give NULL as RNG context may lead to segfault in case of error(caches were not created correctly)*/ BC_ASSERT_EQUAL(bzrtp_getSelfZID((void *)aliceDB, "alice@sip.linphone.org", selfZIDalice, NULL), 0, int, "%x"); BC_ASSERT_EQUAL(bzrtp_getSelfZID((void *)bobDB, "bob@sip.linphone.org", selfZIDbob, NULL), 0, int, "%x"); /* then get the matching zuid in cache */ BC_ASSERT_EQUAL(bzrtp_cache_getZuid((void *)aliceDB, "alice@sip.linphone.org", "bob@sip.linphone.org", selfZIDbob, &zuidAlice), 0, int, "%x"); BC_ASSERT_EQUAL(bzrtp_cache_getZuid((void *)bobDB, "bob@sip.linphone.org", "alice@sip.linphone.org", selfZIDalice, &zuidBob), 0, int, "%x"); /* retrieve the values */ BC_ASSERT_EQUAL(bzrtp_cache_read((void *)aliceDB, zuidAlice, "zrtp", colNames, colValuesAlice, colLengthAlice, 3), 0, int, "%x"); BC_ASSERT_EQUAL(bzrtp_cache_read((void *)bobDB, zuidBob, "zrtp", colNames, colValuesBob, colLengthBob, 3), 0, int, "%x"); /* and compare to expected */ /* rs1 is set and they are both the same */ BC_ASSERT_EQUAL(colLengthAlice[0], 32, int, "%d"); BC_ASSERT_EQUAL(colLengthBob[0], 32, int, "%d"); BC_ASSERT_EQUAL(memcmp(colValuesAlice[0], colValuesBob[0], 32), 0, int, "%d"); /* rs2 is unset(NULL) */ BC_ASSERT_EQUAL(colLengthAlice[1], 0, int, "%d"); BC_ASSERT_EQUAL(colLengthBob[1], 0, int, "%d"); BC_ASSERT_PTR_NULL(colValuesAlice[1]); BC_ASSERT_PTR_NULL(colValuesBob[1]); /* pvs is equal to 0 for Alice(actually NULL, so length is 0 and has no value which is considered 0 by the getPeerSecrets function) and 1 for Bob */ BC_ASSERT_EQUAL(colLengthAlice[2], 0, int, "%d"); BC_ASSERT_EQUAL(colLengthBob[2], 1, int, "%d"); BC_ASSERT_EQUAL(*colValuesBob[2], 1, int, "%d"); /* make a second exchange, the PVS flag returned by both side shall be 0 as Alice did not validate hers on previous exchange */ /* but let them both validate this one */ BC_ASSERT_EQUAL(multichannel_exchange_pvs_params(NULL, NULL, &defaultCryptoAlgoSelection, aliceDB, "alice@sip.linphone.org", bobDB, "bob@sip.linphone.org", TRUE, 0, 0), 0, int, "%x"); /* read new values in cache, ZIDs and zuids must be identical, read alice first to be able to check rs2 with old rs1 */ BC_ASSERT_EQUAL(bzrtp_cache_read((void *)aliceDB, zuidAlice, "zrtp", colNames, colValuesAlice, colLengthAlice, 3), 0, int, "%x"); /* check what is now rs2 is the old rs1 */ BC_ASSERT_EQUAL(colLengthAlice[0], 32, int, "%d"); BC_ASSERT_EQUAL(colLengthAlice[1], 32, int, "%d"); BC_ASSERT_EQUAL(colLengthAlice[2], 1, int, "%d"); BC_ASSERT_EQUAL(memcmp(colValuesAlice[1], colValuesBob[0], 32), 0, int, "%d"); /* colValuesBob, still old values from before the second exchange */ /* so read bob updated values and compare rs1, rs2 and check pvs is at 1 */ BC_ASSERT_EQUAL(bzrtp_cache_read((void *)bobDB, zuidBob, "zrtp", colNames, colValuesBob, colLengthBob, 3), 0, int, "%x"); BC_ASSERT_EQUAL(colLengthBob[0], 32, int, "%d"); BC_ASSERT_EQUAL(colLengthBob[1], 32, int, "%d"); BC_ASSERT_EQUAL(colLengthBob[2], 1, int, "%d"); BC_ASSERT_EQUAL(memcmp(colValuesAlice[0], colValuesBob[0], 32), 0, int, "%d"); BC_ASSERT_EQUAL(memcmp(colValuesAlice[1], colValuesBob[1], 32), 0, int, "%d"); BC_ASSERT_EQUAL(*colValuesAlice[2], 1, int, "%d"); BC_ASSERT_EQUAL(*colValuesBob[2], 1, int, "%d"); /* make a third exchange, the PVS flag returned by both side shall be 1 */ BC_ASSERT_EQUAL(multichannel_exchange_pvs_params(NULL, NULL, &defaultCryptoAlgoSelection, aliceDB, "alice@sip.linphone.org", bobDB, "bob@sip.linphone.org", TRUE, 1, 1), 0, int, "%x"); /* read new values in cache, ZIDs and zuids must be identical, read alice first to be able to check rs2 with old rs1 */ BC_ASSERT_EQUAL(bzrtp_cache_read((void *)aliceDB, zuidAlice, "zrtp", colNames, colValuesAlice, colLengthAlice, 3), 0, int, "%x"); /* check what is now rs2 is the old rs1 */ BC_ASSERT_EQUAL(colLengthAlice[0], 32, int, "%d"); BC_ASSERT_EQUAL(colLengthAlice[1], 32, int, "%d"); BC_ASSERT_EQUAL(colLengthAlice[2], 1, int, "%d"); BC_ASSERT_EQUAL(memcmp(colValuesAlice[1], colValuesBob[0], 32), 0, int, "%d"); /* colValuesBob, still old values from before the second exchange */ /* so read bob updated values and compare rs1, rs2 and check pvs is still at 1 */ BC_ASSERT_EQUAL(bzrtp_cache_read((void *)bobDB, zuidBob, "zrtp", colNames, colValuesBob, colLengthBob, 3), 0, int, "%x"); BC_ASSERT_EQUAL(colLengthBob[0], 32, int, "%d"); BC_ASSERT_EQUAL(colLengthBob[1], 32, int, "%d"); BC_ASSERT_EQUAL(colLengthBob[2], 1, int, "%d"); BC_ASSERT_EQUAL(memcmp(colValuesAlice[0], colValuesBob[0], 32), 0, int, "%d"); BC_ASSERT_EQUAL(memcmp(colValuesAlice[1], colValuesBob[1], 32), 0, int, "%d"); BC_ASSERT_EQUAL(*colValuesAlice[2], 1, int, "%d"); BC_ASSERT_EQUAL(*colValuesBob[2], 1, int, "%d"); /* free buffers */ for (i=0; i<3; i++) { free(colValuesAlice[i]); free(colValuesBob[i]); } sqlite3_close(aliceDB); sqlite3_close(bobDB); /* clean temporary files */ remove("tmpZIDAlice_simpleCache.sqlite"); remove("tmpZIDBob_simpleCache.sqlite"); #endif /* ZIDCACHE_ENABLED */ } bzrtp-1.0.6/test/bzrtpConfigsTest.h000066400000000000000000000017711313411235300173230ustar00rootroot00000000000000/** @file bzrtpConfigsTest.h @author Johan Pascal @copyright Copyright (C) 2017 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ void test_cacheless_exchange(void); void test_loosy_network(void); void test_cache_enabled_exchange(void); void test_cache_mismatch_exchange(void); void test_cache_sas_not_confirmed(void); bzrtp-1.0.6/test/bzrtpCryptoTest.c000066400000000000000000001036521313411235300172070ustar00rootroot00000000000000/** @file bzrtpCryptoTests.c @brief Test suite for the crypto wrapper. Test the following functions needed by ZRTP: - random number generation - HMAC-SHA256 - AES-128 CFB mode - DHM2k and DHM3k - ZRTP Key Derivation function - CRC32 @author Johan Pascal @copyright Copyright (C) 2014 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include "bzrtp/bzrtp.h" #include "cryptoUtils.h" #include "testUtils.h" #include /** * * Patterns generated using GNU ZRTP C++ */ #define KDF_TEST_NUMBER 9 uint8_t patternKDFLabel[KDF_TEST_NUMBER][28] = { "Responder SRTP master key", "Responder SRTP master salt", "SAS", "ZRTP Session Key", "retained secret", "Responder ZRTP key", "Initiator ZRTP key", "Responder HMAC key", "Initiator HMAC key"}; uint16_t patternKDFContextLength[KDF_TEST_NUMBER] = {56, 56, 56 , 56, 56, 56, 56, 56, 56}; uint16_t patternKDFHmacLength[KDF_TEST_NUMBER] = {16, 14, 32, 32, 32, 16, 16, 32, 32}; uint8_t patternKDFOutput[KDF_TEST_NUMBER][32] = { {0xf2, 0xcf, 0xc5, 0x72, 0x4a, 0xcf, 0xd7, 0xb5, 0x0e, 0x89, 0xbe, 0xd8, 0xa5, 0xc9, 0xf2, 0xcd}, {0x3c, 0x8f, 0xb1, 0x3f, 0xd6, 0xca, 0x83, 0xfb, 0xd6, 0xaf, 0x3b, 0xd5, 0xab, 0x1c}, {0xd2, 0x69, 0xb0, 0x71, 0x8a, 0xd5, 0x8f, 0x3c, 0x8e, 0x0d, 0xcf, 0x45, 0x35, 0x81, 0x1d, 0x95, 0x18, 0x47, 0x31, 0x41, 0x28, 0x31, 0x9f, 0x54, 0xc6, 0x06, 0x59, 0x5b, 0x52, 0x2c, 0x52, 0x87}, {0xc3, 0x63, 0x39, 0x0b, 0xc9, 0xee, 0x13, 0xaa, 0x9e, 0x6a, 0x00, 0x52, 0x84, 0x09, 0xdd, 0xc9, 0x07, 0x17, 0xe0, 0x1d, 0x1a, 0xe2, 0xdc, 0xf9, 0xa7, 0x0a, 0xb9, 0x88, 0x86, 0xac, 0x69, 0x75}, {0xa7, 0x27, 0x2d, 0xee, 0x77, 0xe7, 0x99, 0x0c, 0x24, 0xb2, 0x0b, 0x9f, 0x54, 0xba, 0x2b, 0x61, 0x7a, 0x23, 0xd8, 0xa5, 0x97, 0x65, 0x82, 0x9b, 0x78, 0x07, 0x2b, 0xc5, 0x12, 0x99, 0x01, 0x5c}, {0x75, 0x76, 0x7d, 0x41, 0x82, 0x9c, 0xb6, 0x97, 0xc7, 0xa2, 0x0d, 0x68, 0x12, 0xea, 0xdb, 0x9a}, {0x08, 0xa8, 0x21, 0x46, 0x0c, 0xbd, 0x6c, 0xe0, 0xf1, 0xfe, 0x3c, 0x4c, 0x70, 0x4e, 0x3b, 0xea}, {0x21, 0x69, 0xf1, 0x5c, 0x1b, 0x85, 0xa2, 0x39, 0x77, 0x02, 0x4d, 0x5e, 0xa7, 0x1f, 0x48, 0x16, 0x23, 0xfe, 0x94, 0xdc, 0x1a, 0xab, 0xf4, 0x89, 0xb8, 0x74, 0x4d, 0x0d, 0x37, 0x3d, 0x7c, 0xab}, {0x1d, 0x11, 0x7b, 0xef, 0xd6, 0x27, 0xcc, 0x5a, 0x80, 0xd0, 0x23, 0x6e, 0x8d, 0x49, 0x6b, 0xe4, 0x2a, 0x6a, 0x01, 0x18, 0xac, 0x41, 0x59, 0xe8, 0x61, 0xb9, 0xb1, 0x4a, 0x78, 0x4b, 0x5d, 0x3f} }; uint8_t patternKDFContext[KDF_TEST_NUMBER][56] = { {0xf0, 0x1f, 0x24, 0x02, 0x00, 0x00, 0x00, 0x00, 0x80, 0x24, 0xad, 0xfb, 0x94, 0xa9, 0x06, 0x90, 0xcf, 0x9c, 0xed, 0x13, 0x99, 0x8c, 0x51, 0x34, 0x7d, 0xc4, 0x35, 0xa7, 0x4d, 0x75, 0x25, 0x44, 0x80, 0xc2, 0x11, 0xf2, 0xd3, 0x20, 0x5e, 0xa7, 0x1b, 0x4b, 0xa4, 0xee, 0xc7, 0x8e, 0xb7, 0x35, 0x75, 0x28, 0xe5, 0x6f, 0xcf, 0x4f, 0x74, 0x9f}, {0xf0, 0x1f, 0x24, 0x02, 0x00, 0x00, 0x00, 0x00, 0x80, 0x24, 0xad, 0xfb, 0x94, 0xa9, 0x06, 0x90, 0xcf, 0x9c, 0xed, 0x13, 0x99, 0x8c, 0x51, 0x34, 0x7d, 0xc4, 0x35, 0xa7, 0x4d, 0x75, 0x25, 0x44, 0x80, 0xc2, 0x11, 0xf2, 0xd3, 0x20, 0x5e, 0xa7, 0x1b, 0x4b, 0xa4, 0xee, 0xc7, 0x8e, 0xb7, 0x35, 0x75, 0x28, 0xe5, 0x6f, 0xcf, 0x4f, 0x74, 0x9f}, {0xf0, 0x1f, 0x24, 0x02, 0x00, 0x00, 0x00, 0x00, 0x80, 0x24, 0xad, 0xfb, 0x94, 0xa9, 0x06, 0x90, 0xcf, 0x9c, 0xed, 0x13, 0x99, 0x8c, 0x51, 0x34, 0x7d, 0xc4, 0x35, 0xa7, 0x4d, 0x75, 0x25, 0x44, 0x80, 0xc2, 0x11, 0xf2, 0xd3, 0x20, 0x5e, 0xa7, 0x1b, 0x4b, 0xa4, 0xee, 0xc7, 0x8e, 0xb7, 0x35, 0x75, 0x28, 0xe5, 0x6f, 0xcf, 0x4f, 0x74, 0x9f}, {0xf0, 0x1f, 0x24, 0x02, 0x00, 0x00, 0x00, 0x00, 0x80, 0x24, 0xad, 0xfb, 0x94, 0xa9, 0x06, 0x90, 0xcf, 0x9c, 0xed, 0x13, 0x99, 0x8c, 0x51, 0x34, 0x7d, 0xc4, 0x35, 0xa7, 0x4d, 0x75, 0x25, 0x44, 0x80, 0xc2, 0x11, 0xf2, 0xd3, 0x20, 0x5e, 0xa7, 0x1b, 0x4b, 0xa4, 0xee, 0xc7, 0x8e, 0xb7, 0x35, 0x75, 0x28, 0xe5, 0x6f, 0xcf, 0x4f, 0x74, 0x9f}, {0xf0, 0x1f, 0x24, 0x02, 0x00, 0x00, 0x00, 0x00, 0x80, 0x24, 0xad, 0xfb, 0x94, 0xa9, 0x06, 0x90, 0xcf, 0x9c, 0xed, 0x13, 0x99, 0x8c, 0x51, 0x34, 0x7d, 0xc4, 0x35, 0xa7, 0x4d, 0x75, 0x25, 0x44, 0x80, 0xc2, 0x11, 0xf2, 0xd3, 0x20, 0x5e, 0xa7, 0x1b, 0x4b, 0xa4, 0xee, 0xc7, 0x8e, 0xb7, 0x35, 0x75, 0x28, 0xe5, 0x6f, 0xcf, 0x4f, 0x74, 0x9f}, {0xf0, 0x1f, 0x24, 0x02, 0x00, 0x00, 0x00, 0x00, 0x80, 0x24, 0xad, 0xfb, 0x94, 0xa9, 0x06, 0x90, 0xcf, 0x9c, 0xed, 0x13, 0x99, 0x8c, 0x51, 0x34, 0x7d, 0xc4, 0x35, 0xa7, 0x4d, 0x75, 0x25, 0x44, 0x80, 0xc2, 0x11, 0xf2, 0xd3, 0x20, 0x5e, 0xa7, 0x1b, 0x4b, 0xa4, 0xee, 0xc7, 0x8e, 0xb7, 0x35, 0x75, 0x28, 0xe5, 0x6f, 0xcf, 0x4f, 0x74, 0x9f}, {0xf0, 0x1f, 0x24, 0x02, 0x00, 0x00, 0x00, 0x00, 0x80, 0x24, 0xad, 0xfb, 0x94, 0xa9, 0x06, 0x90, 0xcf, 0x9c, 0xed, 0x13, 0x99, 0x8c, 0x51, 0x34, 0x7d, 0xc4, 0x35, 0xa7, 0x4d, 0x75, 0x25, 0x44, 0x80, 0xc2, 0x11, 0xf2, 0xd3, 0x20, 0x5e, 0xa7, 0x1b, 0x4b, 0xa4, 0xee, 0xc7, 0x8e, 0xb7, 0x35, 0x75, 0x28, 0xe5, 0x6f, 0xcf, 0x4f, 0x74, 0x9f}, {0xf0, 0x1f, 0x24, 0x02, 0x00, 0x00, 0x00, 0x00, 0x80, 0x24, 0xad, 0xfb, 0x94, 0xa9, 0x06, 0x90, 0xcf, 0x9c, 0xed, 0x13, 0x99, 0x8c, 0x51, 0x34, 0x7d, 0xc4, 0x35, 0xa7, 0x4d, 0x75, 0x25, 0x44, 0x80, 0xc2, 0x11, 0xf2, 0xd3, 0x20, 0x5e, 0xa7, 0x1b, 0x4b, 0xa4, 0xee, 0xc7, 0x8e, 0xb7, 0x35, 0x75, 0x28, 0xe5, 0x6f, 0xcf, 0x4f, 0x74, 0x9f}, {0xf0, 0x1f, 0x24, 0x02, 0x00, 0x00, 0x00, 0x00, 0x80, 0x24, 0xad, 0xfb, 0x94, 0xa9, 0x06, 0x90, 0xcf, 0x9c, 0xed, 0x13, 0x99, 0x8c, 0x51, 0x34, 0x7d, 0xc4, 0x35, 0xa7, 0x4d, 0x75, 0x25, 0x44, 0x80, 0xc2, 0x11, 0xf2, 0xd3, 0x20, 0x5e, 0xa7, 0x1b, 0x4b, 0xa4, 0xee, 0xc7, 0x8e, 0xb7, 0x35, 0x75, 0x28, 0xe5, 0x6f, 0xcf, 0x4f, 0x74, 0x9f} }; void test_zrtpKDF(void) { int i; uint8_t keyKDF[32] = {0x33, 0xe6, 0x6c, 0x01, 0xca, 0x6f, 0xe6, 0x4f, 0xb7, 0x6f, 0xfd, 0xe3, 0x1c, 0xab, 0xc0, 0xfb, 0xad, 0x3d, 0x31, 0x02, 0x67, 0x6b, 0x0c, 0x09, 0x0f, 0xc9, 0x96, 0x38, 0x1e, 0x0a, 0x8c, 0x2f}; uint8_t output[32]; for (i=0; isupportedHash, types, typesCount); helloMessage->hc = typesCount; break; case ZRTP_CIPHERBLOCK_TYPE: memcpy(helloMessage->supportedCipher, types, typesCount); helloMessage->cc = typesCount; break; case ZRTP_AUTHTAG_TYPE: memcpy(helloMessage->supportedAuthTag, types, typesCount); helloMessage->ac = typesCount; break; case ZRTP_KEYAGREEMENT_TYPE: memcpy(helloMessage->supportedKeyAgreement, types, typesCount); helloMessage->kc = typesCount; break; case ZRTP_SAS_TYPE: memcpy(helloMessage->supportedSas, types, typesCount); helloMessage->sc = typesCount; break; } } static int compareAllAlgoTypes(bzrtpChannelContext_t *zrtpChannelContext, uint8_t expectedHashAlgo, uint8_t expectedCipherAlgo, uint8_t expectedAuthTagAlgo, uint8_t expectedKeyAgreementAlgo, uint8_t expectedSasAlgo) { return zrtpChannelContext->hashAlgo == expectedHashAlgo && zrtpChannelContext->cipherAlgo == expectedCipherAlgo && zrtpChannelContext->authTagAlgo == expectedAuthTagAlgo && zrtpChannelContext->keyAgreementAlgo == expectedKeyAgreementAlgo && zrtpChannelContext->sasAlgo == expectedSasAlgo; } static int compareAllAlgoTypesWithExpectedChangedOnly(bzrtpChannelContext_t *zrtpChannelContext, uint8_t expectedAlgoType, uint8_t expectedType) { switch(expectedAlgoType) { case ZRTP_HASH_TYPE: return compareAllAlgoTypes(zrtpChannelContext, expectedType, ZRTP_CIPHER_AES1, ZRTP_AUTHTAG_HS32, ZRTP_KEYAGREEMENT_DH3k, ZRTP_SAS_B32); case ZRTP_CIPHERBLOCK_TYPE: return compareAllAlgoTypes(zrtpChannelContext, ZRTP_HASH_S256, expectedType, ZRTP_AUTHTAG_HS32, ZRTP_KEYAGREEMENT_DH3k, ZRTP_SAS_B32); case ZRTP_AUTHTAG_TYPE: return compareAllAlgoTypes(zrtpChannelContext, ZRTP_HASH_S256, ZRTP_CIPHER_AES1, expectedType, ZRTP_KEYAGREEMENT_DH3k, ZRTP_SAS_B32); case ZRTP_KEYAGREEMENT_TYPE: return compareAllAlgoTypes(zrtpChannelContext, ZRTP_HASH_S256, ZRTP_CIPHER_AES1, ZRTP_AUTHTAG_HS32, expectedType, ZRTP_SAS_B32); case ZRTP_SAS_TYPE: return compareAllAlgoTypes(zrtpChannelContext, ZRTP_HASH_S256, ZRTP_CIPHER_AES1, ZRTP_AUTHTAG_HS32, ZRTP_KEYAGREEMENT_DH3k, expectedType); default: return compareAllAlgoTypes(zrtpChannelContext, ZRTP_HASH_S256, ZRTP_CIPHER_AES1, ZRTP_AUTHTAG_HS32, ZRTP_KEYAGREEMENT_DH3k, ZRTP_SAS_B32); } } static int testAlgoType(uint8_t algoType, uint8_t *packetTypes, uint8_t packetTypesCount, uint8_t *contextTypes, uint8_t contextTypesCount, uint8_t expectedType) { int retval; bzrtpContext_t *zrtpContext = bzrtp_createBzrtpContext(); bzrtpPacket_t *helloPacket = NULL; bzrtp_initBzrtpContext(zrtpContext, 0x12345678); if (contextTypes != NULL) { bzrtp_setSupportedCryptoTypes(zrtpContext, algoType, contextTypes, contextTypesCount); } helloPacket = bzrtp_createZrtpPacket(zrtpContext, zrtpContext->channelContext[0], MSGTYPE_HELLO, &retval); if (packetTypes != NULL) { bzrtpHelloMessage_t *helloMessage = (bzrtpHelloMessage_t *)helloPacket->messageData; setHelloMessageAlgo(helloMessage, algoType, packetTypes, packetTypesCount); } BC_ASSERT_FALSE(bzrtp_cryptoAlgoAgreement(zrtpContext, zrtpContext->channelContext[0], helloPacket->messageData)); retval = compareAllAlgoTypesWithExpectedChangedOnly(zrtpContext->channelContext[0], algoType, expectedType); bzrtp_freeZrtpPacket(helloPacket); bzrtp_destroyBzrtpContext(zrtpContext, 0x12345678); return retval; } static int testAlgoTypeWithPacket(uint8_t algoType, uint8_t *types, uint8_t typesCount, uint8_t expectedType) { return testAlgoType(algoType, types, typesCount, NULL, 0, expectedType); } static int testAlgoTypeWithContext(uint8_t algoType, uint8_t *types, uint8_t typesCount, uint8_t expectedType) { return testAlgoType(algoType, NULL, 0, types, typesCount, expectedType); } struct st_algo_type_with_packet { uint8_t types[7]; uint8_t typesCount; uint8_t expectedType; }; struct st_algo_type_with_context { uint8_t types[7]; uint8_t typesCount; uint8_t expectedType; }; struct st_algo_type { uint8_t packetTypes[7]; uint8_t packetTypesCount; uint8_t contextTypes[7]; uint8_t contextTypesCount; uint8_t expectedType; }; void test_algoAgreement(void) { struct st_algo_type_with_packet agreement_types_with_packet[] = { { {ZRTP_KEYAGREEMENT_DH2k}, 1, ZRTP_KEYAGREEMENT_DH2k }, { {ZRTP_KEYAGREEMENT_DH3k}, 1, ZRTP_KEYAGREEMENT_DH3k }, { {ZRTP_KEYAGREEMENT_DH2k, ZRTP_KEYAGREEMENT_DH3k}, 2, ZRTP_KEYAGREEMENT_DH2k }, { {ZRTP_KEYAGREEMENT_EC25, ZRTP_KEYAGREEMENT_DH3k}, 2, ZRTP_KEYAGREEMENT_DH3k }, { {ZRTP_KEYAGREEMENT_DH2k, ZRTP_KEYAGREEMENT_EC52}, 2, ZRTP_KEYAGREEMENT_DH2k }, { {ZRTP_KEYAGREEMENT_EC25, ZRTP_KEYAGREEMENT_EC52, ZRTP_KEYAGREEMENT_DH3k}, 3, ZRTP_KEYAGREEMENT_DH3k }, { {ZRTP_KEYAGREEMENT_EC52, ZRTP_KEYAGREEMENT_EC25, ZRTP_KEYAGREEMENT_DH3k, ZRTP_KEYAGREEMENT_DH2k}, 4, ZRTP_KEYAGREEMENT_DH3k }, { {ZRTP_KEYAGREEMENT_DH2k, ZRTP_KEYAGREEMENT_DH3k, ZRTP_KEYAGREEMENT_EC25, ZRTP_KEYAGREEMENT_EC52}, 4, ZRTP_KEYAGREEMENT_DH2k }, { {ZRTP_UNSET_ALGO}, 0, 0 } }; struct st_algo_type_with_packet *agreement_type_with_packet; struct st_algo_type_with_context agreement_types_with_context[] = { { {ZRTP_KEYAGREEMENT_DH2k}, 1, ZRTP_KEYAGREEMENT_DH2k }, { {ZRTP_KEYAGREEMENT_DH3k}, 1, ZRTP_KEYAGREEMENT_DH3k }, { {ZRTP_KEYAGREEMENT_EC25}, 1, ZRTP_KEYAGREEMENT_DH3k }, { {ZRTP_KEYAGREEMENT_DH2k, ZRTP_KEYAGREEMENT_DH3k}, 2, ZRTP_KEYAGREEMENT_DH2k }, { {ZRTP_KEYAGREEMENT_EC25, ZRTP_KEYAGREEMENT_DH3k}, 2, ZRTP_KEYAGREEMENT_DH3k }, { {ZRTP_KEYAGREEMENT_DH2k, ZRTP_KEYAGREEMENT_EC52}, 2, ZRTP_KEYAGREEMENT_DH2k }, { {ZRTP_KEYAGREEMENT_EC52, ZRTP_KEYAGREEMENT_EC25}, 2, ZRTP_KEYAGREEMENT_DH3k }, { {ZRTP_KEYAGREEMENT_EC25, ZRTP_KEYAGREEMENT_EC52, ZRTP_KEYAGREEMENT_DH3k}, 3, ZRTP_KEYAGREEMENT_DH3k }, { {ZRTP_KEYAGREEMENT_EC52, ZRTP_KEYAGREEMENT_EC25, ZRTP_KEYAGREEMENT_DH3k, ZRTP_KEYAGREEMENT_DH2k}, 4, ZRTP_KEYAGREEMENT_DH3k }, { {ZRTP_KEYAGREEMENT_DH2k, ZRTP_KEYAGREEMENT_DH3k, ZRTP_KEYAGREEMENT_EC25, ZRTP_KEYAGREEMENT_EC52}, 4, ZRTP_KEYAGREEMENT_DH2k }, { {ZRTP_UNSET_ALGO}, 0, 0 } }; struct st_algo_type_with_context *agreement_type_with_context; struct st_algo_type agreement_types[] = { { {ZRTP_KEYAGREEMENT_DH3k, ZRTP_KEYAGREEMENT_DH2k}, 2, {ZRTP_KEYAGREEMENT_DH2k, ZRTP_KEYAGREEMENT_DH3k}, 2, ZRTP_KEYAGREEMENT_DH2k }, { {ZRTP_KEYAGREEMENT_DH2k, ZRTP_KEYAGREEMENT_DH3k}, 2, {ZRTP_KEYAGREEMENT_DH3k, ZRTP_KEYAGREEMENT_DH2k}, 2, ZRTP_KEYAGREEMENT_DH2k }, { {ZRTP_KEYAGREEMENT_DH3k, ZRTP_KEYAGREEMENT_DH2k}, 2, {ZRTP_KEYAGREEMENT_DH3k, ZRTP_KEYAGREEMENT_DH2k}, 2, ZRTP_KEYAGREEMENT_DH3k }, { {ZRTP_KEYAGREEMENT_EC52, ZRTP_KEYAGREEMENT_EC25, ZRTP_KEYAGREEMENT_DH3k, ZRTP_KEYAGREEMENT_DH2k}, 4, {ZRTP_KEYAGREEMENT_DH3k, ZRTP_KEYAGREEMENT_DH2k}, 2, ZRTP_KEYAGREEMENT_DH3k }, { {ZRTP_KEYAGREEMENT_DH3k, ZRTP_KEYAGREEMENT_DH2k}, 2, {ZRTP_KEYAGREEMENT_EC52, ZRTP_KEYAGREEMENT_EC25, ZRTP_KEYAGREEMENT_DH3k, ZRTP_KEYAGREEMENT_DH2k}, 4, ZRTP_KEYAGREEMENT_DH3k }, { {ZRTP_KEYAGREEMENT_DH2k, ZRTP_KEYAGREEMENT_DH3k, ZRTP_KEYAGREEMENT_EC25, ZRTP_KEYAGREEMENT_EC52}, 4, {ZRTP_KEYAGREEMENT_DH2k, ZRTP_KEYAGREEMENT_DH3k, ZRTP_KEYAGREEMENT_EC25, ZRTP_KEYAGREEMENT_EC52}, 4, ZRTP_KEYAGREEMENT_DH2k }, { {ZRTP_UNSET_ALGO}, 0, {ZRTP_UNSET_ALGO}, 0, 0 } }; struct st_algo_type *agreement_type; struct st_algo_type_with_packet cipher_types_with_packet[] = { { {ZRTP_CIPHER_AES1}, 1, ZRTP_CIPHER_AES1 }, { {ZRTP_CIPHER_AES3}, 1, ZRTP_CIPHER_AES3 }, { {ZRTP_CIPHER_AES3, ZRTP_CIPHER_AES1}, 2, ZRTP_CIPHER_AES1 }, { {ZRTP_CIPHER_AES1, ZRTP_CIPHER_AES3}, 2, ZRTP_CIPHER_AES1 }, { {ZRTP_CIPHER_2FS3, ZRTP_CIPHER_AES1}, 2, ZRTP_CIPHER_AES1 }, { {ZRTP_CIPHER_AES3, ZRTP_CIPHER_AES2, ZRTP_CIPHER_AES1}, 3, ZRTP_CIPHER_AES1 }, { {ZRTP_CIPHER_2FS3, ZRTP_CIPHER_2FS2, ZRTP_CIPHER_2FS1, ZRTP_CIPHER_AES3, ZRTP_CIPHER_AES2, ZRTP_CIPHER_AES1}, 6, ZRTP_CIPHER_AES1 }, { {ZRTP_CIPHER_2FS3, ZRTP_CIPHER_2FS2, ZRTP_CIPHER_2FS1, ZRTP_CIPHER_AES1, ZRTP_CIPHER_AES2, ZRTP_CIPHER_AES3}, 6, ZRTP_CIPHER_AES1 }, { {ZRTP_UNSET_ALGO}, 0, 0 } }; struct st_algo_type_with_packet *cipher_type_with_packet; struct st_algo_type_with_context cipher_types_with_context[] = { { {ZRTP_CIPHER_AES1}, 1, ZRTP_CIPHER_AES1 }, { {ZRTP_CIPHER_AES3}, 1, ZRTP_CIPHER_AES3 }, { {ZRTP_CIPHER_2FS1}, 1, ZRTP_CIPHER_AES1 }, { {ZRTP_CIPHER_AES3, ZRTP_CIPHER_AES1}, 2, ZRTP_CIPHER_AES3 }, { {ZRTP_CIPHER_AES1, ZRTP_CIPHER_AES3}, 2, ZRTP_CIPHER_AES1 }, { {ZRTP_CIPHER_2FS3, ZRTP_CIPHER_AES1}, 2, ZRTP_CIPHER_AES1 }, { {ZRTP_CIPHER_AES3, ZRTP_CIPHER_AES2, ZRTP_CIPHER_AES1}, 3, ZRTP_CIPHER_AES3 }, { {ZRTP_CIPHER_2FS3, ZRTP_CIPHER_2FS2, ZRTP_CIPHER_2FS1}, 3, ZRTP_CIPHER_AES1 }, { {ZRTP_CIPHER_2FS3, ZRTP_CIPHER_2FS2, ZRTP_CIPHER_2FS1, ZRTP_CIPHER_AES3, ZRTP_CIPHER_AES2, ZRTP_CIPHER_AES1}, 6, ZRTP_CIPHER_AES3 }, { {ZRTP_CIPHER_2FS3, ZRTP_CIPHER_2FS2, ZRTP_CIPHER_2FS1, ZRTP_CIPHER_AES1, ZRTP_CIPHER_AES2, ZRTP_CIPHER_AES3}, 6, ZRTP_CIPHER_AES1 }, { {ZRTP_UNSET_ALGO}, 0, 0 } }; struct st_algo_type_with_context *cipher_type_with_context; struct st_algo_type cipher_types[] = { { {ZRTP_CIPHER_AES3, ZRTP_CIPHER_AES1}, 2, {ZRTP_CIPHER_AES1, ZRTP_CIPHER_AES3}, 2, ZRTP_CIPHER_AES1 }, { {ZRTP_CIPHER_AES1, ZRTP_CIPHER_AES3}, 2, {ZRTP_CIPHER_AES3, ZRTP_CIPHER_AES1}, 2, ZRTP_CIPHER_AES3 }, { {ZRTP_CIPHER_AES3, ZRTP_CIPHER_AES1}, 2, {ZRTP_CIPHER_AES3, ZRTP_CIPHER_AES1}, 2, ZRTP_CIPHER_AES3 }, { {ZRTP_CIPHER_2FS3, ZRTP_CIPHER_2FS2, ZRTP_CIPHER_2FS1, ZRTP_CIPHER_AES3, ZRTP_CIPHER_AES2, ZRTP_CIPHER_AES1}, 6, {ZRTP_CIPHER_AES3, ZRTP_CIPHER_AES1}, 2, ZRTP_CIPHER_AES3 }, { {ZRTP_CIPHER_AES3, ZRTP_CIPHER_AES1}, 2, {ZRTP_CIPHER_2FS3, ZRTP_CIPHER_2FS2, ZRTP_CIPHER_2FS1, ZRTP_CIPHER_AES3, ZRTP_CIPHER_AES2, ZRTP_CIPHER_AES1}, 6, ZRTP_CIPHER_AES3 }, { {ZRTP_CIPHER_2FS3, ZRTP_CIPHER_2FS2, ZRTP_CIPHER_2FS1, ZRTP_CIPHER_AES3, ZRTP_CIPHER_AES2, ZRTP_CIPHER_AES1}, 6, {ZRTP_CIPHER_2FS3, ZRTP_CIPHER_2FS2, ZRTP_CIPHER_2FS1, ZRTP_CIPHER_AES3, ZRTP_CIPHER_AES2, ZRTP_CIPHER_AES1}, 6, ZRTP_CIPHER_AES3 }, { {ZRTP_CIPHER_2FS3, ZRTP_CIPHER_2FS2, ZRTP_CIPHER_2FS1, ZRTP_CIPHER_AES3, ZRTP_CIPHER_AES2, ZRTP_CIPHER_AES1}, 6, {ZRTP_CIPHER_2FS3, ZRTP_CIPHER_2FS2, ZRTP_CIPHER_2FS1, ZRTP_CIPHER_AES1, ZRTP_CIPHER_AES2, ZRTP_CIPHER_AES3}, 6, ZRTP_CIPHER_AES1 }, { {ZRTP_UNSET_ALGO}, 0, {ZRTP_UNSET_ALGO}, 0, 0 } }; struct st_algo_type *cipher_type; /* check defaults */ BC_ASSERT_TRUE(testAlgoTypeWithPacket(ZRTP_UNSET_ALGO, NULL, 0, ZRTP_KEYAGREEMENT_DH3k)); /* key agreement type */ agreement_type_with_packet = &agreement_types_with_packet[0]; while (agreement_type_with_packet->typesCount > 0) { BC_ASSERT_TRUE(testAlgoTypeWithPacket(ZRTP_KEYAGREEMENT_TYPE, agreement_type_with_packet->types, agreement_type_with_packet->typesCount, agreement_type_with_packet->expectedType)); agreement_type_with_packet++; } agreement_type_with_context = &agreement_types_with_context[0]; while (agreement_type_with_context->typesCount > 0) { BC_ASSERT_TRUE(testAlgoTypeWithContext(ZRTP_KEYAGREEMENT_TYPE, agreement_type_with_context->types, agreement_type_with_context->typesCount, agreement_type_with_context->expectedType)); agreement_type_with_context++; } agreement_type = &agreement_types[0]; while (agreement_type->packetTypesCount > 0) { BC_ASSERT_TRUE(testAlgoType(ZRTP_KEYAGREEMENT_TYPE, agreement_type->packetTypes, agreement_type->packetTypesCount, agreement_type->contextTypes, agreement_type->contextTypesCount, agreement_type->expectedType)); agreement_type++; } /* cipher type */ cipher_type_with_packet = &cipher_types_with_packet[0]; while (cipher_type_with_packet->typesCount > 0) { BC_ASSERT_TRUE(testAlgoTypeWithPacket(ZRTP_CIPHERBLOCK_TYPE, cipher_type_with_packet->types, cipher_type_with_packet->typesCount, cipher_type_with_packet->expectedType)); cipher_type_with_packet++; } cipher_type_with_context = &cipher_types_with_context[0]; while (cipher_type_with_context->typesCount > 0) { BC_ASSERT_TRUE(testAlgoTypeWithContext(ZRTP_CIPHERBLOCK_TYPE, cipher_type_with_context->types, cipher_type_with_context->typesCount, cipher_type_with_context->expectedType)); cipher_type_with_context++; } cipher_type = &cipher_types[0]; while (cipher_type->packetTypesCount > 0) { BC_ASSERT_TRUE(testAlgoType(ZRTP_CIPHERBLOCK_TYPE, cipher_type->packetTypes, cipher_type->packetTypesCount, cipher_type->contextTypes, cipher_type->contextTypesCount, cipher_type->expectedType)); cipher_type++; } } static int compareAlgoTypes(uint8_t actualTypes[7], uint8_t actualTypesCount, uint8_t expectedTypes[7], uint8_t expectedTypesCount) { int i; if (actualTypesCount != expectedTypesCount) { return 0; } for (i=0; icontextTypesCount > 0) { BC_ASSERT_TRUE(testAlgoSetterGetter(ZRTP_KEYAGREEMENT_TYPE, agreement_type->contextTypes, agreement_type->contextTypesCount, agreement_type->expectedTypes, agreement_type->expectedTypesCount)); agreement_type++; } /* cipher type */ cipher_type = &cipher_types[0]; while (cipher_type->contextTypesCount > 0) { BC_ASSERT_TRUE(testAlgoSetterGetter(ZRTP_CIPHERBLOCK_TYPE, cipher_type->contextTypes, cipher_type->contextTypesCount, cipher_type->expectedTypes, cipher_type->expectedTypesCount)); cipher_type++; } } #define ZRTP_AUTHTAG_FAKE_1 0x41 #define ZRTP_AUTHTAG_FAKE_2 0x42 #define ZRTP_AUTHTAG_FAKE_3 0x43 #define ZRTP_AUTHTAG_FAKE_4 0x44 #define ZRTP_AUTHTAG_FAKE_5 0x45 static int testAddMandatoryCryptoTypesIfNeeded(uint8_t algoType, uint8_t *algoTypes, uint8_t algoTypesCount, uint8_t *expectedTypes, uint8_t expectedTypesCount) { bzrtp_addMandatoryCryptoTypesIfNeeded(algoType, algoTypes, &algoTypesCount); return compareAlgoTypes(algoTypes, algoTypesCount, expectedTypes, expectedTypesCount); } struct st_add_crypto { uint8_t algoType; uint8_t algoTypes[7]; uint8_t algoTypesCount; uint8_t expectedTypes[7]; uint8_t expectedTypesCount; }; void test_addMandatoryCryptoTypesIfNeeded(void) { struct st_add_crypto crypto_types[] = { /* mandatory types */ { ZRTP_HASH_TYPE, {ZRTP_UNSET_ALGO}, 0, {ZRTP_HASH_S256}, 1 }, { ZRTP_CIPHERBLOCK_TYPE, {ZRTP_UNSET_ALGO}, 0, {ZRTP_CIPHER_AES1}, 1 }, { ZRTP_AUTHTAG_TYPE, {ZRTP_UNSET_ALGO}, 0, {ZRTP_AUTHTAG_HS32, ZRTP_AUTHTAG_HS80}, 2 }, { ZRTP_KEYAGREEMENT_TYPE, {ZRTP_UNSET_ALGO}, 0, {ZRTP_KEYAGREEMENT_DH3k}, 1 }, { ZRTP_SAS_TYPE, {ZRTP_UNSET_ALGO}, 0, {ZRTP_SAS_B32}, 1 }, { ZRTP_AUTHTAG_TYPE, {ZRTP_AUTHTAG_HS32, ZRTP_AUTHTAG_HS80}, 2, {ZRTP_AUTHTAG_HS32, ZRTP_AUTHTAG_HS80}, 2 }, { ZRTP_AUTHTAG_TYPE, {ZRTP_AUTHTAG_HS80, ZRTP_AUTHTAG_HS32}, 2, {ZRTP_AUTHTAG_HS80, ZRTP_AUTHTAG_HS32}, 2 }, { ZRTP_AUTHTAG_TYPE, {ZRTP_AUTHTAG_HS80, ZRTP_AUTHTAG_SK64}, 2, {ZRTP_AUTHTAG_HS80, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_HS32}, 3 }, { ZRTP_AUTHTAG_TYPE, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64}, 2, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_HS32, ZRTP_AUTHTAG_HS80}, 4 }, { ZRTP_AUTHTAG_TYPE, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_FAKE_1, ZRTP_AUTHTAG_FAKE_2, ZRTP_AUTHTAG_FAKE_3}, 5, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_FAKE_1, ZRTP_AUTHTAG_FAKE_2, ZRTP_AUTHTAG_FAKE_3, ZRTP_AUTHTAG_HS32, ZRTP_AUTHTAG_HS80}, 7 }, { ZRTP_AUTHTAG_TYPE, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_FAKE_1, ZRTP_AUTHTAG_FAKE_2, ZRTP_AUTHTAG_FAKE_3, ZRTP_AUTHTAG_HS80}, 6, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_FAKE_1, ZRTP_AUTHTAG_FAKE_2, ZRTP_AUTHTAG_FAKE_3, ZRTP_AUTHTAG_HS80, ZRTP_AUTHTAG_HS32}, 7 }, /* overrride */ { ZRTP_AUTHTAG_TYPE, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_FAKE_1, ZRTP_AUTHTAG_FAKE_2, ZRTP_AUTHTAG_FAKE_3, ZRTP_AUTHTAG_FAKE_4, ZRTP_AUTHTAG_FAKE_5}, 7, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_FAKE_1, ZRTP_AUTHTAG_FAKE_2, ZRTP_AUTHTAG_FAKE_3, ZRTP_AUTHTAG_HS32, ZRTP_AUTHTAG_HS80}, 7 }, { ZRTP_AUTHTAG_TYPE, {ZRTP_AUTHTAG_HS80, ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_FAKE_1, ZRTP_AUTHTAG_FAKE_2, ZRTP_AUTHTAG_FAKE_3, ZRTP_AUTHTAG_FAKE_4}, 7, {ZRTP_AUTHTAG_HS80, ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_FAKE_1, ZRTP_AUTHTAG_FAKE_2, ZRTP_AUTHTAG_FAKE_3, ZRTP_AUTHTAG_HS32}, 7 }, { ZRTP_AUTHTAG_TYPE, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_HS80, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_FAKE_1, ZRTP_AUTHTAG_FAKE_2, ZRTP_AUTHTAG_FAKE_3, ZRTP_AUTHTAG_FAKE_4}, 7, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_HS80, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_FAKE_1, ZRTP_AUTHTAG_FAKE_2, ZRTP_AUTHTAG_FAKE_3, ZRTP_AUTHTAG_HS32}, 7 }, { ZRTP_AUTHTAG_TYPE, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_HS80, ZRTP_AUTHTAG_FAKE_1, ZRTP_AUTHTAG_FAKE_2, ZRTP_AUTHTAG_FAKE_3, ZRTP_AUTHTAG_FAKE_4}, 7, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_HS80, ZRTP_AUTHTAG_FAKE_1, ZRTP_AUTHTAG_FAKE_2, ZRTP_AUTHTAG_FAKE_3, ZRTP_AUTHTAG_HS32}, 7 }, { ZRTP_AUTHTAG_TYPE, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_FAKE_1, ZRTP_AUTHTAG_HS80, ZRTP_AUTHTAG_FAKE_2, ZRTP_AUTHTAG_FAKE_3, ZRTP_AUTHTAG_FAKE_4}, 7, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_FAKE_1, ZRTP_AUTHTAG_HS80, ZRTP_AUTHTAG_FAKE_2, ZRTP_AUTHTAG_FAKE_3, ZRTP_AUTHTAG_HS32}, 7 }, { ZRTP_AUTHTAG_TYPE, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_FAKE_1, ZRTP_AUTHTAG_FAKE_2, ZRTP_AUTHTAG_HS80, ZRTP_AUTHTAG_FAKE_3, ZRTP_AUTHTAG_FAKE_4}, 7, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_FAKE_1, ZRTP_AUTHTAG_FAKE_2, ZRTP_AUTHTAG_HS80, ZRTP_AUTHTAG_FAKE_3, ZRTP_AUTHTAG_HS32}, 7 }, { ZRTP_AUTHTAG_TYPE, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_FAKE_1, ZRTP_AUTHTAG_FAKE_2, ZRTP_AUTHTAG_FAKE_3, ZRTP_AUTHTAG_HS80, ZRTP_AUTHTAG_FAKE_4}, 7, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_FAKE_1, ZRTP_AUTHTAG_FAKE_2, ZRTP_AUTHTAG_FAKE_3, ZRTP_AUTHTAG_HS80, ZRTP_AUTHTAG_HS32}, 7 }, { ZRTP_AUTHTAG_TYPE, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_FAKE_1, ZRTP_AUTHTAG_FAKE_2, ZRTP_AUTHTAG_FAKE_3, ZRTP_AUTHTAG_FAKE_4, ZRTP_AUTHTAG_HS80}, 7, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_FAKE_1, ZRTP_AUTHTAG_FAKE_2, ZRTP_AUTHTAG_FAKE_3, ZRTP_AUTHTAG_HS80, ZRTP_AUTHTAG_HS32}, 7 }, /* uniqueness */ { ZRTP_AUTHTAG_TYPE, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64}, 4, {ZRTP_AUTHTAG_SK32, ZRTP_AUTHTAG_SK64, ZRTP_AUTHTAG_HS32, ZRTP_AUTHTAG_HS80}, 4 }, { ZRTP_AUTHTAG_TYPE, {ZRTP_AUTHTAG_HS32, ZRTP_AUTHTAG_HS32, ZRTP_AUTHTAG_HS32, ZRTP_AUTHTAG_HS32}, 4, {ZRTP_AUTHTAG_HS32, ZRTP_AUTHTAG_HS80}, 2 }, { ZRTP_AUTHTAG_TYPE, {ZRTP_AUTHTAG_HS32, ZRTP_AUTHTAG_HS80, ZRTP_AUTHTAG_HS32, ZRTP_AUTHTAG_HS80}, 4, {ZRTP_AUTHTAG_HS32, ZRTP_AUTHTAG_HS80}, 2 }, { 0, {ZRTP_UNSET_ALGO}, 0, {ZRTP_UNSET_ALGO}, 0, } }; struct st_add_crypto *crypto_type; crypto_type = &crypto_types[0]; while (crypto_type->algoTypesCount > 0) { BC_ASSERT_TRUE(testAddMandatoryCryptoTypesIfNeeded(crypto_type->algoType, crypto_type->algoTypes, crypto_type->algoTypesCount, crypto_type->expectedTypes, crypto_type->expectedTypesCount)); crypto_type++; } } bzrtp-1.0.6/test/bzrtpCryptoTest.h000066400000000000000000000021661313411235300172120ustar00rootroot00000000000000/** @file bzrtpCryptoTests.h @author Johan Pascal @copyright Copyright (C) 2014 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ void test_RNG(void); void test_sha256(void); void test_hmacSha256(void); void test_aes128CFB(void); void test_dhm2048(void); void test_dhm3072(void); void test_zrtpKDF(void); void test_CRC32(void); void test_algoAgreement(void); void test_algoSetterGetter(void); void test_addMandatoryCryptoTypesIfNeeded(void); bzrtp-1.0.6/test/bzrtpParserTest.c000066400000000000000000003426421313411235300171670ustar00rootroot00000000000000/** @file bzrtpParserTests.c @brief Test parsing and building ZRTP packet. @author Johan Pascal @copyright Copyright (C) 2014 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include "bzrtp/bzrtp.h" #include "typedef.h" #include "packetParser.h" #include "cryptoUtils.h" #include "zidCache.h" #include "testUtils.h" #include #ifndef _WIN32 #include #else #include #endif /** * Test pattern : the packet data in the patternZRTPPackets, length, sequence number and SSRC in patternZRTPMetaData * Pattern generated from wireshark trace * */ #define TEST_PACKET_NUMBER 9 /* meta data: length, sequence number, SSRC */ static uint32_t patternZRTPMetaData[TEST_PACKET_NUMBER][3] = { {136, 0x09f1, 0x12345678}, /* hello */ {136, 0x02ce, 0x87654321}, /* hello */ {28, 0x09f2, 0x12345678}, /* hello ack */ {132, 0x02d0, 0x87654321}, /* commit */ {484, 0x09f5, 0x12345678}, /* dhpart1 */ {484, 0x02d1, 0x87654321}, /* dhpart2 */ {92, 0x09f6, 0x12345678}, /* confirm 1 */ {92, 0x02d2, 0x87654321}, /* confirm 2 */ {28, 0x09f7, 0x12345678} /* conf2ACK*/ }; static const uint8_t patternZRTPHelloHash12345678[70]="1.10 13e9f407367895861f0eee6707ba30aca05a0ad9997625e9279ad5d08485aa9d"; static const uint8_t patternZRTPHelloHash87654321[70]="1.10 8a286f762a00f21907fe937801894ce4f4ac6a7d2b9acd61eb25b014f905df77"; static const uint8_t patternZRTPPackets[TEST_PACKET_NUMBER][512] = { /* This is a Hello packet, sequence number is 0x09f1, SSRC 0x12345678 */ {0x10, 0x00, 0x09, 0xf1, 0x5a, 0x52, 0x54, 0x50, 0x12, 0x34, 0x56, 0x78, 0x50, 0x5a, 0x00, 0x1e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x20, 0x20, 0x31, 0x2e, 0x31, 0x30, 0x4c, 0x49, 0x4e, 0x50, 0x48, 0x4f, 0x4e, 0x45, 0x2d, 0x5a, 0x52, 0x54, 0x50, 0x43, 0x50, 0x50, 0xe8, 0xd5, 0x26, 0xc1, 0x3a, 0x0c, 0x4c, 0x6a, 0xce, 0x18, 0xaa, 0xc7, 0xc4, 0xa4, 0x07, 0x0e, 0x65, 0x7a, 0x4d, 0xca, 0x78, 0xf2, 0xcc, 0xcd, 0x20, 0x50, 0x38, 0x73, 0xe9, 0x7e, 0x08, 0x29, 0x7e, 0xb0, 0x04, 0x97, 0xc0, 0xfe, 0xb2, 0xc9, 0x24, 0x31, 0x49, 0x7f, 0x00, 0x01, 0x12, 0x31, 0x53, 0x32, 0x35, 0x36, 0x41, 0x45, 0x53, 0x31, 0x48, 0x53, 0x33, 0x32, 0x48, 0x53, 0x38, 0x30, 0x44, 0x48, 0x33, 0x6b, 0x44, 0x48, 0x32, 0x6b, 0x4d, 0x75, 0x6c, 0x74, 0x42, 0x33, 0x32, 0x20, 0xa0, 0xfd, 0x0f, 0xad, 0xeb, 0xe0, 0x86, 0x56, 0xe3, 0x65, 0x81, 0x02}, /* This is a Hello packet, sequence number is 0x02ce, SSRC 0x87654321 */ {0x10, 0x00, 0x02, 0xce, 0x5a, 0x52, 0x54, 0x50, 0x87, 0x65, 0x43, 0x21, 0x50, 0x5a, 0x00, 0x1e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x20, 0x20, 0x31, 0x2e, 0x31, 0x30, 0x4c, 0x49, 0x4e, 0x50, 0x48, 0x4f, 0x4e, 0x45, 0x2d, 0x5a, 0x52, 0x54, 0x50, 0x43, 0x50, 0x50, 0x8d, 0x0f, 0x5a, 0x20, 0x79, 0x97, 0x42, 0x01, 0x99, 0x45, 0x45, 0xf7, 0x0e, 0x31, 0x06, 0xe1, 0x05, 0xc0, 0xb9, 0x24, 0xe9, 0xc9, 0x78, 0xc7, 0x38, 0xf5, 0x97, 0x48, 0xef, 0x42, 0x6a, 0x3e, 0x92, 0x42, 0xc2, 0xcf, 0x44, 0xee, 0x9c, 0x65, 0xca, 0x58, 0x78, 0xf1, 0x00, 0x01, 0x12, 0x31, 0x53, 0x32, 0x35, 0x36, 0x41, 0x45, 0x53, 0x31, 0x48, 0x53, 0x33, 0x32, 0x48, 0x53, 0x38, 0x30, 0x44, 0x48, 0x33, 0x6b, 0x44, 0x48, 0x32, 0x6b, 0x4d, 0x75, 0x6c, 0x74, 0x42, 0x33, 0x32, 0x20, 0xb3, 0x90, 0x91, 0x95, 0xe4, 0x67, 0xa3, 0x21, 0xe3, 0x5f, 0x9c, 0x92}, /* This is a Hello ack packet, sequence number is 0x09f2, SSRC 0x12345678*/ {0x10, 0x00, 0x09, 0xf2, 0x5a, 0x52, 0x54, 0x50, 0x12, 0x34, 0x56, 0x78, 0x50, 0x5a, 0x00, 0x03, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x41, 0x43, 0x4b, 0x77, 0x0e, 0x44, 0x07}, /* This is a Commit packet, sequence number is 0x02d0, SSRC 0x87654321 */ {0x10, 0x00, 0x02, 0xd0, 0x5a, 0x52, 0x54, 0x50, 0x87, 0x65, 0x43, 0x21, 0x50, 0x5a, 0x00, 0x1d, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x20, 0x20, 0xd9, 0xff, 0x14, 0x8b, 0x34, 0xaa, 0x69, 0xe9, 0x33, 0xc1, 0x62, 0xe6, 0x6b, 0xe8, 0xcd, 0x9d, 0xe3, 0x0f, 0xb7, 0x6a, 0xe8, 0x6a, 0x62, 0x2b, 0xcb, 0xe4, 0x6b, 0x91, 0x05, 0xc7, 0xc8, 0x7e, 0x92, 0x42, 0xc2, 0xcf, 0x44, 0xee, 0x9c, 0x65, 0xca, 0x58, 0x78, 0xf1, 0x53, 0x32, 0x35, 0x36, 0x41, 0x45, 0x53, 0x31, 0x48, 0x53, 0x33, 0x32, 0x44, 0x48, 0x33, 0x6b, 0x42, 0x33, 0x32, 0x20, 0x1e, 0xc0, 0xfe, 0x2e, 0x72, 0x06, 0x4d, 0xfb, 0xfc, 0x92, 0x02, 0x8c, 0x03, 0x0f, 0xb8, 0xf8, 0x91, 0xb4, 0xe7, 0x96, 0xac, 0x25, 0xfd, 0xf9, 0x68, 0xc6, 0xe9, 0x67, 0xa9, 0x42, 0xb1, 0x5b, 0xbb, 0x6d, 0x9c, 0xd2, 0x4b, 0x13, 0xa9, 0xae, 0x25, 0x5c, 0xa9, 0xc1}, /* This is a DHPart1 packet, sequence number is 0x09f5, SSRC 0x12345678 */ {0x10, 0x00, 0x09, 0xf5, 0x5a, 0x52, 0x54, 0x50, 0x12, 0x34, 0x56, 0x78, 0x50, 0x5a, 0x00, 0x75, 0x44, 0x48, 0x50, 0x61, 0x72, 0x74, 0x31, 0x20, 0x28, 0x7c, 0x28, 0xe4, 0xd7, 0x3d, 0x14, 0x39, 0xb5, 0x6d, 0x1c, 0x47, 0x9d, 0x59, 0x0a, 0xf2, 0x10, 0x33, 0xde, 0x6b, 0xd5, 0x2b, 0xfb, 0x26, 0xa5, 0x87, 0x4d, 0xe9, 0x20, 0x6b, 0x9f, 0xdd, 0xab, 0xbc, 0xc6, 0x8d, 0xbd, 0x5d, 0xe6, 0x67, 0x00, 0x69, 0x44, 0xb1, 0x84, 0x2c, 0x27, 0x10, 0x8c, 0x4e, 0x58, 0x8a, 0xed, 0x7e, 0x8b, 0x44, 0x2c, 0x3a, 0x13, 0x02, 0xdf, 0x58, 0xb6, 0xda, 0x80, 0x55, 0xec, 0xb0, 0x20, 0xc7, 0x76, 0x50, 0xc4, 0x1b, 0xa8, 0x26, 0x11, 0x5c, 0xf5, 0x71, 0x7e, 0xb4, 0x86, 0x22, 0x17, 0xde, 0x14, 0x08, 0x46, 0x5c, 0xac, 0x88, 0x8c, 0x41, 0x6b, 0x95, 0x22, 0xba, 0xf8, 0x3e, 0x67, 0x20, 0x94, 0xa0, 0x84, 0xa3, 0x93, 0x41, 0x9a, 0x1a, 0x7c, 0x2f, 0x04, 0xf4, 0x14, 0x3f, 0x11, 0x54, 0x02, 0xba, 0xee, 0xc2, 0x20, 0xfa, 0x38, 0xf7, 0xba, 0xa4, 0xbf, 0x4a, 0x70, 0x02, 0x68, 0xdc, 0xb2, 0xe9, 0x1a, 0x8a, 0x87, 0xa5, 0xe4, 0x9c, 0x42, 0x07, 0x82, 0x26, 0xb4, 0xda, 0xe3, 0x1b, 0xdc, 0x78, 0xc7, 0xd8, 0xa8, 0x00, 0x5c, 0x00, 0x14, 0xe4, 0x00, 0xfe, 0x6c, 0x2d, 0xce, 0x62, 0xc9, 0x71, 0x5d, 0xed, 0x4e, 0x66, 0x9f, 0xf5, 0x30, 0xc0, 0x04, 0x53, 0xf6, 0x15, 0x2f, 0xe1, 0x85, 0x3b, 0xd9, 0x40, 0x9b, 0x50, 0x07, 0x43, 0x7c, 0x36, 0x01, 0xa1, 0xda, 0x66, 0xc4, 0x20, 0x2f, 0x45, 0xc0, 0xcc, 0xb2, 0x64, 0x63, 0x9c, 0x07, 0x9d, 0x23, 0x27, 0x80, 0xa1, 0x7f, 0xc2, 0xe0, 0xa0, 0xfd, 0xc3, 0x98, 0x83, 0xa3, 0xaa, 0x6b, 0xdc, 0x9f, 0x6a, 0xc3, 0x32, 0x94, 0xf0, 0x80, 0xa0, 0xd9, 0xf1, 0x83, 0x41, 0x48, 0xa9, 0xb5, 0xed, 0x62, 0x50, 0x88, 0xec, 0x33, 0x32, 0xd2, 0x5f, 0xdc, 0xcc, 0xae, 0xc9, 0x74, 0xca, 0x0a, 0xab, 0x82, 0x06, 0x01, 0x46, 0x35, 0x30, 0xcd, 0x68, 0xec, 0x09, 0xab, 0x8c, 0xb0, 0x39, 0xe5, 0xd8, 0x5c, 0xa2, 0xe4, 0x82, 0xfe, 0x46, 0x01, 0xbd, 0xe7, 0x7f, 0x60, 0x1b, 0x50, 0x62, 0xfb, 0x6f, 0xee, 0x6c, 0xf1, 0xf7, 0x9b, 0xb7, 0x1c, 0x76, 0x48, 0xb5, 0xbe, 0xa5, 0x83, 0x73, 0x07, 0xa2, 0xe2, 0x73, 0xc7, 0x68, 0x34, 0xc8, 0xef, 0x12, 0xc4, 0x32, 0xdf, 0x37, 0x3d, 0xdc, 0x07, 0x0e, 0xa6, 0x92, 0x82, 0xbd, 0xba, 0x20, 0xc4, 0xb4, 0x8d, 0x1f, 0x19, 0x1c, 0x15, 0x0f, 0x5f, 0x01, 0xdf, 0x67, 0x1f, 0x59, 0xd1, 0x5e, 0x99, 0x60, 0xf6, 0xb8, 0x67, 0xe2, 0x46, 0x62, 0x11, 0x30, 0xfb, 0x81, 0x9d, 0x0b, 0xec, 0x36, 0xe9, 0x8d, 0x43, 0xfe, 0x55, 0xd9, 0x61, 0x98, 0x3f, 0x2e, 0x39, 0x6a, 0x26, 0x43, 0xb0, 0x6d, 0x08, 0xec, 0x2e, 0x42, 0x7e, 0x23, 0x82, 0x6f, 0xd9, 0xbb, 0xfd, 0x0a, 0xcd, 0x48, 0xe7, 0xd5, 0x8b, 0xa5, 0x80, 0x34, 0xca, 0x96, 0x4f, 0x58, 0x25, 0xba, 0x43, 0x5e, 0x3d, 0x1c, 0xee, 0x72, 0xb8, 0x35, 0x8c, 0x5d, 0xd9, 0x69, 0x24, 0x58, 0x36, 0x21, 0xb0, 0x45, 0xa4, 0xad, 0x40, 0xda, 0x94, 0x98, 0x0f, 0xb1, 0xed, 0x6c, 0xad, 0x26, 0x03, 0x04, 0x82, 0xff, 0x15, 0x00, 0x41, 0x87, 0x06, 0x93, 0xd4, 0x86, 0xa9, 0x7e, 0xb8, 0xd9, 0x70, 0x34, 0x6d, 0x8e, 0x6a, 0x16, 0xe2, 0x46, 0x52, 0xb0, 0x78, 0x54, 0x53, 0xaf}, /* This is a DHPart2 packet, sequence number is 0x02d1, SSRC 0x87654321 */ {0x10, 0x00, 0x02, 0xd1, 0x5a, 0x52, 0x54, 0x50, 0x87, 0x65, 0x43, 0x21, 0x50, 0x5a, 0x00, 0x75, 0x44, 0x48, 0x50, 0x61, 0x72, 0x74, 0x32, 0x20, 0x9e, 0xb2, 0xa5, 0x8b, 0xe8, 0x96, 0x37, 0xf5, 0x5a, 0x41, 0x34, 0xb2, 0xec, 0xda, 0x84, 0x95, 0xf0, 0xf8, 0x9b, 0xab, 0x61, 0x4f, 0x7c, 0x9e, 0x56, 0xb7, 0x3b, 0xd3, 0x46, 0xba, 0xbe, 0x9a, 0xae, 0x97, 0x97, 0xda, 0x5f, 0x9f, 0x89, 0xba, 0xfe, 0x61, 0x66, 0x5f, 0x9e, 0xa4, 0x5b, 0xcb, 0xd5, 0x69, 0xcf, 0xfb, 0xfd, 0xdc, 0xac, 0x79, 0xac, 0x1d, 0x0b, 0xe5, 0x15, 0x75, 0x39, 0x2e, 0xe5, 0xa9, 0x2a, 0x60, 0xd7, 0xe3, 0x48, 0xd0, 0x1f, 0xd8, 0x61, 0x65, 0xfd, 0x2e, 0x5c, 0xef, 0x43, 0xf5, 0x63, 0x99, 0xb3, 0x45, 0x25, 0xe3, 0xbc, 0xf0, 0xe1, 0xad, 0xf7, 0x84, 0xcd, 0x82, 0x20, 0xe3, 0x6f, 0x2c, 0x77, 0x51, 0xf1, 0x11, 0x2e, 0x4a, 0x2c, 0xfd, 0x2f, 0x5e, 0x74, 0xa9, 0x37, 0x99, 0xff, 0xf7, 0x4c, 0x2d, 0xa8, 0xcf, 0x51, 0xfd, 0x5b, 0xe7, 0x51, 0x14, 0x6d, 0xbc, 0x2f, 0x5b, 0xb9, 0x77, 0x85, 0xad, 0xb4, 0x72, 0x99, 0xad, 0x7b, 0x6c, 0x6a, 0xdf, 0x4d, 0xca, 0x2f, 0xef, 0x8b, 0x5e, 0x4b, 0xf3, 0xd9, 0xfd, 0xbd, 0x47, 0x1a, 0x72, 0xe2, 0x41, 0xd8, 0xfa, 0xa1, 0x25, 0x00, 0xa3, 0xfe, 0x12, 0xda, 0xf6, 0x16, 0xb3, 0xb3, 0x08, 0x02, 0xfd, 0x0a, 0x6a, 0xab, 0x85, 0x17, 0xd7, 0x0f, 0xf4, 0x6b, 0xdf, 0x8f, 0xe2, 0x05, 0xf4, 0x5b, 0x13, 0x26, 0xa9, 0xe2, 0x57, 0xb6, 0xda, 0x76, 0x17, 0x3c, 0x52, 0x13, 0x8d, 0x83, 0xc0, 0x2b, 0xe7, 0x2e, 0xbd, 0xb0, 0xde, 0x98, 0x4f, 0x7a, 0x95, 0xa1, 0x75, 0x19, 0x6e, 0xda, 0x19, 0xff, 0x7f, 0xdd, 0x70, 0x01, 0x12, 0x3c, 0x9e, 0xd7, 0xfe, 0xc3, 0x22, 0x39, 0xce, 0x4f, 0x86, 0xd8, 0x85, 0x40, 0x75, 0xd4, 0xfe, 0x93, 0x57, 0xbc, 0x9b, 0x01, 0xa4, 0x71, 0x35, 0x70, 0x9d, 0x62, 0x91, 0x47, 0x4e, 0x32, 0xa2, 0x76, 0x16, 0x06, 0xaf, 0xc7, 0xe3, 0xe5, 0xdc, 0x25, 0xac, 0xe7, 0x68, 0x25, 0x69, 0x0f, 0x97, 0x8d, 0x91, 0x32, 0x81, 0x23, 0xb1, 0x08, 0xf3, 0xa3, 0x2b, 0x3d, 0xfb, 0xcf, 0x99, 0x12, 0x0a, 0x59, 0xb9, 0xbb, 0x76, 0x16, 0x71, 0xa2, 0x0b, 0x0a, 0x5a, 0x6c, 0x37, 0x99, 0x9d, 0xe6, 0x3a, 0x05, 0x89, 0xf7, 0xc6, 0xfc, 0xf3, 0xfe, 0x36, 0x97, 0x77, 0x86, 0xe4, 0x7c, 0x48, 0x93, 0x0b, 0x26, 0x8e, 0x31, 0xe9, 0x22, 0xcc, 0xd3, 0xe0, 0x56, 0x29, 0xc8, 0x26, 0xe6, 0x1f, 0xa8, 0xb8, 0x93, 0x98, 0xec, 0xd9, 0x7c, 0x4a, 0x45, 0xd3, 0x71, 0x35, 0x9f, 0x14, 0xc1, 0x99, 0xd5, 0x21, 0x0b, 0xfa, 0x0f, 0xfb, 0x31, 0x7a, 0xa0, 0x70, 0x35, 0xb3, 0x9b, 0x1b, 0xe7, 0x65, 0xfd, 0xe3, 0x7d, 0x0b, 0xcc, 0x34, 0x4b, 0xf1, 0x5a, 0x9f, 0x19, 0xa4, 0x8f, 0xc8, 0x30, 0xf1, 0x87, 0x99, 0xc2, 0x75, 0x55, 0x2a, 0x34, 0xd7, 0x81, 0x9c, 0x54, 0x12, 0x82, 0x69, 0x5f, 0x8b, 0x01, 0xc1, 0x45, 0x95, 0xf5, 0xb1, 0x2d, 0x27, 0x0d, 0xa9, 0xc3, 0x93, 0x54, 0x2f, 0x57, 0x04, 0x7b, 0x20, 0xb7, 0xac, 0x33, 0x68, 0xb3, 0xef, 0x9a, 0x33, 0x95, 0x82, 0x9d, 0xfa, 0x2a, 0xb9, 0x88, 0x06, 0x04, 0x88, 0x51, 0x2c, 0x46, 0xdb, 0x83, 0xd7, 0x2f, 0xea, 0x1f, 0x0f, 0x24, 0xab, 0x03, 0xef, 0xb0, 0x61, 0xc7, 0x90, 0xdc, 0x78, 0x17, 0xf2, 0x9a, 0xab}, /* This is a confirm1 packet, sequence number is 0x09f6, SSRC 0x12345678 */ {0x10, 0x00, 0x09, 0xf6, 0x5a, 0x52, 0x54, 0x50, 0x12, 0x34, 0x56, 0x78, 0x50, 0x5a, 0x00, 0x13, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x31, 0xb1, 0x21, 0xee, 0xe2, 0x67, 0xa4, 0xfd, 0xa6, 0x94, 0x24, 0x9a, 0x60, 0xf0, 0x2e, 0x5e, 0xd9, 0x33, 0xe1, 0xd8, 0x41, 0x54, 0xa3, 0x7c, 0xea, 0xe9, 0x61, 0xae, 0xf9, 0x19, 0x0d, 0xb3, 0x68, 0x68, 0x9e, 0xf8, 0x1a, 0x18, 0x91, 0x87, 0xc5, 0x6e, 0x5e, 0x2d, 0x5e, 0x32, 0xa2, 0xb2, 0x66, 0x31, 0xb8, 0xe5, 0x59, 0xc9, 0x10, 0xbb, 0xa0, 0x00, 0x6c, 0xee, 0x0c, 0x6d, 0xfb, 0xeb, 0x32, 0x85, 0xb6, 0x6e, 0x93}, /* This is a confirm2 packet, sequence number is 0x02d2, SSRC 0x87654321 */ {0x10, 0x00, 0x02, 0xd2, 0x5a, 0x52, 0x54, 0x50, 0x87, 0x65, 0x43, 0x21, 0x50, 0x5a, 0x00, 0x13, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x32, 0x0f, 0xec, 0xfa, 0x4b, 0x45, 0x17, 0x9d, 0xb3, 0x92, 0x7d, 0x1c, 0x53, 0x86, 0x01, 0x12, 0xd9, 0x25, 0x48, 0xca, 0x18, 0xb9, 0x10, 0x95, 0x04, 0xb7, 0xc8, 0xee, 0x87, 0x2b, 0xec, 0x59, 0x39, 0x92, 0x96, 0x11, 0x73, 0xa6, 0x69, 0x2b, 0x11, 0xcd, 0x1d, 0xa1, 0x73, 0xb2, 0xc9, 0x29, 0x6f, 0x82, 0x32, 0x6a, 0x0a, 0x56, 0x40, 0x57, 0xfb, 0xac, 0xab, 0x20, 0xb8, 0xe2, 0xa9, 0x2c, 0x61, 0x6a, 0x05, 0xe8, 0xb5}, /* This is a conf2ACK packet, sequence number 0x09f7, SSRC 0x12345678 */ {0x10, 0x00, 0x09, 0xf7, 0x5a, 0x52, 0x54, 0x50, 0x12, 0x34, 0x56, 0x78, 0x50, 0x5a, 0x00, 0x03, 0x43, 0x6f, 0x6e, 0x66, 0x32, 0x41, 0x43, 0x4b, 0x23, 0xc1, 0x1b, 0x45}, }; /* Hash images for both sides */ uint8_t H12345678[4][32] = { {0xbb, 0xbf, 0x7e, 0xb1, 0x14, 0xd5, 0xd4, 0x0c, 0x6b, 0xb0, 0x79, 0x58, 0x19, 0xc1, 0xd0, 0x83, 0xc9, 0xe1, 0xf4, 0x2e, 0x11, 0xcd, 0x7e, 0xc3, 0xaa, 0xd8, 0xb9, 0x17, 0xe6, 0xb5, 0x9e, 0x86}, {0x28, 0x7c, 0x28, 0xe4, 0xd7, 0x3d, 0x14, 0x39, 0xb5, 0x6d, 0x1c, 0x47, 0x9d, 0x59, 0x0a, 0xf2, 0x10, 0x33, 0xde, 0x6b, 0xd5, 0x2b, 0xfb, 0x26, 0xa5, 0x87, 0x4d, 0xe9, 0x20, 0x6b, 0x9f, 0xdd}, {0x70, 0x12, 0xef, 0x2e, 0x85, 0x2f, 0xfc, 0x84, 0xb8, 0x8d, 0xcc, 0x03, 0xd7, 0x8f, 0x53, 0x01, 0x63, 0xfb, 0xd3, 0xb0, 0x2d, 0xbb, 0x9e, 0x98, 0x22, 0x0d, 0xe3, 0xe3, 0x64, 0x25, 0x04, 0x0f}, {0xe8, 0xd5, 0x26, 0xc1, 0x3a, 0x0c, 0x4c, 0x6a, 0xce, 0x18, 0xaa, 0xc7, 0xc4, 0xa4, 0x07, 0x0e, 0x65, 0x7a, 0x4d, 0xca, 0x78, 0xf2, 0xcc, 0xcd, 0x20, 0x50, 0x38, 0x73, 0xe9, 0x7e, 0x08, 0x29} }; uint8_t H87654321[4][32] = { {0x09, 0x02, 0xcc, 0x13, 0xc4, 0x84, 0x03, 0x31, 0x68, 0x91, 0x05, 0x4d, 0xe0, 0x6d, 0xf4, 0xc9, 0x6a, 0xb5, 0xbe, 0x82, 0xe8, 0x37, 0x33, 0xb7, 0xa9, 0xce, 0xbe, 0xb5, 0x42, 0xaa, 0x54, 0xba}, {0x9e, 0xb2, 0xa5, 0x8b, 0xe8, 0x96, 0x37, 0xf5, 0x5a, 0x41, 0x34, 0xb2, 0xec, 0xda, 0x84, 0x95, 0xf0, 0xf8, 0x9b, 0xab, 0x61, 0x4f, 0x7c, 0x9e, 0x56, 0xb7, 0x3b, 0xd3, 0x46, 0xba, 0xbe, 0x9a}, {0xd9, 0xff, 0x14, 0x8b, 0x34, 0xaa, 0x69, 0xe9, 0x33, 0xc1, 0x62, 0xe6, 0x6b, 0xe8, 0xcd, 0x9d, 0xe3, 0x0f, 0xb7, 0x6a, 0xe8, 0x6a, 0x62, 0x2b, 0xcb, 0xe4, 0x6b, 0x91, 0x05, 0xc7, 0xc8, 0x7e}, {0x8d, 0x0f, 0x5a, 0x20, 0x79, 0x97, 0x42, 0x01, 0x99, 0x45, 0x45, 0xf7, 0x0e, 0x31, 0x06, 0xe1, 0x05, 0xc0, 0xb9, 0x24, 0xe9, 0xc9, 0x78, 0xc7, 0x38, 0xf5, 0x97, 0x48, 0xef, 0x42, 0x6a, 0x3e} }; /* Hello packet and matching zrtp-hash generated using libzrtpcpp */ #define ZRTPHASHPATTERN "1.10 3be3a5d605f6bc51951f6eb151a6ecbc071a9a2f4273ddd4affe5215d7300815" #define ZRTPHASHPATTERN_WRONG "1.10 00e3a5d605f6bc51951f6eb151a6ecbc071a9a2f4273ddd4affe5215d7300815" uint8_t HelloPacketZrtpHash[168] = { 0x10, 0x00, 0x00, 0x01, 0x5a, 0x52, 0x54, 0x50, 0x76, 0xdc, 0xa7, 0xbd, 0x50, 0x5a, 0x00, 0x26, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x20, 0x20, 0x31, 0x2e, 0x31, 0x30, 0x50, 0x4a, 0x53, 0x20, 0x5a, 0x52, 0x54, 0x50, 0x20, 0x33, 0x2e, 0x30, 0x2e, 0x30, 0x20, 0x20, 0xe4, 0xba, 0x78, 0xba, 0xa0, 0x2a, 0xd4, 0x36, 0x1a, 0xb8, 0xd2, 0xdd, 0x57, 0x8a, 0x68, 0x16, 0xbb, 0xe4, 0x05, 0xb8, 0x69, 0xb7, 0xaf, 0x06, 0x4d, 0x1c, 0x09, 0x53, 0x1c, 0xeb, 0xc6, 0x29, 0x20, 0x12, 0xa2, 0xf0, 0x6c, 0xfd, 0x0f, 0xfb, 0x88, 0xd8, 0xe6, 0x52, 0x00, 0x02, 0x44, 0x51, 0x53, 0x33, 0x38, 0x34, 0x53, 0x32, 0x35, 0x36, 0x32, 0x46, 0x53, 0x33, 0x41, 0x45, 0x53, 0x33, 0x32, 0x46, 0x53, 0x31, 0x41, 0x45, 0x53, 0x31, 0x53, 0x4b, 0x33, 0x32, 0x53, 0x4b, 0x36, 0x34, 0x48, 0x53, 0x33, 0x32, 0x48, 0x53, 0x38, 0x30, 0x45, 0x43, 0x32, 0x35, 0x44, 0x48, 0x33, 0x6b, 0x45, 0x43, 0x33, 0x38, 0x44, 0x48, 0x32, 0x6b, 0x4d, 0x75, 0x6c, 0x74, 0x42, 0x33, 0x32, 0x20, 0x05, 0xc9, 0xf1, 0x87, 0x2b, 0x41, 0xa9, 0x9a, 0x0a, 0x1d, 0xcd, 0x3c}; /* mac and zrtp keys */ uint8_t mackeyi[32] = {0xdc, 0x47, 0xe1, 0xc7, 0x48, 0x11, 0xb1, 0x54, 0x14, 0x2a, 0x91, 0x29, 0x9f, 0xa4, 0x8b, 0x45, 0x87, 0x16, 0x8d, 0x3a, 0xe6, 0xb0, 0x0c, 0x08, 0x4f, 0xa5, 0x48, 0xd5, 0x96, 0x67, 0x1a, 0x1b}; uint8_t mackeyr[32] = {0x3a, 0xa5, 0x22, 0x43, 0x26, 0x13, 0x8f, 0xd6, 0x54, 0x59, 0x40, 0xb8, 0x5c, 0xf4, 0x0f, 0x0c, 0xbc, 0x9c, 0x4f, 0x7d, 0x55, 0xeb, 0x4b, 0xa5, 0x1e, 0x1c, 0x42, 0xd0, 0x5e, 0xac, 0x12, 0x06}; uint8_t zrtpkeyi[16] = {0x22, 0xf6, 0xea, 0xaa, 0xa4, 0xad, 0x53, 0x30, 0x71, 0x97, 0xcc, 0x68, 0x6b, 0xb0, 0xcb, 0x55}; uint8_t zrtpkeyr[16] = {0x09, 0x50, 0xcd, 0x9e, 0xc2, 0x78, 0x54, 0x31, 0x93, 0x2e, 0x99, 0x31, 0x15, 0x58, 0xd0, 0x2a}; void test_parser_param(uint8_t hvi_trick) { int i, retval; bzrtpPacket_t *zrtpPacket; /* Create zrtp Context to use H0-H3 chains and others */ bzrtpContext_t *context87654321 = bzrtp_createBzrtpContext(); bzrtpContext_t *context12345678 = bzrtp_createBzrtpContext(); bzrtp_initBzrtpContext(context87654321, 0x87654321); bzrtp_initBzrtpContext(context12345678, 0x12345678); /* replace created H by the patterns one to be able to generate the correct packet */ memcpy (context12345678->channelContext[0]->selfH[0], H12345678[0], 32); memcpy (context12345678->channelContext[0]->selfH[1], H12345678[1], 32); memcpy (context12345678->channelContext[0]->selfH[2], H12345678[2], 32); memcpy (context12345678->channelContext[0]->selfH[3], H12345678[3], 32); memcpy (context87654321->channelContext[0]->selfH[0], H87654321[0], 32); memcpy (context87654321->channelContext[0]->selfH[1], H87654321[1], 32); memcpy (context87654321->channelContext[0]->selfH[2], H87654321[2], 32); memcpy (context87654321->channelContext[0]->selfH[3], H87654321[3], 32); /* preset the key agreement algo in the contexts */ context87654321->channelContext[0]->keyAgreementAlgo = ZRTP_KEYAGREEMENT_DH3k; context12345678->channelContext[0]->keyAgreementAlgo = ZRTP_KEYAGREEMENT_DH3k; context87654321->channelContext[0]->cipherAlgo = ZRTP_CIPHER_AES1; context12345678->channelContext[0]->cipherAlgo = ZRTP_CIPHER_AES1; context87654321->channelContext[0]->hashAlgo = ZRTP_HASH_S256; context12345678->channelContext[0]->hashAlgo = ZRTP_HASH_S256; bzrtp_updateCryptoFunctionPointers(context87654321->channelContext[0]); bzrtp_updateCryptoFunctionPointers(context12345678->channelContext[0]); /* set the zrtp and mac keys */ context87654321->channelContext[0]->mackeyi = (uint8_t *)malloc(32); context12345678->channelContext[0]->mackeyi = (uint8_t *)malloc(32); context87654321->channelContext[0]->mackeyr = (uint8_t *)malloc(32); context12345678->channelContext[0]->mackeyr = (uint8_t *)malloc(32); context87654321->channelContext[0]->zrtpkeyi = (uint8_t *)malloc(16); context12345678->channelContext[0]->zrtpkeyi = (uint8_t *)malloc(16); context87654321->channelContext[0]->zrtpkeyr = (uint8_t *)malloc(16); context12345678->channelContext[0]->zrtpkeyr = (uint8_t *)malloc(16); memcpy(context12345678->channelContext[0]->mackeyi, mackeyi, 32); memcpy(context12345678->channelContext[0]->mackeyr, mackeyr, 32); memcpy(context12345678->channelContext[0]->zrtpkeyi, zrtpkeyi, 16); memcpy(context12345678->channelContext[0]->zrtpkeyr, zrtpkeyr, 16); memcpy(context87654321->channelContext[0]->mackeyi, mackeyi, 32); memcpy(context87654321->channelContext[0]->mackeyr, mackeyr, 32); memcpy(context87654321->channelContext[0]->zrtpkeyi, zrtpkeyi, 16); memcpy(context87654321->channelContext[0]->zrtpkeyr, zrtpkeyr, 16); /* set the role: 87654321 is initiator in our exchange pattern */ context12345678->channelContext[0]->role = BZRTP_ROLE_RESPONDER; /* set the peer hello packet Hash for context 12345678, the other one will be set after Hello Packet reception */ bzrtp_setPeerHelloHash(context12345678, 0x12345678, (uint8_t *)patternZRTPHelloHash87654321, strlen((const char *)patternZRTPHelloHash87654321)); for (i=0; ichannelContext[0]:context87654321->channelContext[0], patternZRTPPackets[i], patternZRTPMetaData[i][0], zrtpPacket); if (hvi_trick==0) { BC_ASSERT_EQUAL(retval, 0, int, "%d"); if (retval != 0) goto error; } else { /* when hvi trick is enable, the DH2 parsing shall fail and return BZRTP_PARSER_ERROR_UNMATCHINGHVI */ if (zrtpPacket->messageType==MSGTYPE_DHPART2) { BC_ASSERT_EQUAL(retval, BZRTP_PARSER_ERROR_UNMATCHINGHVI, int, "%d"); goto error; } else { BC_ASSERT_EQUAL(retval, 0, int, "%d"); if (retval != 0) goto error; } } bzrtp_message("parsing Ret val is %x index is %d\n", retval, i); /* We must store some packets in the context if we want to be able to parse further packets */ /* Check also the zrtp hello hash */ if (zrtpPacket->messageType==MSGTYPE_HELLO) { if (patternZRTPMetaData[i][2]==0x87654321) { context12345678->channelContext[0]->peerPackets[HELLO_MESSAGE_STORE_ID] = zrtpPacket; context87654321->channelContext[0]->selfPackets[HELLO_MESSAGE_STORE_ID] = zrtpPacket; } else { context87654321->channelContext[0]->peerPackets[HELLO_MESSAGE_STORE_ID] = zrtpPacket; context12345678->channelContext[0]->selfPackets[HELLO_MESSAGE_STORE_ID] = zrtpPacket; /* Set the correct one */ retval = bzrtp_setPeerHelloHash(context87654321, 0x87654321, (uint8_t *)patternZRTPHelloHash12345678, strlen((const char *)patternZRTPHelloHash12345678)); BC_ASSERT_EQUAL(retval, 0, int, "%d"); if (retval != 0) goto error; } freePacketFlag = 0; } if (zrtpPacket->messageType==MSGTYPE_COMMIT) { if (patternZRTPMetaData[i][2]==0x87654321) { context12345678->channelContext[0]->peerPackets[COMMIT_MESSAGE_STORE_ID] = zrtpPacket; } else { context87654321->channelContext[0]->peerPackets[COMMIT_MESSAGE_STORE_ID] = zrtpPacket; } freePacketFlag = 0; } if (zrtpPacket->messageType==MSGTYPE_DHPART1 || zrtpPacket->messageType==MSGTYPE_DHPART2) { if (patternZRTPMetaData[i][2]==0x87654321) { context12345678->channelContext[0]->peerPackets[DHPART_MESSAGE_STORE_ID] = zrtpPacket; } else { context87654321->channelContext[0]->peerPackets[DHPART_MESSAGE_STORE_ID] = zrtpPacket; } freePacketFlag = 0; } /* free the packet string as will be created again by the packetBuild function and might have been copied by packetParser */ free(zrtpPacket->packetString); /* build a packet string from the parser packet*/ retval = bzrtp_packetBuild((patternZRTPMetaData[i][2]==0x12345678)?context12345678:context87654321, (patternZRTPMetaData[i][2]==0x12345678)?context12345678->channelContext[0]:context87654321->channelContext[0], zrtpPacket, patternZRTPMetaData[i][1]); /* if (retval ==0) { packetDump(zrtpPacket, 1); } else { bzrtp_message("Ret val is %x index is %d\n", retval, i); }*/ /* check they are the same */ if (zrtpPacket->packetString != NULL) { BC_ASSERT_TRUE(memcmp(zrtpPacket->packetString, patternZRTPPackets[i], patternZRTPMetaData[i][0]) == 0); } else { BC_FAIL("Unable to build packet"); } if (freePacketFlag == 1) { bzrtp_freeZrtpPacket(zrtpPacket); } /* modify the hvi stored in the peerPackets, this shall result in parsing failure on DH2 packet */ if (hvi_trick == 1) { if (zrtpPacket->messageType==MSGTYPE_COMMIT) { if (patternZRTPMetaData[i][2]==0x87654321) { bzrtpCommitMessage_t *peerCommitMessageData; peerCommitMessageData = (bzrtpCommitMessage_t *)zrtpPacket->messageData; peerCommitMessageData->hvi[0]=0xFF; } } } } error: /* reset pointers to selfHello packet in order to avoid double free */ context87654321->channelContext[0]->selfPackets[HELLO_MESSAGE_STORE_ID] = NULL; context12345678->channelContext[0]->selfPackets[HELLO_MESSAGE_STORE_ID] = NULL; bzrtp_destroyBzrtpContext(context87654321, 0x87654321); bzrtp_destroyBzrtpContext(context12345678, 0x12345678); } void test_parser(void) { test_parser_param(0); } void test_parser_hvi(void) { test_parser_param(1); } /* context structure mainly used by statemachine test, but also needed by parserComplete to get the zid Filename */ typedef struct my_Context_struct { unsigned char nom[30]; /* nom du contexte */ bzrtpContext_t *peerContext; bzrtpChannelContext_t *peerChannelContext; } my_Context_t; void test_parserComplete() { int retval; /* alice's maintained packet */ bzrtpPacket_t *alice_Hello, *alice_HelloFromBob, *alice_HelloACK, *alice_HelloACKFromBob; /* bob's maintained packet */ bzrtpPacket_t *bob_Hello, *bob_HelloFromAlice, *bob_HelloACK, *bob_HelloACKFromAlice; /* Create zrtp Context */ bzrtpContext_t *contextAlice = bzrtp_createBzrtpContext(); bzrtpContext_t *contextBob = bzrtp_createBzrtpContext(); bzrtpHelloMessage_t *alice_HelloFromBob_message; bzrtpHelloMessage_t *bob_HelloFromAlice_message; bzrtpPacket_t *alice_selfDHPart; bzrtpPacket_t *bob_selfDHPart; bzrtpPacket_t *alice_Commit; bzrtpPacket_t *bob_Commit; bzrtpPacket_t *bob_CommitFromAlice; bzrtpPacket_t *alice_CommitFromBob; uint8_t tmpBuffer[8]; bzrtpDHPartMessage_t *bob_DHPart1; bzrtpPacket_t *alice_DHPart1FromBob; bzrtpDHPartMessage_t *alice_DHPart1FromBob_message=NULL; bzrtpPacket_t *bob_DHPart2FromAlice; bzrtpDHPartMessage_t *bob_DHPart2FromAlice_message=NULL; uint16_t secretLength; uint16_t totalHashDataLength; uint8_t *dataToHash; uint16_t hashDataIndex = 0; uint8_t alice_totalHash[32]; /* Note : actual length of hash depends on the choosen algo */ uint8_t bob_totalHash[32]; /* Note : actual length of hash depends on the choosen algo */ uint8_t *s1=NULL; uint32_t s1Length=0; uint8_t *s2=NULL; uint32_t s2Length=0; uint8_t *s3=NULL; uint32_t s3Length=0; uint8_t alice_sasHash[32]; uint8_t bob_sasHash[32]; uint32_t sasValue; char sas[32]; bzrtpPacket_t *bob_Confirm1; bzrtpPacket_t *alice_Confirm1FromBob; bzrtpConfirmMessage_t *alice_Confirm1FromBob_message=NULL; bzrtpPacket_t *alice_Confirm2; bzrtpPacket_t *bob_Confirm2FromAlice; bzrtpConfirmMessage_t *bob_Confirm2FromAlice_message=NULL; bzrtpPacket_t *bob_Conf2ACK; bzrtpPacket_t *alice_Conf2ACKFromBob; bzrtpPacket_t *alice_Confirm1; bzrtpPacket_t *bob_Confirm1FromAlice; bzrtpConfirmMessage_t *bob_Confirm1FromAlice_message=NULL; bzrtpPacket_t *bob_Confirm2; bzrtpPacket_t *alice_Confirm2FromBob; bzrtpConfirmMessage_t *alice_Confirm2FromBob_message=NULL; bzrtpPacket_t *alice_Conf2ACK; bzrtpPacket_t *bob_Conf2ACKFromAlice; bzrtp_message ("Init the contexts\n"); /* end the context init */ bzrtp_initBzrtpContext(contextAlice, 0x12345678);/* Alice's SSRC of main channel is 12345678 */ bzrtp_initBzrtpContext(contextBob, 0x87654321); /* Bob's SSRC of main channel is 87654321 */ /* now create Alice and BOB Hello packet */ alice_Hello = bzrtp_createZrtpPacket(contextAlice, contextAlice->channelContext[0], MSGTYPE_HELLO, &retval); if (bzrtp_packetBuild(contextAlice, contextAlice->channelContext[0], alice_Hello, contextAlice->channelContext[0]->selfSequenceNumber) ==0) { contextAlice->channelContext[0]->selfSequenceNumber++; contextAlice->channelContext[0]->selfPackets[HELLO_MESSAGE_STORE_ID] = alice_Hello; } bob_Hello = bzrtp_createZrtpPacket(contextBob, contextBob->channelContext[0], MSGTYPE_HELLO, &retval); if (bzrtp_packetBuild(contextBob, contextBob->channelContext[0], bob_Hello, contextBob->channelContext[0]->selfSequenceNumber) ==0) { contextBob->channelContext[0]->selfSequenceNumber++; contextBob->channelContext[0]->selfPackets[HELLO_MESSAGE_STORE_ID] = bob_Hello; } /* now send Alice Hello's to Bob and vice-versa, so they parse them */ alice_HelloFromBob = bzrtp_packetCheck(bob_Hello->packetString, bob_Hello->messageLength+16, contextAlice->channelContext[0]->peerSequenceNumber, &retval); retval += bzrtp_packetParser(contextAlice, contextAlice->channelContext[0], bob_Hello->packetString, bob_Hello->messageLength+16, alice_HelloFromBob); bzrtp_message ("Alice parsing returns %x\n", retval); if (retval==0) { bzrtpHelloMessage_t *alice_HelloFromBob_message; int i; contextAlice->channelContext[0]->peerSequenceNumber = alice_HelloFromBob->sequenceNumber; /* save bob's Hello packet in Alice's context */ contextAlice->channelContext[0]->peerPackets[HELLO_MESSAGE_STORE_ID] = alice_HelloFromBob; /* determine crypto Algo to use */ alice_HelloFromBob_message = (bzrtpHelloMessage_t *)alice_HelloFromBob->messageData; retval = bzrtp_cryptoAlgoAgreement(contextAlice, contextAlice->channelContext[0], contextAlice->channelContext[0]->peerPackets[HELLO_MESSAGE_STORE_ID]->messageData); if (retval == 0) { bzrtp_message ("Alice selected algo %x\n", contextAlice->channelContext[0]->keyAgreementAlgo); memcpy(contextAlice->peerZID, alice_HelloFromBob_message->ZID, 12); } /* check if the peer accept MultiChannel */ for (i=0; ikc; i++) { if (alice_HelloFromBob_message->supportedKeyAgreement[i] == ZRTP_KEYAGREEMENT_Mult) { contextAlice->peerSupportMultiChannel = 1; } } } bob_HelloFromAlice = bzrtp_packetCheck(alice_Hello->packetString, alice_Hello->messageLength+16, contextBob->channelContext[0]->peerSequenceNumber, &retval); retval += bzrtp_packetParser(contextBob, contextBob->channelContext[0], alice_Hello->packetString, alice_Hello->messageLength+16, bob_HelloFromAlice); bzrtp_message ("Bob parsing returns %x\n", retval); if (retval==0) { bzrtpHelloMessage_t *bob_HelloFromAlice_message; int i; contextBob->channelContext[0]->peerSequenceNumber = bob_HelloFromAlice->sequenceNumber; /* save alice's Hello packet in bob's context */ contextBob->channelContext[0]->peerPackets[HELLO_MESSAGE_STORE_ID] = bob_HelloFromAlice; /* determine crypto Algo to use */ bob_HelloFromAlice_message = (bzrtpHelloMessage_t *)bob_HelloFromAlice->messageData; retval = bzrtp_cryptoAlgoAgreement(contextBob, contextBob->channelContext[0], contextBob->channelContext[0]->peerPackets[HELLO_MESSAGE_STORE_ID]->messageData); if (retval == 0) { bzrtp_message ("Bob selected algo %x\n", contextBob->channelContext[0]->keyAgreementAlgo); memcpy(contextBob->peerZID, bob_HelloFromAlice_message->ZID, 12); } /* check if the peer accept MultiChannel */ for (i=0; ikc; i++) { if (bob_HelloFromAlice_message->supportedKeyAgreement[i] == ZRTP_KEYAGREEMENT_Mult) { contextBob->peerSupportMultiChannel = 1; } } } /* update context with hello message information : H3 and compute initiator and responder's shared secret Hashs */ alice_HelloFromBob_message = (bzrtpHelloMessage_t *)alice_HelloFromBob->messageData; memcpy(contextAlice->channelContext[0]->peerH[3], alice_HelloFromBob_message->H3, 32); bob_HelloFromAlice_message = (bzrtpHelloMessage_t *)bob_HelloFromAlice->messageData; memcpy(contextBob->channelContext[0]->peerH[3], bob_HelloFromAlice_message->H3, 32); /* get the secrets associated to peer ZID */ bzrtp_getPeerAssociatedSecrets(contextAlice, alice_HelloFromBob_message->ZID); bzrtp_getPeerAssociatedSecrets(contextBob, bob_HelloFromAlice_message->ZID); /* compute the initiator hashed secret as in rfc section 4.3.1 */ if (contextAlice->cachedSecret.rs1!=NULL) { contextAlice->channelContext[0]->hmacFunction(contextAlice->cachedSecret.rs1, contextAlice->cachedSecret.rs1Length, (uint8_t *)"Initiator", 9, 8, contextAlice->initiatorCachedSecretHash.rs1ID); } else { /* we have no secret, generate a random */ bctbx_rng_get(contextAlice->RNGContext, contextAlice->initiatorCachedSecretHash.rs1ID, 8); } if (contextAlice->cachedSecret.rs2!=NULL) { contextAlice->channelContext[0]->hmacFunction(contextAlice->cachedSecret.rs2, contextAlice->cachedSecret.rs2Length, (uint8_t *)"Initiator", 9, 8, contextAlice->initiatorCachedSecretHash.rs2ID); } else { /* we have no secret, generate a random */ bctbx_rng_get(contextAlice->RNGContext, contextAlice->initiatorCachedSecretHash.rs2ID, 8); } if (contextAlice->cachedSecret.auxsecret!=NULL) { contextAlice->channelContext[0]->hmacFunction(contextAlice->cachedSecret.auxsecret, contextAlice->cachedSecret.auxsecretLength, contextAlice->channelContext[0]->selfH[3], 32, 8, contextAlice->channelContext[0]->initiatorAuxsecretID); } else { /* we have no secret, generate a random */ bctbx_rng_get(contextAlice->RNGContext, contextAlice->channelContext[0]->initiatorAuxsecretID, 8); } if (contextAlice->cachedSecret.pbxsecret!=NULL) { contextAlice->channelContext[0]->hmacFunction(contextAlice->cachedSecret.pbxsecret, contextAlice->cachedSecret.pbxsecretLength, (uint8_t *)"Initiator", 9, 8, contextAlice->initiatorCachedSecretHash.pbxsecretID); } else { /* we have no secret, generate a random */ bctbx_rng_get(contextAlice->RNGContext, contextAlice->initiatorCachedSecretHash.pbxsecretID, 8); } if (contextAlice->cachedSecret.rs1!=NULL) { contextAlice->channelContext[0]->hmacFunction(contextAlice->cachedSecret.rs1, contextAlice->cachedSecret.rs1Length, (uint8_t *)"Responder", 9, 8, contextAlice->responderCachedSecretHash.rs1ID); } else { /* we have no secret, generate a random */ bctbx_rng_get(contextAlice->RNGContext, contextAlice->responderCachedSecretHash.rs1ID, 8); } if (contextAlice->cachedSecret.rs2!=NULL) { contextAlice->channelContext[0]->hmacFunction(contextAlice->cachedSecret.rs2, contextAlice->cachedSecret.rs2Length, (uint8_t *)"Responder", 9, 8, contextAlice->responderCachedSecretHash.rs2ID); } else { /* we have no secret, generate a random */ bctbx_rng_get(contextAlice->RNGContext, contextAlice->responderCachedSecretHash.rs2ID, 8); } if (contextAlice->cachedSecret.auxsecret!=NULL) { contextAlice->channelContext[0]->hmacFunction(contextAlice->cachedSecret.auxsecret, contextAlice->cachedSecret.auxsecretLength, contextAlice->channelContext[0]->peerH[3], 32, 8, contextAlice->channelContext[0]->responderAuxsecretID); } else { /* we have no secret, generate a random */ bctbx_rng_get(contextAlice->RNGContext, contextAlice->channelContext[0]->responderAuxsecretID, 8); } if (contextAlice->cachedSecret.pbxsecret!=NULL) { contextAlice->channelContext[0]->hmacFunction(contextAlice->cachedSecret.pbxsecret, contextAlice->cachedSecret.pbxsecretLength, (uint8_t *)"Responder", 9, 8, contextAlice->responderCachedSecretHash.pbxsecretID); } else { /* we have no secret, generate a random */ bctbx_rng_get(contextAlice->RNGContext, contextAlice->responderCachedSecretHash.pbxsecretID, 8); } /* Bob hashes*/ if (contextBob->cachedSecret.rs1!=NULL) { contextBob->channelContext[0]->hmacFunction(contextBob->cachedSecret.rs1, contextBob->cachedSecret.rs1Length, (uint8_t *)"Initiator", 9, 8, contextBob->initiatorCachedSecretHash.rs1ID); } else { /* we have no secret, generate a random */ bctbx_rng_get(contextBob->RNGContext, contextBob->initiatorCachedSecretHash.rs1ID, 8); } if (contextBob->cachedSecret.rs2!=NULL) { contextBob->channelContext[0]->hmacFunction(contextBob->cachedSecret.rs2, contextBob->cachedSecret.rs2Length, (uint8_t *)"Initiator", 9, 8, contextBob->initiatorCachedSecretHash.rs2ID); } else { /* we have no secret, generate a random */ bctbx_rng_get(contextBob->RNGContext, contextBob->initiatorCachedSecretHash.rs2ID, 8); } if (contextBob->cachedSecret.auxsecret!=NULL) { contextBob->channelContext[0]->hmacFunction(contextBob->cachedSecret.auxsecret, contextBob->cachedSecret.auxsecretLength, contextBob->channelContext[0]->selfH[3], 32, 8, contextBob->channelContext[0]->initiatorAuxsecretID); } else { /* we have no secret, generate a random */ bctbx_rng_get(contextBob->RNGContext, contextBob->channelContext[0]->initiatorAuxsecretID, 8); } if (contextBob->cachedSecret.pbxsecret!=NULL) { contextBob->channelContext[0]->hmacFunction(contextBob->cachedSecret.pbxsecret, contextBob->cachedSecret.pbxsecretLength, (uint8_t *)"Initiator", 9, 8, contextBob->initiatorCachedSecretHash.pbxsecretID); } else { /* we have no secret, generate a random */ bctbx_rng_get(contextBob->RNGContext, contextBob->initiatorCachedSecretHash.pbxsecretID, 8); } if (contextBob->cachedSecret.rs1!=NULL) { contextBob->channelContext[0]->hmacFunction(contextBob->cachedSecret.rs1, contextBob->cachedSecret.rs1Length, (uint8_t *)"Responder", 9, 8, contextBob->responderCachedSecretHash.rs1ID); } else { /* we have no secret, generate a random */ bctbx_rng_get(contextBob->RNGContext, contextBob->responderCachedSecretHash.rs1ID, 8); } if (contextBob->cachedSecret.rs2!=NULL) { contextBob->channelContext[0]->hmacFunction(contextBob->cachedSecret.rs2, contextBob->cachedSecret.rs2Length, (uint8_t *)"Responder", 9, 8, contextBob->responderCachedSecretHash.rs2ID); } else { /* we have no secret, generate a random */ bctbx_rng_get(contextBob->RNGContext, contextBob->responderCachedSecretHash.rs2ID, 8); } if (contextBob->cachedSecret.auxsecret!=NULL) { contextBob->channelContext[0]->hmacFunction(contextBob->cachedSecret.auxsecret, contextBob->cachedSecret.auxsecretLength, contextBob->channelContext[0]->peerH[3], 32, 8, contextBob->channelContext[0]->responderAuxsecretID); } else { /* we have no secret, generate a random */ bctbx_rng_get(contextBob->RNGContext, contextBob->channelContext[0]->responderAuxsecretID, 8); } if (contextBob->cachedSecret.pbxsecret!=NULL) { contextBob->channelContext[0]->hmacFunction(contextBob->cachedSecret.pbxsecret, contextBob->cachedSecret.pbxsecretLength, (uint8_t *)"Responder", 9, 8, contextBob->responderCachedSecretHash.pbxsecretID); } else { /* we have no secret, generate a random */ bctbx_rng_get(contextBob->RNGContext, contextBob->responderCachedSecretHash.pbxsecretID, 8); } /* dump alice's packet on both sides */ bzrtp_message ("\nAlice original Packet is \n"); packetDump(alice_Hello, 1); bzrtp_message ("\nBob's parsed Alice Packet is \n"); packetDump(bob_HelloFromAlice, 0); /* Create the DHPart2 packet (that we then may change to DHPart1 if we ended to be the responder) */ alice_selfDHPart = bzrtp_createZrtpPacket(contextAlice, contextAlice->channelContext[0], MSGTYPE_DHPART2, &retval); retval += bzrtp_packetBuild(contextAlice, contextAlice->channelContext[0], alice_selfDHPart, 0); /* we don't care now about sequence number as we just need to build the message to be able to insert a hash of it into the commit packet */ if (retval == 0) { /* ok, insert it in context as we need it to build the commit packet */ contextAlice->channelContext[0]->selfPackets[DHPART_MESSAGE_STORE_ID] = alice_selfDHPart; } else { bzrtp_message ("Alice building DHPart packet returns %x\n", retval); } bob_selfDHPart = bzrtp_createZrtpPacket(contextBob, contextBob->channelContext[0], MSGTYPE_DHPART2, &retval); retval +=bzrtp_packetBuild(contextBob, contextBob->channelContext[0], bob_selfDHPart, 0); /* we don't care now about sequence number as we just need to build the message to be able to insert a hash of it into the commit packet */ if (retval == 0) { /* ok, insert it in context as we need it to build the commit packet */ contextBob->channelContext[0]->selfPackets[DHPART_MESSAGE_STORE_ID] = bob_selfDHPart; } else { bzrtp_message ("Bob building DHPart packet returns %x\n", retval); } bzrtp_message("Alice DHPart packet:\n"); packetDump(alice_selfDHPart,0); bzrtp_message("Bob DHPart packet:\n"); packetDump(bob_selfDHPart,0); /* respond to HELLO packet with an HelloACK - 1 create packets */ alice_HelloACK = bzrtp_createZrtpPacket(contextAlice, contextAlice->channelContext[0], MSGTYPE_HELLOACK, &retval); retval += bzrtp_packetBuild(contextAlice, contextAlice->channelContext[0], alice_HelloACK, contextAlice->channelContext[0]->selfSequenceNumber); if (retval == 0) { contextAlice->channelContext[0]->selfSequenceNumber++; } else { bzrtp_message("Alice building HelloACK return %x\n", retval); } bob_HelloACK = bzrtp_createZrtpPacket(contextBob, contextBob->channelContext[0], MSGTYPE_HELLOACK, &retval); retval += bzrtp_packetBuild(contextBob, contextBob->channelContext[0], bob_HelloACK, contextBob->channelContext[0]->selfSequenceNumber); if (retval == 0) { contextBob->channelContext[0]->selfSequenceNumber++; } else { bzrtp_message("Bob building HelloACK return %x\n", retval); } /* exchange the HelloACK */ alice_HelloACKFromBob = bzrtp_packetCheck(bob_HelloACK->packetString, bob_HelloACK->messageLength+16, contextAlice->channelContext[0]->peerSequenceNumber, &retval); retval += bzrtp_packetParser(contextAlice, contextAlice->channelContext[0], bob_HelloACK->packetString, bob_HelloACK->messageLength+16, alice_HelloACKFromBob); bzrtp_message ("Alice parsing Hello ACK returns %x\n", retval); if (retval==0) { contextAlice->channelContext[0]->peerSequenceNumber = alice_HelloACKFromBob->sequenceNumber; } bob_HelloACKFromAlice = bzrtp_packetCheck(alice_HelloACK->packetString, alice_HelloACK->messageLength+16, contextBob->channelContext[0]->peerSequenceNumber, &retval); retval += bzrtp_packetParser(contextBob, contextBob->channelContext[0], alice_HelloACK->packetString, alice_HelloACK->messageLength+16, bob_HelloACKFromAlice); bzrtp_message ("Bob parsing Hello ACK returns %x\n", retval); if (retval==0) { contextBob->channelContext[0]->peerSequenceNumber = bob_HelloACKFromAlice->sequenceNumber; } bzrtp_freeZrtpPacket(alice_HelloACK); bzrtp_freeZrtpPacket(bob_HelloACK); bzrtp_freeZrtpPacket(alice_HelloACKFromBob); bzrtp_freeZrtpPacket(bob_HelloACKFromAlice); /* now build the commit message (both Alice and Bob will send it, then use the mechanism of rfc section 4.2 to determine who will be the initiator)*/ alice_Commit = bzrtp_createZrtpPacket(contextAlice, contextAlice->channelContext[0], MSGTYPE_COMMIT, &retval); retval += bzrtp_packetBuild(contextAlice, contextAlice->channelContext[0], alice_Commit, contextAlice->channelContext[0]->selfSequenceNumber); if (retval == 0) { contextAlice->channelContext[0]->selfSequenceNumber++; contextAlice->channelContext[0]->selfPackets[COMMIT_MESSAGE_STORE_ID] = alice_Commit; } bzrtp_message("Alice building Commit return %x\n", retval); bob_Commit = bzrtp_createZrtpPacket(contextBob, contextBob->channelContext[0], MSGTYPE_COMMIT, &retval); retval += bzrtp_packetBuild(contextBob, contextBob->channelContext[0], bob_Commit, contextBob->channelContext[0]->selfSequenceNumber); if (retval == 0) { contextBob->channelContext[0]->selfSequenceNumber++; contextBob->channelContext[0]->selfPackets[COMMIT_MESSAGE_STORE_ID] = bob_Commit; } bzrtp_message("Bob building Commit return %x\n", retval); /* and exchange the commits */ bob_CommitFromAlice = bzrtp_packetCheck(alice_Commit->packetString, alice_Commit->messageLength+16, contextBob->channelContext[0]->peerSequenceNumber, &retval); retval += bzrtp_packetParser(contextBob, contextBob->channelContext[0], alice_Commit->packetString, alice_Commit->messageLength+16, bob_CommitFromAlice); bzrtp_message ("Bob parsing Commit returns %x\n", retval); if (retval==0) { /* update context with the information found in the packet */ bzrtpCommitMessage_t *bob_CommitFromAlice_message = (bzrtpCommitMessage_t *)bob_CommitFromAlice->messageData; contextBob->channelContext[0]->peerSequenceNumber = bob_CommitFromAlice->sequenceNumber; memcpy(contextBob->channelContext[0]->peerH[2], bob_CommitFromAlice_message->H2, 32); contextBob->channelContext[0]->peerPackets[COMMIT_MESSAGE_STORE_ID] = bob_CommitFromAlice; } packetDump(bob_CommitFromAlice, 0); alice_CommitFromBob = bzrtp_packetCheck(bob_Commit->packetString, bob_Commit->messageLength+16, contextAlice->channelContext[0]->peerSequenceNumber, &retval); retval += bzrtp_packetParser(contextAlice, contextAlice->channelContext[0], bob_Commit->packetString, bob_Commit->messageLength+16, alice_CommitFromBob); bzrtp_message ("Alice parsing Commit returns %x\n", retval); if (retval==0) { /* update context with the information found in the packet */ contextAlice->channelContext[0]->peerSequenceNumber = alice_CommitFromBob->sequenceNumber; /* Alice will be the initiator (commit contention not implemented in this test) so just discard bob's commit */ /*bzrtpCommirMessage_t *alice_CommitFromBob_message = (bzrtpCommitMessage_t *)alice_CommitFromBob->messageData; memcpy(contextAlice->channelContext[0]->peerH[2], alice_CommitFromBob_message->H2, 32); contextAlice->channelContext[0]->peerPackets[COMMIT_MESSAGE_STORE_ID] = alice_CommitFromBob;*/ } packetDump(alice_CommitFromBob, 0); bzrtp_freeZrtpPacket(alice_CommitFromBob); /* Now determine who shall be the initiator : rfc section 4.2 */ /* select the one with the lowest value of hvi */ /* for test purpose, we will set Alice as the initiator */ contextBob->channelContext[0]->role = BZRTP_ROLE_RESPONDER; /* Bob (responder) shall update his selected algo list to match Alice selection */ /* no need to do this here as we have the same selection */ /* Bob is the responder, rebuild his DHPart packet to be responder and not initiator : */ /* as responder, bob must also swap his aux shared secret between responder and initiator as they are computed using the H3 and not a constant string */ memcpy(tmpBuffer, contextBob->channelContext[0]->initiatorAuxsecretID, 8); memcpy(contextBob->channelContext[0]->initiatorAuxsecretID, contextBob->channelContext[0]->responderAuxsecretID, 8); memcpy(contextBob->channelContext[0]->responderAuxsecretID, tmpBuffer, 8); contextBob->channelContext[0]->selfPackets[DHPART_MESSAGE_STORE_ID]->messageType = MSGTYPE_DHPART1; /* we are now part 1*/ bob_DHPart1 = (bzrtpDHPartMessage_t *)contextBob->channelContext[0]->selfPackets[DHPART_MESSAGE_STORE_ID]->messageData; /* change the shared secret ID to the responder one (we set them by default to the initiator's one) */ memcpy(bob_DHPart1->rs1ID, contextBob->responderCachedSecretHash.rs1ID, 8); memcpy(bob_DHPart1->rs2ID, contextBob->responderCachedSecretHash.rs2ID, 8); memcpy(bob_DHPart1->auxsecretID, contextBob->channelContext[0]->responderAuxsecretID, 8); memcpy(bob_DHPart1->pbxsecretID, contextBob->responderCachedSecretHash.pbxsecretID, 8); retval +=bzrtp_packetBuild(contextBob, contextBob->channelContext[0], contextBob->channelContext[0]->selfPackets[DHPART_MESSAGE_STORE_ID],contextBob->channelContext[0]->selfSequenceNumber); if (retval == 0) { contextBob->channelContext[0]->selfSequenceNumber++; } bzrtp_message("Bob building DHPart1 return %x\n", retval); /* Alice parse bob's DHPart1 message */ alice_DHPart1FromBob = bzrtp_packetCheck(contextBob->channelContext[0]->selfPackets[DHPART_MESSAGE_STORE_ID]->packetString, contextBob->channelContext[0]->selfPackets[DHPART_MESSAGE_STORE_ID]->messageLength+16, contextAlice->channelContext[0]->peerSequenceNumber, &retval); retval += bzrtp_packetParser(contextAlice, contextAlice->channelContext[0], contextBob->channelContext[0]->selfPackets[DHPART_MESSAGE_STORE_ID]->packetString, contextBob->channelContext[0]->selfPackets[DHPART_MESSAGE_STORE_ID]->messageLength+16, alice_DHPart1FromBob); bzrtp_message ("Alice parsing DHPart1 returns %x\n", retval); if (retval==0) { /* update context with the information found in the packet */ contextAlice->channelContext[0]->peerSequenceNumber = alice_DHPart1FromBob->sequenceNumber; alice_DHPart1FromBob_message = (bzrtpDHPartMessage_t *)alice_DHPart1FromBob->messageData; memcpy(contextAlice->channelContext[0]->peerH[1], alice_DHPart1FromBob_message->H1, 32); contextAlice->channelContext[0]->peerPackets[DHPART_MESSAGE_STORE_ID] = alice_DHPart1FromBob; } packetDump(alice_DHPart1FromBob, 1); /* Now Alice may check which shared secret she expected and if they are valid in bob's DHPart1 */ if (contextAlice->cachedSecret.rs1!=NULL) { if (memcmp(contextAlice->responderCachedSecretHash.rs1ID, alice_DHPart1FromBob_message->rs1ID,8) != 0) { bzrtp_message ("Alice found that requested shared secret rs1 ID differs!\n"); } else { bzrtp_message("Alice validate rs1ID from bob DHPart1\n"); } } if (contextAlice->cachedSecret.rs2!=NULL) { if (memcmp(contextAlice->responderCachedSecretHash.rs2ID, alice_DHPart1FromBob_message->rs2ID,8) != 0) { bzrtp_message ("Alice found that requested shared secret rs2 ID differs!\n"); } else { bzrtp_message("Alice validate rs2ID from bob DHPart1\n"); } } if (contextAlice->cachedSecret.auxsecret!=NULL) { if (memcmp(contextAlice->channelContext[0]->responderAuxsecretID, alice_DHPart1FromBob_message->auxsecretID,8) != 0) { bzrtp_message ("Alice found that requested shared secret aux secret ID differs!\n"); } else { bzrtp_message("Alice validate aux secret ID from bob DHPart1\n"); } } if (contextAlice->cachedSecret.pbxsecret!=NULL) { if (memcmp(contextAlice->responderCachedSecretHash.pbxsecretID, alice_DHPart1FromBob_message->pbxsecretID,8) != 0) { bzrtp_message ("Alice found that requested shared secret pbx secret ID differs!\n"); } else { bzrtp_message("Alice validate pbxsecretID from bob DHPart1\n"); } } /* Now Alice shall check that the PV from bob is not 1 or Prime-1 TODO*/ /* Compute the shared DH secret */ contextAlice->DHMContext->peer = (uint8_t *)malloc(contextAlice->channelContext[0]->keyAgreementLength*sizeof(uint8_t)); memcpy (contextAlice->DHMContext->peer, alice_DHPart1FromBob_message->pv, contextAlice->channelContext[0]->keyAgreementLength); bctbx_DHMComputeSecret(contextAlice->DHMContext, (int (*)(void *, uint8_t *, size_t))bctbx_rng_get, (void *)contextAlice->RNGContext); /* So Alice send bob her DHPart2 message which is already prepared and stored (we just need to update the sequence number) */ bzrtp_packetUpdateSequenceNumber(contextAlice->channelContext[0]->selfPackets[DHPART_MESSAGE_STORE_ID], contextAlice->channelContext[0]->selfSequenceNumber); contextAlice->channelContext[0]->selfSequenceNumber++; /* Bob parse Alice's DHPart2 message */ bob_DHPart2FromAlice = bzrtp_packetCheck(contextAlice->channelContext[0]->selfPackets[DHPART_MESSAGE_STORE_ID]->packetString, contextAlice->channelContext[0]->selfPackets[DHPART_MESSAGE_STORE_ID]->messageLength+16, contextBob->channelContext[0]->peerSequenceNumber, &retval); bzrtp_message ("Bob checking DHPart2 returns %x\n", retval); retval += bzrtp_packetParser(contextBob, contextBob->channelContext[0], contextAlice->channelContext[0]->selfPackets[DHPART_MESSAGE_STORE_ID]->packetString, contextAlice->channelContext[0]->selfPackets[DHPART_MESSAGE_STORE_ID]->messageLength+16, bob_DHPart2FromAlice); bzrtp_message ("Bob parsing DHPart2 returns %x\n", retval); if (retval==0) { /* update context with the information found in the packet */ contextBob->channelContext[0]->peerSequenceNumber = bob_DHPart2FromAlice->sequenceNumber; bob_DHPart2FromAlice_message = (bzrtpDHPartMessage_t *)bob_DHPart2FromAlice->messageData; memcpy(contextBob->channelContext[0]->peerH[1], bob_DHPart2FromAlice_message->H1, 32); contextBob->channelContext[0]->peerPackets[DHPART_MESSAGE_STORE_ID] = bob_DHPart2FromAlice; } packetDump(bob_DHPart2FromAlice, 0); /* Now Bob may check which shared secret she expected and if they are valid in bob's DHPart1 */ if (contextBob->cachedSecret.rs1!=NULL) { if (memcmp(contextBob->initiatorCachedSecretHash.rs1ID, bob_DHPart2FromAlice_message->rs1ID,8) != 0) { bzrtp_message ("Bob found that requested shared secret rs1 ID differs!\n"); } else { bzrtp_message("Bob validate rs1ID from Alice DHPart2\n"); } } if (contextBob->cachedSecret.rs2!=NULL) { if (memcmp(contextBob->initiatorCachedSecretHash.rs2ID, bob_DHPart2FromAlice_message->rs2ID,8) != 0) { bzrtp_message ("Bob found that requested shared secret rs2 ID differs!\n"); } else { bzrtp_message("Bob validate rs2ID from Alice DHPart2\n"); } } if (contextBob->cachedSecret.auxsecret!=NULL) { if (memcmp(contextBob->channelContext[0]->initiatorAuxsecretID, bob_DHPart2FromAlice_message->auxsecretID,8) != 0) { bzrtp_message ("Bob found that requested shared secret aux secret ID differs!\n"); } else { bzrtp_message("Bob validate aux secret ID from Alice DHPart2\n"); } } if (contextBob->cachedSecret.pbxsecret!=NULL) { if (memcmp(contextBob->initiatorCachedSecretHash.pbxsecretID, bob_DHPart2FromAlice_message->pbxsecretID,8) != 0) { bzrtp_message ("Bob found that requested shared secret pbx secret ID differs!\n"); } else { bzrtp_message("Bob validate pbxsecretID from Alice DHPart2\n"); } } /* Now Bob shall check that the PV from Alice is not 1 or Prime-1 TODO*/ /* Compute the shared DH secret */ contextBob->DHMContext->peer = (uint8_t *)malloc(contextBob->channelContext[0]->keyAgreementLength*sizeof(uint8_t)); memcpy (contextBob->DHMContext->peer, bob_DHPart2FromAlice_message->pv, contextBob->channelContext[0]->keyAgreementLength); bctbx_DHMComputeSecret(contextBob->DHMContext, (int (*)(void *, uint8_t *, size_t))bctbx_rng_get, (void *)contextAlice->RNGContext); /* JUST FOR TEST: check that the generated secrets are the same */ secretLength = bob_DHPart2FromAlice->messageLength-84; /* length of generated secret is the same than public value */ if (memcmp(contextBob->DHMContext->key, contextAlice->DHMContext->key, secretLength)==0) { bzrtp_message("Secret Key correctly exchanged \n"); BC_PASS("Secret Key exchange OK"); } else { BC_FAIL("Secret Key exchange failed"); bzrtp_message("ERROR : secretKey exchange failed!!\n"); } /* now compute the total_hash as in rfc section 4.4.1.4 * total_hash = hash(Hello of responder || Commit || DHPart1 || DHPart2) */ totalHashDataLength = bob_Hello->messageLength + alice_Commit->messageLength + contextBob->channelContext[0]->selfPackets[DHPART_MESSAGE_STORE_ID]->messageLength + alice_selfDHPart->messageLength; dataToHash = (uint8_t *)malloc(totalHashDataLength*sizeof(uint8_t)); /* get all data from Alice */ memcpy(dataToHash, contextAlice->channelContext[0]->peerPackets[HELLO_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, contextAlice->channelContext[0]->peerPackets[HELLO_MESSAGE_STORE_ID]->messageLength); hashDataIndex += contextAlice->channelContext[0]->peerPackets[HELLO_MESSAGE_STORE_ID]->messageLength; memcpy(dataToHash+hashDataIndex, contextAlice->channelContext[0]->selfPackets[COMMIT_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, contextAlice->channelContext[0]->selfPackets[COMMIT_MESSAGE_STORE_ID]->messageLength); hashDataIndex += contextAlice->channelContext[0]->selfPackets[COMMIT_MESSAGE_STORE_ID]->messageLength; memcpy(dataToHash+hashDataIndex, contextAlice->channelContext[0]->peerPackets[DHPART_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, contextAlice->channelContext[0]->peerPackets[DHPART_MESSAGE_STORE_ID]->messageLength); hashDataIndex += contextAlice->channelContext[0]->peerPackets[DHPART_MESSAGE_STORE_ID]->messageLength; memcpy(dataToHash+hashDataIndex, contextAlice->channelContext[0]->selfPackets[DHPART_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, contextAlice->channelContext[0]->selfPackets[DHPART_MESSAGE_STORE_ID]->messageLength); contextAlice->channelContext[0]->hashFunction(dataToHash, totalHashDataLength, 32, alice_totalHash); /* get all data from Bob */ hashDataIndex = 0; memcpy(dataToHash, contextBob->channelContext[0]->selfPackets[HELLO_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, contextBob->channelContext[0]->selfPackets[HELLO_MESSAGE_STORE_ID]->messageLength); hashDataIndex += contextBob->channelContext[0]->selfPackets[HELLO_MESSAGE_STORE_ID]->messageLength; memcpy(dataToHash+hashDataIndex, contextBob->channelContext[0]->peerPackets[COMMIT_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, contextBob->channelContext[0]->peerPackets[COMMIT_MESSAGE_STORE_ID]->messageLength); hashDataIndex += contextBob->channelContext[0]->peerPackets[COMMIT_MESSAGE_STORE_ID]->messageLength; memcpy(dataToHash+hashDataIndex, contextBob->channelContext[0]->selfPackets[DHPART_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, contextBob->channelContext[0]->selfPackets[DHPART_MESSAGE_STORE_ID]->messageLength); hashDataIndex += contextBob->channelContext[0]->selfPackets[DHPART_MESSAGE_STORE_ID]->messageLength; memcpy(dataToHash+hashDataIndex, contextBob->channelContext[0]->peerPackets[DHPART_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, contextBob->channelContext[0]->peerPackets[DHPART_MESSAGE_STORE_ID]->messageLength); contextBob->channelContext[0]->hashFunction(dataToHash, totalHashDataLength, 32, bob_totalHash); if (memcmp(bob_totalHash, alice_totalHash, 32) == 0) { bzrtp_message("Got the same total hash\n"); BC_PASS("Total Hash match"); } else { bzrtp_message("AARGG!! total hash mismatch"); BC_FAIL("Total Hash mismatch"); } /* now compute s0 and KDF_context as in rfc section 4.4.1.4 s0 = hash(counter || DHResult || "ZRTP-HMAC-KDF" || ZIDi || ZIDr || total_hash || len(s1) || s1 || len(s2) || s2 || len(s3) || s3) counter is a fixed 32 bits integer in big endian set to 1 : 0x00000001 */ free(dataToHash); contextAlice->channelContext[0]->KDFContextLength = 24+32;/* actual depends on selected hash length*/ contextAlice->channelContext[0]->KDFContext = (uint8_t *)malloc(contextAlice->channelContext[0]->KDFContextLength*sizeof(uint8_t)); memcpy(contextAlice->channelContext[0]->KDFContext, contextAlice->selfZID, 12); /* ZIDi*/ memcpy(contextAlice->channelContext[0]->KDFContext+12, contextAlice->peerZID, 12); /* ZIDr */ memcpy(contextAlice->channelContext[0]->KDFContext+24, alice_totalHash, 32); /* total Hash*/ /* get s1 from rs1 or rs2 */ if (contextAlice->cachedSecret.rs1 != NULL) { /* if there is a s1 (already validated when received the DHpacket) */ s1 = contextAlice->cachedSecret.rs1; s1Length = contextAlice->cachedSecret.rs1Length; } else if (contextAlice->cachedSecret.rs2 != NULL) { /* otherwise if there is a s2 (already validated when received the DHpacket) */ s1 = contextAlice->cachedSecret.rs2; s1Length = contextAlice->cachedSecret.rs2Length; } /* s2 is the auxsecret */ s2 = contextAlice->cachedSecret.auxsecret; /* this may be null if no match or no aux secret where found */ s2Length = contextAlice->cachedSecret.auxsecretLength; /* this may be 0 if no match or no aux secret where found */ /* s3 is the pbxsecret */ s3 = contextAlice->cachedSecret.pbxsecret; /* this may be null if no match or no pbx secret where found */ s3Length = contextAlice->cachedSecret.pbxsecretLength; /* this may be 0 if no match or no pbx secret where found */ totalHashDataLength = 4+secretLength+13/*ZRTP-HMAC-KDF string*/ + 12 + 12 + 32 + 4 +s1Length + 4 +s2Length + 4 + s3Length; /* secret length was computed before as the length of DH secret data */ dataToHash = (uint8_t *)malloc(totalHashDataLength*sizeof(uint8_t)); dataToHash[0] = 0x00; dataToHash[1] = 0x00; dataToHash[2] = 0x00; dataToHash[3] = 0x01; hashDataIndex = 4; memcpy(dataToHash+hashDataIndex, contextAlice->DHMContext->key, secretLength); hashDataIndex += secretLength; memcpy(dataToHash+hashDataIndex, "ZRTP-HMAC-KDF", 13); hashDataIndex += 13; memcpy(dataToHash+hashDataIndex, contextAlice->channelContext[0]->KDFContext, contextAlice->channelContext[0]->KDFContextLength); hashDataIndex += 56; dataToHash[hashDataIndex++] = (uint8_t)((s1Length>>24)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)((s1Length>>16)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)((s1Length>>8)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)(s1Length&0xFF); if (s1!=NULL) { memcpy(dataToHash+hashDataIndex, s1, s1Length); hashDataIndex += s1Length; } dataToHash[hashDataIndex++] = (uint8_t)((s2Length>>24)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)((s2Length>>16)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)((s2Length>>8)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)(s2Length&0xFF); if (s2!=NULL) { memcpy(dataToHash+hashDataIndex, s2, s2Length); hashDataIndex += s2Length; } dataToHash[hashDataIndex++] = (uint8_t)((s3Length>>24)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)((s3Length>>16)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)((s3Length>>8)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)(s3Length&0xFF); if (s3!=NULL) { memcpy(dataToHash+hashDataIndex, s3, s3Length); hashDataIndex += s3Length; } contextAlice->channelContext[0]->s0 = (uint8_t *)malloc(32*sizeof(uint8_t)); contextAlice->channelContext[0]->hashFunction(dataToHash, totalHashDataLength, 32, contextAlice->channelContext[0]->s0); /* destroy all cached keys in context */ if (contextAlice->cachedSecret.rs1!=NULL) { bzrtp_DestroyKey(contextAlice->cachedSecret.rs1, contextAlice->cachedSecret.rs1Length, contextAlice->RNGContext); free(contextAlice->cachedSecret.rs1); contextAlice->cachedSecret.rs1 = NULL; } if (contextAlice->cachedSecret.rs2!=NULL) { bzrtp_DestroyKey(contextAlice->cachedSecret.rs2, contextAlice->cachedSecret.rs2Length, contextAlice->RNGContext); free(contextAlice->cachedSecret.rs2); contextAlice->cachedSecret.rs2 = NULL; } if (contextAlice->cachedSecret.auxsecret!=NULL) { bzrtp_DestroyKey(contextAlice->cachedSecret.auxsecret, contextAlice->cachedSecret.auxsecretLength, contextAlice->RNGContext); free(contextAlice->cachedSecret.auxsecret); contextAlice->cachedSecret.auxsecret = NULL; } if (contextAlice->cachedSecret.pbxsecret!=NULL) { bzrtp_DestroyKey(contextAlice->cachedSecret.pbxsecret, contextAlice->cachedSecret.pbxsecretLength, contextAlice->RNGContext); free(contextAlice->cachedSecret.pbxsecret); contextAlice->cachedSecret.pbxsecret = NULL; } /*** Do the same for bob ***/ /* get s1 from rs1 or rs2 */ s1=NULL; s2=NULL; s3=NULL; contextBob->channelContext[0]->KDFContextLength = 24+32;/* actual depends on selected hash length*/ contextBob->channelContext[0]->KDFContext = (uint8_t *)malloc(contextBob->channelContext[0]->KDFContextLength*sizeof(uint8_t)); memcpy(contextBob->channelContext[0]->KDFContext, contextBob->peerZID, 12); /* ZIDi*/ memcpy(contextBob->channelContext[0]->KDFContext+12, contextBob->selfZID, 12); /* ZIDr */ memcpy(contextBob->channelContext[0]->KDFContext+24, bob_totalHash, 32); /* total Hash*/ if (contextBob->cachedSecret.rs1 != NULL) { /* if there is a s1 (already validated when received the DHpacket) */ s1 = contextBob->cachedSecret.rs1; s1Length = contextBob->cachedSecret.rs1Length; } else if (contextBob->cachedSecret.rs2 != NULL) { /* otherwise if there is a s2 (already validated when received the DHpacket) */ s1 = contextBob->cachedSecret.rs2; s1Length = contextBob->cachedSecret.rs2Length; } /* s2 is the auxsecret */ s2 = contextBob->cachedSecret.auxsecret; /* this may be null if no match or no aux secret where found */ s2Length = contextBob->cachedSecret.auxsecretLength; /* this may be 0 if no match or no aux secret where found */ /* s3 is the pbxsecret */ s3 = contextBob->cachedSecret.pbxsecret; /* this may be null if no match or no pbx secret where found */ s3Length = contextBob->cachedSecret.pbxsecretLength; /* this may be 0 if no match or no pbx secret where found */ free(dataToHash); dataToHash = (uint8_t *)malloc(totalHashDataLength*sizeof(uint8_t)); dataToHash[0] = 0x00; dataToHash[1] = 0x00; dataToHash[2] = 0x00; dataToHash[3] = 0x01; hashDataIndex = 4; memcpy(dataToHash+hashDataIndex, contextBob->DHMContext->key, secretLength); hashDataIndex += secretLength; memcpy(dataToHash+hashDataIndex, "ZRTP-HMAC-KDF", 13); hashDataIndex += 13; memcpy(dataToHash+hashDataIndex, contextBob->channelContext[0]->KDFContext, contextBob->channelContext[0]->KDFContextLength); hashDataIndex += 56; dataToHash[hashDataIndex++] = (uint8_t)((s1Length>>24)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)((s1Length>>16)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)((s1Length>>8)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)(s1Length&0xFF); if (s1!=NULL) { memcpy(dataToHash+hashDataIndex, s1, s1Length); hashDataIndex += s1Length; } dataToHash[hashDataIndex++] = (uint8_t)((s2Length>>24)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)((s2Length>>16)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)((s2Length>>8)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)(s2Length&0xFF); if (s2!=NULL) { memcpy(dataToHash+hashDataIndex, s2, s2Length); hashDataIndex += s2Length; } dataToHash[hashDataIndex++] = (uint8_t)((s3Length>>24)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)((s3Length>>16)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)((s3Length>>8)&0xFF); dataToHash[hashDataIndex++] = (uint8_t)(s3Length&0xFF); if (s3!=NULL) { memcpy(dataToHash+hashDataIndex, s3, s3Length); hashDataIndex += s3Length; } contextBob->channelContext[0]->s0 = (uint8_t *)malloc(32*sizeof(uint8_t)); contextBob->channelContext[0]->hashFunction(dataToHash, totalHashDataLength, 32, contextBob->channelContext[0]->s0); free(dataToHash); /* destroy all cached keys in context */ if (contextBob->cachedSecret.rs1!=NULL) { bzrtp_DestroyKey(contextBob->cachedSecret.rs1, contextBob->cachedSecret.rs1Length, contextBob->RNGContext); free(contextBob->cachedSecret.rs1); contextBob->cachedSecret.rs1 = NULL; } if (contextBob->cachedSecret.rs2!=NULL) { bzrtp_DestroyKey(contextBob->cachedSecret.rs2, contextBob->cachedSecret.rs2Length, contextBob->RNGContext); free(contextBob->cachedSecret.rs2); contextBob->cachedSecret.rs2 = NULL; } if (contextBob->cachedSecret.auxsecret!=NULL) { bzrtp_DestroyKey(contextBob->cachedSecret.auxsecret, contextBob->cachedSecret.auxsecretLength, contextBob->RNGContext); free(contextBob->cachedSecret.auxsecret); contextBob->cachedSecret.auxsecret = NULL; } if (contextBob->cachedSecret.pbxsecret!=NULL) { bzrtp_DestroyKey(contextBob->cachedSecret.pbxsecret, contextBob->cachedSecret.pbxsecretLength, contextBob->RNGContext); free(contextBob->cachedSecret.pbxsecret); contextBob->cachedSecret.pbxsecret = NULL; } /* DEBUG compare s0 */ if (memcmp(contextBob->channelContext[0]->s0, contextAlice->channelContext[0]->s0, 32)==0) { bzrtp_message("Got the same s0\n"); BC_PASS("s0 match"); } else { bzrtp_message("ERROR s0 differs\n"); BC_PASS("s0 mismatch"); } /* now compute the ZRTPSession key : section 4.5.2 * ZRTPSess = KDF(s0, "ZRTP Session Key", KDF_Context, negotiated hash length)*/ contextAlice->ZRTPSessLength=32; /* must be set to the length of negotiated hash */ contextAlice->ZRTPSess = (uint8_t *)malloc(contextAlice->ZRTPSessLength*sizeof(uint8_t)); retval = bzrtp_keyDerivationFunction(contextAlice->channelContext[0]->s0, contextAlice->channelContext[0]->hashLength, (uint8_t *)"ZRTP Session Key", 16, contextAlice->channelContext[0]->KDFContext, contextAlice->channelContext[0]->KDFContextLength, /* this one too depends on selected hash */ contextAlice->channelContext[0]->hashLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextAlice->channelContext[0]->hmacFunction, contextAlice->ZRTPSess); contextBob->ZRTPSessLength=32; /* must be set to the length of negotiated hash */ contextBob->ZRTPSess = (uint8_t *)malloc(contextBob->ZRTPSessLength*sizeof(uint8_t)); retval = bzrtp_keyDerivationFunction(contextBob->channelContext[0]->s0, contextBob->channelContext[0]->hashLength, (uint8_t *)"ZRTP Session Key", 16, contextBob->channelContext[0]->KDFContext, contextBob->channelContext[0]->KDFContextLength, /* this one too depends on selected hash */ contextBob->channelContext[0]->hashLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextBob->channelContext[0]->hmacFunction, contextBob->ZRTPSess); /* DEBUG compare ZRTPSess Key */ if (memcmp(contextBob->ZRTPSess, contextAlice->ZRTPSess, 32)==0) { bzrtp_message("Got the same ZRTPSess\n"); BC_PASS("ZRTPSess match"); } else { bzrtp_message("ERROR ZRTPSess differs\n"); BC_PASS("ZRTPSess mismatch"); } /* compute the sas according to rfc section 4.5.2 sashash = KDF(s0, "SAS", KDF_Context, 256) */ retval = bzrtp_keyDerivationFunction(contextAlice->channelContext[0]->s0, contextAlice->channelContext[0]->hashLength, (uint8_t *)"SAS", 3, contextAlice->channelContext[0]->KDFContext, contextAlice->channelContext[0]->KDFContextLength, /* this one too depends on selected hash */ 256/8, /* function gets L in bytes */ (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextAlice->channelContext[0]->hmacFunction, alice_sasHash); retval = bzrtp_keyDerivationFunction(contextBob->channelContext[0]->s0, contextBob->channelContext[0]->hashLength, (uint8_t *)"SAS", 3, contextBob->channelContext[0]->KDFContext, contextBob->channelContext[0]->KDFContextLength, /* this one too depends on selected hash */ 256/8, /* function gets L in bytes */ (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextBob->channelContext[0]->hmacFunction, bob_sasHash); /* DEBUG compare sasHash */ if (memcmp(alice_sasHash, bob_sasHash, 32)==0) { bzrtp_message("Got the same SAS Hash\n"); BC_PASS("SAS Hash match"); } else { bzrtp_message("ERROR SAS Hash differs\n"); BC_PASS("SAS Hash mismatch"); } /* display SAS (we shall not do this now but after the confirm message exchanges) */ sasValue = ((uint32_t)alice_sasHash[0]<<24) | ((uint32_t)alice_sasHash[1]<<16) | ((uint32_t)alice_sasHash[2]<<8) | ((uint32_t)(alice_sasHash[3])); contextAlice->channelContext[0]->sasFunction(sasValue, sas, 5); bzrtp_message("Alice SAS is %.4s\n", sas); sasValue = ((uint32_t)bob_sasHash[0]<<24) | ((uint32_t)bob_sasHash[1]<<16) | ((uint32_t)bob_sasHash[2]<<8) | ((uint32_t)(bob_sasHash[3])); contextBob->channelContext[0]->sasFunction(sasValue, sas, 5); bzrtp_message("Bob SAS is %.4s\n", sas); /* now derive the other keys (mackeyi, mackeyr, zrtpkeyi and zrtpkeyr, srtpkeys and salt) */ contextAlice->channelContext[0]->mackeyi = (uint8_t *)malloc(contextAlice->channelContext[0]->hashLength*(sizeof(uint8_t))); contextAlice->channelContext[0]->mackeyr = (uint8_t *)malloc(contextAlice->channelContext[0]->hashLength*(sizeof(uint8_t))); contextAlice->channelContext[0]->zrtpkeyi = (uint8_t *)malloc(contextAlice->channelContext[0]->cipherKeyLength*(sizeof(uint8_t))); contextAlice->channelContext[0]->zrtpkeyr = (uint8_t *)malloc(contextAlice->channelContext[0]->cipherKeyLength*(sizeof(uint8_t))); contextBob->channelContext[0]->mackeyi = (uint8_t *)malloc(contextBob->channelContext[0]->hashLength*(sizeof(uint8_t))); contextBob->channelContext[0]->mackeyr = (uint8_t *)malloc(contextBob->channelContext[0]->hashLength*(sizeof(uint8_t))); contextBob->channelContext[0]->zrtpkeyi = (uint8_t *)malloc(contextBob->channelContext[0]->cipherKeyLength*(sizeof(uint8_t))); contextBob->channelContext[0]->zrtpkeyr = (uint8_t *)malloc(contextBob->channelContext[0]->cipherKeyLength*(sizeof(uint8_t))); /* Alice */ retval = bzrtp_keyDerivationFunction(contextAlice->channelContext[0]->s0, contextAlice->channelContext[0]->hashLength, (uint8_t *)"Initiator HMAC key", 18, contextAlice->channelContext[0]->KDFContext, contextAlice->channelContext[0]->KDFContextLength, contextAlice->channelContext[0]->hashLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextAlice->channelContext[0]->hmacFunction, contextAlice->channelContext[0]->mackeyi); retval += bzrtp_keyDerivationFunction(contextAlice->channelContext[0]->s0, contextAlice->channelContext[0]->hashLength, (uint8_t *)"Responder HMAC key", 18, contextAlice->channelContext[0]->KDFContext, contextAlice->channelContext[0]->KDFContextLength, contextAlice->channelContext[0]->hashLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextAlice->channelContext[0]->hmacFunction, contextAlice->channelContext[0]->mackeyr); retval += bzrtp_keyDerivationFunction(contextAlice->channelContext[0]->s0, contextAlice->channelContext[0]->hashLength, (uint8_t *)"Initiator ZRTP key", 18, contextAlice->channelContext[0]->KDFContext, contextAlice->channelContext[0]->KDFContextLength, contextAlice->channelContext[0]->cipherKeyLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextAlice->channelContext[0]->hmacFunction, contextAlice->channelContext[0]->zrtpkeyi); retval += bzrtp_keyDerivationFunction(contextAlice->channelContext[0]->s0, contextAlice->channelContext[0]->hashLength, (uint8_t *)"Responder ZRTP key", 18, contextAlice->channelContext[0]->KDFContext, contextAlice->channelContext[0]->KDFContextLength, contextAlice->channelContext[0]->cipherKeyLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextAlice->channelContext[0]->hmacFunction, contextAlice->channelContext[0]->zrtpkeyr); /* Bob */ retval = bzrtp_keyDerivationFunction(contextBob->channelContext[0]->s0, contextBob->channelContext[0]->hashLength, (uint8_t *)"Initiator HMAC key", 18, contextBob->channelContext[0]->KDFContext, contextBob->channelContext[0]->KDFContextLength, contextBob->channelContext[0]->hashLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextBob->channelContext[0]->hmacFunction, contextBob->channelContext[0]->mackeyi); retval += bzrtp_keyDerivationFunction(contextBob->channelContext[0]->s0, contextBob->channelContext[0]->hashLength, (uint8_t *)"Responder HMAC key", 18, contextBob->channelContext[0]->KDFContext, contextBob->channelContext[0]->KDFContextLength, contextBob->channelContext[0]->hashLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextBob->channelContext[0]->hmacFunction, contextBob->channelContext[0]->mackeyr); retval += bzrtp_keyDerivationFunction(contextBob->channelContext[0]->s0, contextBob->channelContext[0]->hashLength, (uint8_t *)"Initiator ZRTP key", 18, contextBob->channelContext[0]->KDFContext, contextBob->channelContext[0]->KDFContextLength, contextBob->channelContext[0]->cipherKeyLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextBob->channelContext[0]->hmacFunction, contextBob->channelContext[0]->zrtpkeyi); retval += bzrtp_keyDerivationFunction(contextBob->channelContext[0]->s0, contextBob->channelContext[0]->hashLength, (uint8_t *)"Responder ZRTP key", 18, contextBob->channelContext[0]->KDFContext, contextBob->channelContext[0]->KDFContextLength, contextBob->channelContext[0]->cipherKeyLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextBob->channelContext[0]->hmacFunction, contextBob->channelContext[0]->zrtpkeyr); /* DEBUG compare keys */ if ((memcmp(contextAlice->channelContext[0]->mackeyi, contextBob->channelContext[0]->mackeyi, contextAlice->channelContext[0]->hashLength)==0) && (memcmp(contextAlice->channelContext[0]->mackeyr, contextBob->channelContext[0]->mackeyr, contextAlice->channelContext[0]->hashLength)==0) && (memcmp(contextAlice->channelContext[0]->zrtpkeyi, contextBob->channelContext[0]->zrtpkeyi, contextAlice->channelContext[0]->cipherKeyLength)==0) && (memcmp(contextAlice->channelContext[0]->zrtpkeyr, contextBob->channelContext[0]->zrtpkeyr, contextAlice->channelContext[0]->cipherKeyLength)==0)) { bzrtp_message("Got the same keys\n"); BC_PASS("keys match"); } else { bzrtp_message("ERROR keys differ\n"); BC_PASS("Keys mismatch"); } /* now Bob build the CONFIRM1 packet and send it to Alice */ bob_Confirm1 = bzrtp_createZrtpPacket(contextBob, contextBob->channelContext[0], MSGTYPE_CONFIRM1, &retval); retval += bzrtp_packetBuild(contextBob, contextBob->channelContext[0], bob_Confirm1, contextBob->channelContext[0]->selfSequenceNumber); if (retval == 0) { contextBob->channelContext[0]->selfSequenceNumber++; } bzrtp_message("Bob building Confirm1 return %x\n", retval); alice_Confirm1FromBob = bzrtp_packetCheck(bob_Confirm1->packetString, bob_Confirm1->messageLength+16, contextAlice->channelContext[0]->peerSequenceNumber, &retval); retval += bzrtp_packetParser(contextAlice, contextAlice->channelContext[0], bob_Confirm1->packetString, bob_Confirm1->messageLength+16, alice_Confirm1FromBob); bzrtp_message ("Alice parsing confirm1 returns %x\n", retval); if (retval==0) { /* update context with the information found in the packet */ contextAlice->channelContext[0]->peerSequenceNumber = alice_Confirm1FromBob->sequenceNumber; alice_Confirm1FromBob_message = (bzrtpConfirmMessage_t *)alice_Confirm1FromBob->messageData; memcpy(contextAlice->channelContext[0]->peerH[0], alice_Confirm1FromBob_message->H0, 32); } packetDump(bob_Confirm1,1); packetDump(alice_Confirm1FromBob,0); bzrtp_freeZrtpPacket(alice_Confirm1FromBob); bzrtp_freeZrtpPacket(bob_Confirm1); /* now Alice build the CONFIRM2 packet and send it to Bob */ alice_Confirm2 = bzrtp_createZrtpPacket(contextAlice, contextAlice->channelContext[0], MSGTYPE_CONFIRM2, &retval); retval += bzrtp_packetBuild(contextAlice, contextAlice->channelContext[0], alice_Confirm2, contextAlice->channelContext[0]->selfSequenceNumber); if (retval == 0) { contextAlice->channelContext[0]->selfSequenceNumber++; } bzrtp_message("Alice building Confirm2 return %x\n", retval); bob_Confirm2FromAlice = bzrtp_packetCheck(alice_Confirm2->packetString, alice_Confirm2->messageLength+16, contextBob->channelContext[0]->peerSequenceNumber, &retval); retval += bzrtp_packetParser(contextBob, contextBob->channelContext[0], alice_Confirm2->packetString, alice_Confirm2->messageLength+16, bob_Confirm2FromAlice); bzrtp_message ("Bob parsing confirm2 returns %x\n", retval); if (retval==0) { /* update context with the information found in the packet */ contextBob->channelContext[0]->peerSequenceNumber = bob_Confirm2FromAlice->sequenceNumber; bob_Confirm2FromAlice_message = (bzrtpConfirmMessage_t *)bob_Confirm2FromAlice->messageData; memcpy(contextBob->channelContext[0]->peerH[0], bob_Confirm2FromAlice_message->H0, 32); /* set bob's status to secure */ contextBob->isSecure = 1; } packetDump(alice_Confirm2,1); packetDump(bob_Confirm2FromAlice,0); bzrtp_freeZrtpPacket(bob_Confirm2FromAlice); bzrtp_freeZrtpPacket(alice_Confirm2); /* Bob build the conf2Ack and send it to Alice */ bob_Conf2ACK = bzrtp_createZrtpPacket(contextBob, contextBob->channelContext[0], MSGTYPE_CONF2ACK, &retval); retval += bzrtp_packetBuild(contextBob, contextBob->channelContext[0], bob_Conf2ACK, contextBob->channelContext[0]->selfSequenceNumber); if (retval == 0) { contextBob->channelContext[0]->selfSequenceNumber++; } bzrtp_message("Bob building Conf2ACK return %x\n", retval); alice_Conf2ACKFromBob = bzrtp_packetCheck(bob_Conf2ACK->packetString, bob_Conf2ACK->messageLength+16, contextAlice->channelContext[0]->peerSequenceNumber, &retval); retval += bzrtp_packetParser(contextAlice, contextAlice->channelContext[0], bob_Conf2ACK->packetString, bob_Conf2ACK->messageLength+16, alice_Conf2ACKFromBob); bzrtp_message ("Alice parsing conf2ACK returns %x\n", retval); if (retval==0) { /* update context with the information found in the packet */ contextAlice->channelContext[0]->peerSequenceNumber = alice_Conf2ACKFromBob->sequenceNumber; /* set Alice's status to secure */ contextAlice->isSecure = 1; } bzrtp_freeZrtpPacket(bob_Conf2ACK); bzrtp_freeZrtpPacket(alice_Conf2ACKFromBob); dumpContext("Alice", contextAlice); dumpContext("Bob", contextBob); bzrtp_message("\n\n\n\n\n*************************************************************\n SECOND CHANNEL\n**********************************************\n\n"); /* Now create a second channel for Bob and Alice */ retval = bzrtp_addChannel(contextAlice, 0x45678901); bzrtp_message("Add channel to Alice's context returns %d\n", retval); retval = bzrtp_addChannel(contextBob, 0x54321098); bzrtp_message("Add channel to Bob's context returns %d\n", retval); /* create hello packets for this channel */ alice_Hello = bzrtp_createZrtpPacket(contextAlice, contextAlice->channelContext[1], MSGTYPE_HELLO, &retval); if (bzrtp_packetBuild(contextAlice, contextAlice->channelContext[1], alice_Hello, contextAlice->channelContext[1]->selfSequenceNumber) ==0) { contextAlice->channelContext[1]->selfSequenceNumber++; contextAlice->channelContext[1]->selfPackets[HELLO_MESSAGE_STORE_ID] = alice_Hello; } bob_Hello = bzrtp_createZrtpPacket(contextBob, contextBob->channelContext[1], MSGTYPE_HELLO, &retval); if (bzrtp_packetBuild(contextBob, contextBob->channelContext[1], bob_Hello, contextBob->channelContext[1]->selfSequenceNumber) ==0) { contextBob->channelContext[1]->selfSequenceNumber++; contextBob->channelContext[1]->selfPackets[HELLO_MESSAGE_STORE_ID] = bob_Hello; } /* now send Alice Hello's to Bob and vice-versa, so they parse them */ alice_HelloFromBob = bzrtp_packetCheck(bob_Hello->packetString, bob_Hello->messageLength+16, contextAlice->channelContext[1]->peerSequenceNumber, &retval); retval += bzrtp_packetParser(contextAlice, contextAlice->channelContext[0], bob_Hello->packetString, bob_Hello->messageLength+16, alice_HelloFromBob); bzrtp_message ("Alice parsing returns %x\n", retval); if (retval==0) { bzrtpHelloMessage_t *alice_HelloFromBob_message; int i; uint8_t checkPeerSupportMultiChannel = 0; contextAlice->channelContext[1]->peerSequenceNumber = alice_HelloFromBob->sequenceNumber; /* save bob's Hello packet in Alice's context */ contextAlice->channelContext[1]->peerPackets[HELLO_MESSAGE_STORE_ID] = alice_HelloFromBob; /* we are already secured (shall check isSecure==1), so we just need to check that peer Hello have the Mult in his key agreement list of supported algo */ alice_HelloFromBob_message = (bzrtpHelloMessage_t *)alice_HelloFromBob->messageData; for (i=0; ikc; i++) { if (alice_HelloFromBob_message->supportedKeyAgreement[i] == ZRTP_KEYAGREEMENT_Mult) { checkPeerSupportMultiChannel = 1; } } /* ok multi channel is supported*/ if (checkPeerSupportMultiChannel == 1) { bzrtp_message("Alice found that Bob supports multi channel\n"); /* now set the choosen algos, they MUST be the same than main channel (channel 0) except for keyAgreement which is set to mult */ contextAlice->channelContext[1]->hashAlgo = contextAlice->channelContext[0]->hashAlgo; contextAlice->channelContext[1]->hashLength = contextAlice->channelContext[0]->hashLength; contextAlice->channelContext[1]->cipherAlgo = contextAlice->channelContext[0]->cipherAlgo; contextAlice->channelContext[1]->cipherKeyLength = contextAlice->channelContext[0]->cipherKeyLength; contextAlice->channelContext[1]->authTagAlgo = contextAlice->channelContext[0]->authTagAlgo; contextAlice->channelContext[1]->sasAlgo = contextAlice->channelContext[0]->sasAlgo; contextAlice->channelContext[1]->keyAgreementAlgo = ZRTP_KEYAGREEMENT_Mult; contextAlice->channelContext[1]->keyAgreementLength = 0; /* no public values exchanged in Multi channel mode */ bzrtp_updateCryptoFunctionPointers(contextAlice->channelContext[1]); } else { bzrtp_message("ERROR : Alice found that Bob doesn't support multi channel\n"); } } bob_HelloFromAlice = bzrtp_packetCheck(alice_Hello->packetString, alice_Hello->messageLength+16, contextBob->channelContext[1]->peerSequenceNumber, &retval); retval += bzrtp_packetParser(contextBob, contextBob->channelContext[1], alice_Hello->packetString, alice_Hello->messageLength+16, bob_HelloFromAlice); bzrtp_message ("Bob parsing returns %x\n", retval); if (retval==0) { bzrtpHelloMessage_t *bob_HelloFromAlice_message; int i; uint8_t checkPeerSupportMultiChannel = 0; contextBob->channelContext[1]->peerSequenceNumber = bob_HelloFromAlice->sequenceNumber; /* save alice's Hello packet in bob's context */ contextBob->channelContext[1]->peerPackets[HELLO_MESSAGE_STORE_ID] = bob_HelloFromAlice; /* we are already secured (shall check isSecure==1), so we just need to check that peer Hello have the Mult in his key agreement list of supported algo */ bob_HelloFromAlice_message = (bzrtpHelloMessage_t *)bob_HelloFromAlice->messageData; for (i=0; ikc; i++) { if (bob_HelloFromAlice_message->supportedKeyAgreement[i] == ZRTP_KEYAGREEMENT_Mult) { checkPeerSupportMultiChannel = 1; } } /* ok multi channel is supported*/ if (checkPeerSupportMultiChannel == 1) { bzrtp_message("Bob found that Alice supports multi channel\n"); /* now set the choosen algos, they MUST be the same than main channel (channel 0) except for keyAgreement which is set to mult */ contextBob->channelContext[1]->hashAlgo = contextBob->channelContext[0]->hashAlgo; contextBob->channelContext[1]->hashLength = contextBob->channelContext[0]->hashLength; contextBob->channelContext[1]->cipherAlgo = contextBob->channelContext[0]->cipherAlgo; contextBob->channelContext[1]->cipherKeyLength = contextBob->channelContext[0]->cipherKeyLength; contextBob->channelContext[1]->authTagAlgo = contextBob->channelContext[0]->authTagAlgo; contextBob->channelContext[1]->sasAlgo = contextBob->channelContext[0]->sasAlgo; contextBob->channelContext[1]->keyAgreementAlgo = ZRTP_KEYAGREEMENT_Mult; contextBob->channelContext[1]->keyAgreementLength = 0; /* no public values exchanged in Multi channel mode */ bzrtp_updateCryptoFunctionPointers(contextBob->channelContext[1]); } else { bzrtp_message("ERROR : Bob found that Alice doesn't support multi channel\n"); } } /* update context with hello message information : H3 and compute initiator and responder's shared secret Hashs */ alice_HelloFromBob_message = (bzrtpHelloMessage_t *)alice_HelloFromBob->messageData; memcpy(contextAlice->channelContext[1]->peerH[3], alice_HelloFromBob_message->H3, 32); bob_HelloFromAlice_message = (bzrtpHelloMessage_t *)bob_HelloFromAlice->messageData; memcpy(contextBob->channelContext[1]->peerH[3], bob_HelloFromAlice_message->H3, 32); /* here we shall exchange Hello ACK but it is just a test and was done already for channel 0, skip it as it is useless for the test */ /* Bob will be the initiator, so compute a commit for him */ bob_Commit = bzrtp_createZrtpPacket(contextBob, contextBob->channelContext[1], MSGTYPE_COMMIT, &retval); retval += bzrtp_packetBuild(contextBob, contextBob->channelContext[1], bob_Commit, contextBob->channelContext[1]->selfSequenceNumber); if (retval == 0) { contextBob->channelContext[1]->selfSequenceNumber++; contextBob->channelContext[1]->selfPackets[COMMIT_MESSAGE_STORE_ID] = bob_Commit; } bzrtp_message("Bob building Commit return %x\n", retval); /* and send it to Alice */ alice_CommitFromBob = bzrtp_packetCheck(bob_Commit->packetString, bob_Commit->messageLength+16, contextAlice->channelContext[1]->peerSequenceNumber, &retval); retval += bzrtp_packetParser(contextAlice, contextAlice->channelContext[1], bob_Commit->packetString, bob_Commit->messageLength+16, alice_CommitFromBob); bzrtp_message ("Alice parsing Commit returns %x\n", retval); if (retval==0) { bzrtpCommitMessage_t *alice_CommitFromBob_message; /* update context with the information found in the packet */ contextAlice->channelContext[1]->peerSequenceNumber = alice_CommitFromBob->sequenceNumber; /* Alice will be the initiator (commit contention not implemented in this test) so just discard bob's commit */ alice_CommitFromBob_message = (bzrtpCommitMessage_t *)alice_CommitFromBob->messageData; memcpy(contextAlice->channelContext[1]->peerH[2], alice_CommitFromBob_message->H2, 32); contextAlice->channelContext[1]->peerPackets[COMMIT_MESSAGE_STORE_ID] = alice_CommitFromBob; } packetDump(alice_CommitFromBob, 0); /* for test purpose define Alice as the responder */ contextAlice->channelContext[1]->role = BZRTP_ROLE_RESPONDER; /* compute the total hash as in rfc section 4.4.3.2 total_hash = hash(Hello of responder || Commit) */ totalHashDataLength = alice_Hello->messageLength + bob_Commit->messageLength; dataToHash = (uint8_t *)malloc(totalHashDataLength*sizeof(uint8_t)); hashDataIndex = 0; /* get all data from Alice */ memcpy(dataToHash, contextAlice->channelContext[1]->selfPackets[HELLO_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, contextAlice->channelContext[1]->selfPackets[HELLO_MESSAGE_STORE_ID]->messageLength); hashDataIndex += contextAlice->channelContext[1]->selfPackets[HELLO_MESSAGE_STORE_ID]->messageLength; memcpy(dataToHash+hashDataIndex, contextAlice->channelContext[1]->peerPackets[COMMIT_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, contextAlice->channelContext[1]->peerPackets[COMMIT_MESSAGE_STORE_ID]->messageLength); contextAlice->channelContext[1]->hashFunction(dataToHash, totalHashDataLength, 32, alice_totalHash); /* get all data from Bob */ hashDataIndex = 0; memcpy(dataToHash, contextBob->channelContext[1]->peerPackets[HELLO_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, contextBob->channelContext[1]->peerPackets[HELLO_MESSAGE_STORE_ID]->messageLength); hashDataIndex += contextBob->channelContext[1]->peerPackets[HELLO_MESSAGE_STORE_ID]->messageLength; memcpy(dataToHash+hashDataIndex, contextBob->channelContext[1]->selfPackets[COMMIT_MESSAGE_STORE_ID]->packetString+ZRTP_PACKET_HEADER_LENGTH, contextBob->channelContext[1]->selfPackets[COMMIT_MESSAGE_STORE_ID]->messageLength); contextBob->channelContext[1]->hashFunction(dataToHash, totalHashDataLength, 32, bob_totalHash); if (memcmp(bob_totalHash, alice_totalHash, 32) == 0) { bzrtp_message("Got the same total hash\n"); BC_PASS("Total Hash match"); } else { bzrtp_message("AARGG!! total hash mismatch"); BC_FAIL("Total Hash mismatch"); } free(dataToHash); /* compute the KDF Context as in rfc section 4.4.3.2 KDF_Context = (ZIDi || ZIDr || total_hash) */ contextAlice->channelContext[1]->KDFContextLength = 24 + contextAlice->channelContext[1]->hashLength; contextAlice->channelContext[1]->KDFContext = (uint8_t *)malloc(contextAlice->channelContext[1]->KDFContextLength*sizeof(uint8_t)); memcpy(contextAlice->channelContext[1]->KDFContext, contextAlice->peerZID, 12); memcpy(contextAlice->channelContext[1]->KDFContext+12, contextAlice->selfZID, 12); memcpy(contextAlice->channelContext[1]->KDFContext+24, alice_totalHash, contextAlice->channelContext[1]->hashLength); contextBob->channelContext[1]->KDFContextLength = 24 + contextBob->channelContext[1]->hashLength; contextBob->channelContext[1]->KDFContext = (uint8_t *)malloc(contextBob->channelContext[1]->KDFContextLength*sizeof(uint8_t)); memcpy(contextBob->channelContext[1]->KDFContext, contextBob->selfZID, 12); memcpy(contextBob->channelContext[1]->KDFContext+12, contextBob->peerZID, 12); memcpy(contextBob->channelContext[1]->KDFContext+24, bob_totalHash, contextBob->channelContext[1]->hashLength); if (memcmp(contextBob->channelContext[1]->KDFContext, contextAlice->channelContext[1]->KDFContext, 56) == 0) { bzrtp_message("Got the same total KDF Context\n"); BC_PASS("KDFContext match"); } else { bzrtp_message("AARGG!! KDF Context mismatch"); BC_FAIL("KDF Context mismatch"); } /* compute s0 as in rfc section 4.4.3.2 s0 = KDF(ZRTPSess, "ZRTP MSK", KDF_Context, negotiated hash length) */ contextBob->channelContext[1]->s0 = (uint8_t *)malloc(contextBob->channelContext[1]->hashLength*sizeof(uint8_t)); contextAlice->channelContext[1]->s0 = (uint8_t *)malloc(contextAlice->channelContext[1]->hashLength*sizeof(uint8_t)); retval = bzrtp_keyDerivationFunction(contextBob->ZRTPSess, contextBob->ZRTPSessLength, (uint8_t *)"ZRTP MSK", 8, contextBob->channelContext[1]->KDFContext, contextBob->channelContext[1]->KDFContextLength, /* this one too depends on selected hash */ contextBob->channelContext[1]->hashLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextBob->channelContext[1]->hmacFunction, contextBob->channelContext[1]->s0); retval = bzrtp_keyDerivationFunction(contextAlice->ZRTPSess, contextAlice->ZRTPSessLength, (uint8_t *)"ZRTP MSK", 8, contextAlice->channelContext[1]->KDFContext, contextAlice->channelContext[1]->KDFContextLength, /* this one too depends on selected hash */ contextAlice->channelContext[1]->hashLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextAlice->channelContext[1]->hmacFunction, contextAlice->channelContext[1]->s0); if (memcmp(contextBob->channelContext[1]->s0, contextAlice->channelContext[1]->s0, contextAlice->channelContext[1]->hashLength) == 0) { bzrtp_message("Got the same s0\n"); BC_PASS("s0 match"); } else { bzrtp_message("AARGG!! s0 mismatch"); BC_FAIL("s0 mismatch"); } /* the rest of key derivation is common to DH mode, no need to test it as it has been done before for channel 0 */ /* we must anyway derive zrtp and mac key for initiator and responder in order to be able to build the confirm packets */ contextAlice->channelContext[1]->mackeyi = (uint8_t *)malloc(contextAlice->channelContext[1]->hashLength*(sizeof(uint8_t))); contextAlice->channelContext[1]->mackeyr = (uint8_t *)malloc(contextAlice->channelContext[1]->hashLength*(sizeof(uint8_t))); contextAlice->channelContext[1]->zrtpkeyi = (uint8_t *)malloc(contextAlice->channelContext[1]->cipherKeyLength*(sizeof(uint8_t))); contextAlice->channelContext[1]->zrtpkeyr = (uint8_t *)malloc(contextAlice->channelContext[1]->cipherKeyLength*(sizeof(uint8_t))); contextBob->channelContext[1]->mackeyi = (uint8_t *)malloc(contextBob->channelContext[1]->hashLength*(sizeof(uint8_t))); contextBob->channelContext[1]->mackeyr = (uint8_t *)malloc(contextBob->channelContext[1]->hashLength*(sizeof(uint8_t))); contextBob->channelContext[1]->zrtpkeyi = (uint8_t *)malloc(contextBob->channelContext[1]->cipherKeyLength*(sizeof(uint8_t))); contextBob->channelContext[1]->zrtpkeyr = (uint8_t *)malloc(contextBob->channelContext[1]->cipherKeyLength*(sizeof(uint8_t))); /* Alice */ retval = bzrtp_keyDerivationFunction(contextAlice->channelContext[1]->s0, contextAlice->channelContext[1]->hashLength, (uint8_t *)"Initiator HMAC key", 18, contextAlice->channelContext[1]->KDFContext, contextAlice->channelContext[1]->KDFContextLength, contextAlice->channelContext[1]->hashLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextAlice->channelContext[1]->hmacFunction, contextAlice->channelContext[1]->mackeyi); retval += bzrtp_keyDerivationFunction(contextAlice->channelContext[1]->s0, contextAlice->channelContext[1]->hashLength, (uint8_t *)"Responder HMAC key", 18, contextAlice->channelContext[1]->KDFContext, contextAlice->channelContext[1]->KDFContextLength, contextAlice->channelContext[1]->hashLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextAlice->channelContext[1]->hmacFunction, contextAlice->channelContext[1]->mackeyr); retval += bzrtp_keyDerivationFunction(contextAlice->channelContext[1]->s0, contextAlice->channelContext[1]->hashLength, (uint8_t *)"Initiator ZRTP key", 18, contextAlice->channelContext[1]->KDFContext, contextAlice->channelContext[1]->KDFContextLength, contextAlice->channelContext[1]->cipherKeyLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextAlice->channelContext[1]->hmacFunction, contextAlice->channelContext[1]->zrtpkeyi); retval += bzrtp_keyDerivationFunction(contextAlice->channelContext[1]->s0, contextAlice->channelContext[1]->hashLength, (uint8_t *)"Responder ZRTP key", 18, contextAlice->channelContext[1]->KDFContext, contextAlice->channelContext[1]->KDFContextLength, contextAlice->channelContext[1]->cipherKeyLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextAlice->channelContext[1]->hmacFunction, contextAlice->channelContext[1]->zrtpkeyr); /* Bob */ retval = bzrtp_keyDerivationFunction(contextBob->channelContext[1]->s0, contextBob->channelContext[1]->hashLength, (uint8_t *)"Initiator HMAC key", 18, contextBob->channelContext[1]->KDFContext, contextBob->channelContext[1]->KDFContextLength, contextBob->channelContext[1]->hashLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextBob->channelContext[1]->hmacFunction, contextBob->channelContext[1]->mackeyi); retval += bzrtp_keyDerivationFunction(contextBob->channelContext[1]->s0, contextBob->channelContext[1]->hashLength, (uint8_t *)"Responder HMAC key", 18, contextBob->channelContext[1]->KDFContext, contextBob->channelContext[1]->KDFContextLength, contextBob->channelContext[1]->hashLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextBob->channelContext[1]->hmacFunction, contextBob->channelContext[1]->mackeyr); retval += bzrtp_keyDerivationFunction(contextBob->channelContext[1]->s0, contextBob->channelContext[1]->hashLength, (uint8_t *)"Initiator ZRTP key", 18, contextBob->channelContext[1]->KDFContext, contextBob->channelContext[1]->KDFContextLength, contextBob->channelContext[1]->cipherKeyLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextBob->channelContext[1]->hmacFunction, contextBob->channelContext[1]->zrtpkeyi); retval += bzrtp_keyDerivationFunction(contextBob->channelContext[1]->s0, contextBob->channelContext[1]->hashLength, (uint8_t *)"Responder ZRTP key", 18, contextBob->channelContext[1]->KDFContext, contextBob->channelContext[1]->KDFContextLength, contextBob->channelContext[1]->cipherKeyLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))contextBob->channelContext[1]->hmacFunction, contextBob->channelContext[1]->zrtpkeyr); /* DEBUG compare keys */ if ((memcmp(contextAlice->channelContext[1]->mackeyi, contextBob->channelContext[1]->mackeyi, contextAlice->channelContext[1]->hashLength)==0) && (memcmp(contextAlice->channelContext[1]->mackeyr, contextBob->channelContext[1]->mackeyr, contextAlice->channelContext[1]->hashLength)==0) && (memcmp(contextAlice->channelContext[1]->zrtpkeyi, contextBob->channelContext[1]->zrtpkeyi, contextAlice->channelContext[1]->cipherKeyLength)==0) && (memcmp(contextAlice->channelContext[1]->zrtpkeyr, contextBob->channelContext[1]->zrtpkeyr, contextAlice->channelContext[1]->cipherKeyLength)==0)) { bzrtp_message("Got the same keys\n"); BC_PASS("keys match"); } else { bzrtp_message("ERROR keys differ\n"); BC_PASS("Keys mismatch"); } /* now Alice build a confirm1 packet */ alice_Confirm1 = bzrtp_createZrtpPacket(contextAlice, contextAlice->channelContext[1], MSGTYPE_CONFIRM1, &retval); retval += bzrtp_packetBuild(contextAlice, contextAlice->channelContext[1], alice_Confirm1, contextAlice->channelContext[1]->selfSequenceNumber); if (retval == 0) { contextAlice->channelContext[1]->selfSequenceNumber++; } bzrtp_message("Alice building Confirm1 return %x\n", retval); bob_Confirm1FromAlice = bzrtp_packetCheck(alice_Confirm1->packetString, alice_Confirm1->messageLength+16, contextBob->channelContext[1]->peerSequenceNumber, &retval); retval += bzrtp_packetParser(contextBob, contextBob->channelContext[1], alice_Confirm1->packetString, alice_Confirm1->messageLength+16, bob_Confirm1FromAlice); bzrtp_message ("Bob parsing confirm1 returns %x\n", retval); if (retval==0) { /* update context with the information found in the packet */ contextBob->channelContext[1]->peerSequenceNumber = bob_Confirm1FromAlice->sequenceNumber; bob_Confirm1FromAlice_message = (bzrtpConfirmMessage_t *)bob_Confirm1FromAlice->messageData; memcpy(contextBob->channelContext[1]->peerH[0], bob_Confirm1FromAlice_message->H0, 32); } packetDump(bob_Confirm1FromAlice,0); bzrtp_freeZrtpPacket(bob_Confirm1FromAlice); bzrtp_freeZrtpPacket(alice_Confirm1); /* now Bob build the CONFIRM2 packet and send it to Alice */ bob_Confirm2 = bzrtp_createZrtpPacket(contextBob, contextBob->channelContext[1], MSGTYPE_CONFIRM2, &retval); retval += bzrtp_packetBuild(contextBob, contextBob->channelContext[1], bob_Confirm2, contextBob->channelContext[1]->selfSequenceNumber); if (retval == 0) { contextBob->channelContext[1]->selfSequenceNumber++; } bzrtp_message("Bob building Confirm2 return %x\n", retval); alice_Confirm2FromBob = bzrtp_packetCheck(bob_Confirm2->packetString, bob_Confirm2->messageLength+16, contextAlice->channelContext[1]->peerSequenceNumber, &retval); retval += bzrtp_packetParser(contextAlice, contextAlice->channelContext[1], bob_Confirm2->packetString, bob_Confirm2->messageLength+16, alice_Confirm2FromBob); bzrtp_message ("Alice parsing confirm2 returns %x\n", retval); if (retval==0) { /* update context with the information found in the packet */ contextAlice->channelContext[1]->peerSequenceNumber = alice_Confirm2FromBob->sequenceNumber; alice_Confirm2FromBob_message = (bzrtpConfirmMessage_t *)alice_Confirm2FromBob->messageData; memcpy(contextAlice->channelContext[1]->peerH[0], alice_Confirm2FromBob_message->H0, 32); } packetDump(alice_Confirm2FromBob,0); bzrtp_freeZrtpPacket(alice_Confirm2FromBob); bzrtp_freeZrtpPacket(bob_Confirm2); /* Alice build the conf2Ack and send it to Bob */ alice_Conf2ACK = bzrtp_createZrtpPacket(contextAlice, contextAlice->channelContext[1], MSGTYPE_CONF2ACK, &retval); retval += bzrtp_packetBuild(contextAlice, contextAlice->channelContext[1], alice_Conf2ACK, contextAlice->channelContext[1]->selfSequenceNumber); if (retval == 0) { contextAlice->channelContext[1]->selfSequenceNumber++; } bzrtp_message("Alice building Conf2ACK return %x\n", retval); bob_Conf2ACKFromAlice = bzrtp_packetCheck(alice_Conf2ACK->packetString, alice_Conf2ACK->messageLength+16, contextBob->channelContext[1]->peerSequenceNumber, &retval); retval += bzrtp_packetParser(contextBob, contextBob->channelContext[1], alice_Conf2ACK->packetString, alice_Conf2ACK->messageLength+16, bob_Conf2ACKFromAlice); bzrtp_message ("Bob parsing conf2ACK returns %x\n", retval); if (retval==0) { /* update context with the information found in the packet */ contextBob->channelContext[1]->peerSequenceNumber = bob_Conf2ACKFromAlice->sequenceNumber; } bzrtp_freeZrtpPacket(alice_Conf2ACK); bzrtp_freeZrtpPacket(bob_Conf2ACKFromAlice); /* dumpContext("\nAlice", contextAlice); dumpContext("\nBob", contextBob); */ bzrtp_message("Destroy the contexts\n"); /* destroy the context */ bzrtp_destroyBzrtpContext(contextAlice, 0x45678901); bzrtp_destroyBzrtpContext(contextBob, 0x54321098); bzrtp_message("Destroy the contexts last channel\n"); bzrtp_destroyBzrtpContext(contextBob, 0x87654321); bzrtp_destroyBzrtpContext(contextAlice, 0x12345678); } typedef struct packetDatas_struct { uint8_t packetString[1000]; uint16_t packetLength; } packetDatas_t; /* Alice and Bob packet queues are globals */ packetDatas_t aliceQueue[10]; packetDatas_t bobQueue[10]; uint8_t aliceQueueIndex = 0; uint8_t bobQueueIndex = 0; uint8_t block_Hello = 0; /* this is a callback function for send data, just dump the packet */ /* client Data is a my_Context_t structure */ int bzrtp_sendData(void *clientData, const uint8_t *packetString, uint16_t packetLength) { /* get the client Data */ my_Context_t *contexts = (my_Context_t *)clientData; /* bzrtp_message ("%s sends a message!\n", contexts->nom); int retval; bzrtpPacket_t *zrtpPacket = bzrtp_packetCheck(packetString, packetLength, contexts->peerChannelContext->peerSequenceNumber, &retval); if (retval==0) { retval = bzrtp_packetParser(contexts->peerContext, contexts->peerChannelContext, packetString, packetLength, zrtpPacket); if (retval == 0) { */ /* packetDump(zrtpPacket,0); */ /* printHex("Data", packetString, packetLength);*/ /* } else { bzrtp_message("Parse says %04x\n", retval); } } else { bzrtp_message("Check says %04x\n", retval); } */ /* put the message in the message queue */ if (contexts->nom[0] == 'A') { /* message sent by Alice, put it in Bob's queue */ /* block the first Hello to force going through wait for hello state and check it is retransmitted */ /* if ((block_Hello == 0) && (zrtpPacket->messageType == MSGTYPE_HELLO)) { block_Hello = 1; } else {*/ memcpy(bobQueue[bobQueueIndex].packetString, packetString, packetLength); bobQueue[bobQueueIndex++].packetLength = packetLength; /* }*/ } else { memcpy(aliceQueue[aliceQueueIndex].packetString, packetString, packetLength); aliceQueue[aliceQueueIndex++].packetLength = packetLength; } /* bzrtp_freeZrtpPacket(zrtpPacket); */ return 0; } uint64_t myCurrentTime = 0; /* we do not need a real time, start at 0 and increment it at each sleep */ uint64_t getCurrentTimeInMs() { return myCurrentTime; } static void sleepMs(int ms){ #ifdef _WIN32 Sleep(ms); #else struct timespec ts; ts.tv_sec=0; ts.tv_nsec=ms*1000000LL; nanosleep(&ts,NULL); #endif myCurrentTime +=ms; } /* Ping message length is 24 bytes (already define in packetParser.c out of this scope) */ #define ZRTP_PINGMESSAGE_FIXED_LENGTH 24 void test_stateMachine() { int retval; my_Context_t aliceClientData, bobClientData; uint64_t initialTime; uint8_t pingPacketString[ZRTP_PACKET_OVERHEAD+ZRTP_PINGMESSAGE_FIXED_LENGTH]; /* there is no builder for ping packet and it is 24 bytes long(12 bytes of message header, 12 of data + packet overhead*/ uint32_t CRC; uint8_t *CRCbuffer; my_Context_t aliceSecondChannelClientData, bobSecondChannelClientData; bzrtpCallbacks_t cbs={0} ; /* Create zrtp Context */ bzrtpContext_t *contextAlice = bzrtp_createBzrtpContext(); bzrtpContext_t *contextBob = bzrtp_createBzrtpContext(); /* set the cache related callback functions */ cbs.bzrtp_sendData=bzrtp_sendData; bzrtp_setCallbacks(contextAlice, &cbs); cbs.bzrtp_sendData=bzrtp_sendData; bzrtp_setCallbacks(contextBob, &cbs); /* create the client Data and associate them to the channel contexts */ memcpy(aliceClientData.nom, "Alice", 6); memcpy(bobClientData.nom, "Bob", 4); aliceClientData.peerContext = contextBob; aliceClientData.peerChannelContext = contextBob->channelContext[0]; bobClientData.peerContext = contextAlice; bobClientData.peerChannelContext = contextAlice->channelContext[0]; /* run the init */ bzrtp_initBzrtpContext(contextAlice, 0x12345678);/* Alice's SSRC of main channel is 12345678 */ bzrtp_initBzrtpContext(contextBob, 0x87654321); /* Bob's SSRC of main channel is 87654321 */ retval = bzrtp_setClientData(contextAlice, 0x12345678, (void *)&aliceClientData); retval += bzrtp_setClientData(contextBob, 0x87654321, (void *)&bobClientData); bzrtp_message("Set client data return %x\n", retval); /* now start the engine */ initialTime = getCurrentTimeInMs(); retval = bzrtp_startChannelEngine(contextAlice, 0x12345678); bzrtp_message ("Alice starts return %x\n", retval); retval = bzrtp_startChannelEngine(contextBob, 0x87654321); bzrtp_message ("Bob starts return %x\n", retval); /* now start infinite loop until we reach secure state */ while ((contextAlice->isSecure == 0 || contextBob->isSecure == 0) && (getCurrentTimeInMs()-initialTime<5000)){ int i; /* first check the message queue */ for (i=0; iisSecure == 1) && (contextBob->isSecure == 1)) { /* don't compare sas if we're not secure at we may not have it */ BC_ASSERT_TRUE((memcmp(contextAlice->channelContext[0]->srtpSecrets.sas, contextBob->channelContext[0]->srtpSecrets.sas, 4) == 0)); /* call the set verified Sas function */ bzrtp_SASVerified(contextAlice); bzrtp_SASVerified(contextBob); } else { BC_FAIL("Unable to reach secure state"); } /*** Send alice a ping message from Bob ***/ /* set packet header and CRC */ /* preambule */ pingPacketString[0] = 0x10; pingPacketString[1] = 0x00; /* Sequence number */ pingPacketString[2] = (uint8_t)((contextBob->channelContext[0]->selfSequenceNumber>>8)&0x00FF); pingPacketString[3] = (uint8_t)(contextBob->channelContext[0]->selfSequenceNumber&0x00FF); /* ZRTP magic cookie */ pingPacketString[4] = (uint8_t)((ZRTP_MAGIC_COOKIE>>24)&0xFF); pingPacketString[5] = (uint8_t)((ZRTP_MAGIC_COOKIE>>16)&0xFF); pingPacketString[6] = (uint8_t)((ZRTP_MAGIC_COOKIE>>8)&0xFF); pingPacketString[7] = (uint8_t)(ZRTP_MAGIC_COOKIE&0xFF); /* Source Identifier : insert bob's one: 0x87654321 */ pingPacketString[8] = 0x87; pingPacketString[9] = 0x65; pingPacketString[10] = 0x43; pingPacketString[11] = 0x21; /* message header */ pingPacketString[12] = 0x50; pingPacketString[13] = 0x5a; /* length in 32 bits words */ pingPacketString[14] = 0x00; pingPacketString[15] = 0x06; /* message type "Ping " */ memcpy(pingPacketString+16, "Ping ",8); /* Version on 4 bytes is "1.10" */ memcpy(pingPacketString+24, "1.10", 4); /* a endPointHash, use the first 8 bytes of Bob's ZID */ memcpy(pingPacketString+28, contextBob->selfZID, 8); /* CRC */ CRC = bzrtp_CRC32(pingPacketString, ZRTP_PINGMESSAGE_FIXED_LENGTH+ZRTP_PACKET_HEADER_LENGTH); CRCbuffer = pingPacketString+ZRTP_PINGMESSAGE_FIXED_LENGTH+ZRTP_PACKET_HEADER_LENGTH; *CRCbuffer = (uint8_t)((CRC>>24)&0xFF); CRCbuffer++; *CRCbuffer = (uint8_t)((CRC>>16)&0xFF); CRCbuffer++; *CRCbuffer = (uint8_t)((CRC>>8)&0xFF); CRCbuffer++; *CRCbuffer = (uint8_t)(CRC&0xFF); bzrtp_message("Process a PING message for Alice\n"); retval = bzrtp_processMessage(contextAlice, 0x12345678, pingPacketString, ZRTP_PACKET_OVERHEAD+ZRTP_PINGMESSAGE_FIXED_LENGTH); bzrtp_message("Alice processed PING message and return %04x\n\n", retval); /*** now add a second channel ***/ retval = bzrtp_addChannel(contextAlice, 0x34567890); bzrtp_message("Add a channel to Alice context, return %x\n", retval); retval = bzrtp_addChannel(contextBob, 0x09876543); bzrtp_message("Add a channel to Bob context, return %x\n", retval); /* create the client Data and associate them to the channel contexts */ memcpy(aliceSecondChannelClientData.nom, "Alice", 6); memcpy(bobSecondChannelClientData.nom, "Bob", 4); aliceSecondChannelClientData.peerContext = contextBob; aliceSecondChannelClientData.peerChannelContext = contextBob->channelContext[1]; bobSecondChannelClientData.peerContext = contextAlice; bobSecondChannelClientData.peerChannelContext = contextAlice->channelContext[1]; retval = bzrtp_setClientData(contextAlice, 0x34567890, (void *)&aliceSecondChannelClientData); retval += bzrtp_setClientData(contextBob, 0x09876543, (void *)&bobSecondChannelClientData); bzrtp_message("Set client data return %x\n", retval); /* start the channels */ retval = bzrtp_startChannelEngine(contextAlice, 0x34567890); bzrtp_message ("Alice starts return %x\n", retval); retval = bzrtp_startChannelEngine(contextBob, 0x09876543); bzrtp_message ("Bob starts return %x\n", retval); /* now start infinite loop until we reach secure state */ while ((getCurrentTimeInMs()-initialTime<2000)){ int i; /* first check the message queue */ for (i=0; ichannelContext[1]->srtpSecrets.selfSrtpKey, contextBob->channelContext[1]->srtpSecrets.peerSrtpKey, 16) == 0) && (contextAlice->isSecure == 1) && (contextBob->isSecure == 1)); dumpContext("\nAlice", contextAlice); dumpContext("\nBob", contextBob); bzrtp_message("Destroy the contexts\n"); /* destroy the context */ bzrtp_destroyBzrtpContext(contextAlice, 0x34567890); bzrtp_destroyBzrtpContext(contextBob, 0x09876543); bzrtp_message("Destroy the contexts last channel\n"); bzrtp_destroyBzrtpContext(contextBob, 0x87654321); bzrtp_destroyBzrtpContext(contextAlice, 0x12345678); } /* first parse a packet and then try good and bad zrtp-hash, then do it the other way : set the zrtp-hash and then parse packet */ void test_zrtphash(void) { bzrtpPacket_t *zrtpPacket; int retval; /* Create zrtp Context to use H0-H3 chains and others */ bzrtpContext_t *context12345678 = bzrtp_createBzrtpContext(); /* init the context so it's ready to receive a packet */ bzrtp_initBzrtpContext(context12345678, 0x12345678); /* parse the hello packet */ zrtpPacket = bzrtp_packetCheck(HelloPacketZrtpHash, sizeof(HelloPacketZrtpHash), 0, &retval); BC_ASSERT_EQUAL(retval, 0, int, "%d"); retval = bzrtp_packetParser(context12345678, context12345678->channelContext[0], HelloPacketZrtpHash, sizeof(HelloPacketZrtpHash), zrtpPacket); BC_ASSERT_EQUAL(retval, 0, int, "%d"); /* store it in the peer hello hash structure so we can check it against the zrtp-hash */ context12345678->channelContext[0]->peerPackets[HELLO_MESSAGE_STORE_ID] = zrtpPacket; retval = bzrtp_setPeerHelloHash(context12345678, 0x12345678, (uint8_t *)ZRTPHASHPATTERN, strlen((const char *)ZRTPHASHPATTERN)); BC_ASSERT_EQUAL(retval, 0, int, "%d"); /* set a wrong hello hash, this will also reset the session */ retval = bzrtp_setPeerHelloHash(context12345678, 0x12345678, (uint8_t *)ZRTPHASHPATTERN_WRONG, strlen((const char *)ZRTPHASHPATTERN)); BC_ASSERT_EQUAL(retval, BZRTP_ERROR_HELLOHASH_MISMATCH, int, "%d"); BC_ASSERT_TRUE(context12345678->channelContext[0]->peerPackets[HELLO_MESSAGE_STORE_ID]==NULL); /* session must have been reset, peer packets are cancelled */ /* Parse again the hello packet, the peer hello hash is still in the context and incorrect, so good packet must be rejected */ zrtpPacket = bzrtp_packetCheck(HelloPacketZrtpHash, sizeof(HelloPacketZrtpHash), 0, &retval); BC_ASSERT_EQUAL(retval, 0, int, "%d"); retval = bzrtp_packetParser(context12345678, context12345678->channelContext[0], HelloPacketZrtpHash, sizeof(HelloPacketZrtpHash), zrtpPacket); BC_ASSERT_EQUAL(retval, BZRTP_ERROR_HELLOHASH_MISMATCH, int, "%d"); /* set the correct peer hello hash(no packet in context so it just store it) and try again to parse the correct packet */ retval = bzrtp_setPeerHelloHash(context12345678, 0x12345678, (uint8_t *)ZRTPHASHPATTERN, strlen((const char *)ZRTPHASHPATTERN)); BC_ASSERT_EQUAL(retval, 0, int, "%d"); retval = bzrtp_packetParser(context12345678, context12345678->channelContext[0], HelloPacketZrtpHash, sizeof(HelloPacketZrtpHash), zrtpPacket); BC_ASSERT_EQUAL(retval, 0, int, "%d"); } bzrtp-1.0.6/test/bzrtpParserTest.h000066400000000000000000000017121313411235300171620ustar00rootroot00000000000000/** @file bzrtpCryptoTests.h @author Johan Pascal @copyright Copyright (C) 2014 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ void test_parser(void); void test_parser_hvi(void); void test_parserComplete(void); void test_stateMachine(void); void test_zrtphash(void); bzrtp-1.0.6/test/bzrtpTest.c000066400000000000000000000067511313411235300160100ustar00rootroot00000000000000/** @file bzrtpTests.c @author Johan Pascal @copyright Copyright (C) 2014 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "bzrtpCryptoTest.h" #include "bzrtpParserTest.h" #include "bzrtpConfigsTest.h" #include "bzrtpZidCacheTest.h" #include "typedef.h" #include "testUtils.h" #include #include test_t crypto_utils_tests[] = { TEST_NO_TAG("zrtpKDF", test_zrtpKDF), TEST_NO_TAG("CRC32", test_CRC32), TEST_NO_TAG("algo agreement", test_algoAgreement), TEST_NO_TAG("context algo setter and getter", test_algoSetterGetter), TEST_NO_TAG("adding mandatory crypto algorithms if needed", test_addMandatoryCryptoTypesIfNeeded) }; test_suite_t crypto_utils_test_suite = { "Crypto Utils", NULL, NULL, NULL, NULL, sizeof(crypto_utils_tests) / sizeof(crypto_utils_tests[0]), crypto_utils_tests }; test_t packet_parser_tests[] = { TEST_NO_TAG("Parse", test_parser), TEST_NO_TAG("Parse hvi check fail", test_parser_hvi), TEST_NO_TAG("Parse Exchange", test_parserComplete), TEST_NO_TAG("State machine", test_stateMachine), TEST_NO_TAG("ZRTP-hash", test_zrtphash) }; test_suite_t packet_parser_test_suite = { "Packet Parser", NULL, NULL, NULL, NULL, sizeof(packet_parser_tests) / sizeof(packet_parser_tests[0]), packet_parser_tests }; test_t zidcache_tests[] = { TEST_NO_TAG("SelfZID", test_cache_getSelfZID), TEST_NO_TAG("ZRTP secrets", test_cache_zrtpSecrets), TEST_NO_TAG("Migration", test_cache_migration), }; test_suite_t zidcache_test_suite = { "ZID Cache", NULL, NULL, NULL, NULL, sizeof(zidcache_tests) / sizeof(zidcache_tests[0]), zidcache_tests }; test_t key_exchange_tests[] = { TEST_NO_TAG("Cacheless multi channel", test_cacheless_exchange), TEST_NO_TAG("Cached Simple", test_cache_enabled_exchange), TEST_NO_TAG("Cached mismatch", test_cache_mismatch_exchange), TEST_NO_TAG("Loosy network", test_loosy_network), TEST_NO_TAG("Cached PVS", test_cache_sas_not_confirmed) }; test_suite_t key_exchange_test_suite = { "Key exchange", NULL, NULL, NULL, NULL, sizeof(key_exchange_tests) / sizeof(key_exchange_tests[0]), key_exchange_tests }; void bzrtp_tester_init(void) { bc_tester_init(NULL, BCTBX_LOG_MESSAGE, BCTBX_LOG_ERROR, NULL); bc_tester_add_suite(&crypto_utils_test_suite); bc_tester_add_suite(&packet_parser_test_suite); bc_tester_add_suite(&key_exchange_test_suite); bc_tester_add_suite(&zidcache_test_suite); } void bzrtp_tester_uninit(void) { bc_tester_uninit(); } int main(int argc, char *argv[]) { int i; int ret; bzrtp_tester_init(); for (i = 1; i < argc; ++i) { int ret = bc_tester_parse_args(argc, argv, i); if (ret > 0) { i += ret - 1; continue; } else if (ret < 0) { bc_tester_helper(argv[0], ""); } return ret; } ret = bc_tester_start(argv[0]); bzrtp_tester_uninit(); return ret; } bzrtp-1.0.6/test/bzrtpZidCacheTest.c000066400000000000000000000341411313411235300173750ustar00rootroot00000000000000/** @file bzrtpZidCacheTest.c @brief Test ZID cache operation @author Johan Pascal @copyright Copyright (C) 2017 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include "bzrtp/bzrtp.h" #include #include "testUtils.h" #include "zidCache.h" #ifdef ZIDCACHE_ENABLED #include "sqlite3.h" #ifdef HAVE_LIBXML2 #include #include #endif /* HAVE_LIBXML2 */ #endif /* ZIDCACHE_ENABLED */ static const char *xmlCacheMigration = "\n00112233445566778899aabb99887766554433221100ffeec4274f13a2b6fa05c15ec93158f930e7264b0a893393376dbc80c6eb1cccdc5asip:bob@sip.linphone.org219d9e445d10d4ed64083c7ccbb83a23bc17a97df0af5de4261f3fe026b05b0b747e72a5cc996413cb9fa6e3d18d8b370436e274cd6ba4efc1a4580340af57cadf2bf38e719fa89e17332cf8d5e774ee70d347baa74d16dee01f306c54789869928ce78b0bfc30427a02b1b668b2b3b0496d5664d7e89b75ed292ee97e3fc850496bcc8959337abe5dda11f388384b349d210612f30824268a3753a7afa52ef6df5866dca76315c4sip:bob2@sip.linphone.orgffeeddccbbaa987654321012858b495dfad483af3c088f26d68c4beebc638bd44feae45aea726a771727235esip:bob@sip.linphone.orgb6aac945057bc4466bfe9a23771c6a1b3b8d72ec3e7d8f30ed63cbc5a9479a25bea5ac3225edd0545b816f061a8190370e3ee5160e75404846a34d1580e0c26317ce70fdf12e500294bcb5f2ffef53096761bb1c912b21e972ae03a5a9f05c477e13a20e15a517700f0be0921f74b96d4b4a0c539d5e14d5cdd8706441874ac075e18caa2cfbbf061533dee20c8116dc2c282cae9adfea689b87bc4c6a4e18a846f12e3e7fea39590987654321fedcba5a5a5a5acb6ecc87d1dd87b23f225eec53a26fc541384917623e0c46abab8c0350c6929e92bb03988e8f0ccfefa37a55fd7c5893bea3bfbb27312f49dd9b10d0e3c15fc72315705a5830b98f68458fcd49623144cb34a667512c4d44686aee125bb8b62294c56eea0dd829379263b6da3f6ac0a95388090f168a3568736ca0bd9f8d595fc319ae0d41183fec90afc412d42253c5b456580f7a463c111c7293623b8631f4sip:bob@sip.linphone.org2c46ddcc15f5779e0000000058f095bf01"; void test_cache_getSelfZID(void) { #ifdef ZIDCACHE_ENABLED bzrtpContext_t *aliceContext; sqlite3 *aliceDB=NULL; uint8_t selfZIDalice[12]; uint8_t selfZIDecila[12]; char patternFilename[1024]; uint8_t patternZIDalice[12] = {0x42, 0x31, 0xf2, 0x9a, 0x6b, 0x14, 0xbc, 0xdf, 0x69, 0x72, 0x9f, 0xb8}; uint8_t patternZIDecila[12] = {0x17, 0x72, 0xae, 0x6b, 0x57, 0xb0, 0x3d, 0x99, 0x96, 0x3d, 0x63, 0xb2}; uint8_t patternZIDbob[12] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xed, 0xcb, 0xa9, 0x87}; char *resource_dir = (char *)bc_tester_get_resource_dir_prefix(); int ret,zuidalicebob=0, zuidCheck=0; /* write/read patterns: write rs1, rs2 and pvs, read also aux*/ int patternLength = 3; uint8_t rs1Value[] = {0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00}; uint8_t rs2Value[] = {0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, 0xff, 0xee}; uint8_t pvsValue[] = {0x1}; char *patternColNames[]={"rs1", "rs2", "pvs", "aux"}; uint8_t *patternColValues[] = {rs1Value, rs2Value, pvsValue}; size_t patternColValuesLength[] = {16, 16, 1}; uint8_t *readValues[] = {NULL, NULL, NULL,NULL}; size_t readLength[4]; int i; /* we need a bzrtp context */ aliceContext = bzrtp_createBzrtpContext(); /* create a new DB file */ remove("tmpZIDAlice.sqlite"); bzrtptester_sqlite3_open(bc_tester_file("tmpZIDAlice.sqlite"), &aliceDB); /* check what happend if we try to run cacheless */ BC_ASSERT_EQUAL(bzrtp_setZIDCache(aliceContext, NULL, "alice@sip.linphone.org", "bob@sip.linphone.org"),BZRTP_ZIDCACHE_RUNTIME_CACHELESS, int, "%x"); /* add real cache data into context using the dedicated function */ BC_ASSERT_EQUAL(bzrtp_setZIDCache(aliceContext, (void *)aliceDB, "alice@sip.linphone.org", "bob@sip.linphone.org"), BZRTP_CACHE_SETUP,int,"%x"); sqlite3_close(aliceDB); /* close the DB and reopen/init it, check the return value is now 0*/ bzrtptester_sqlite3_open(bc_tester_file("tmpZIDAlice.sqlite"), &aliceDB); BC_ASSERT_EQUAL(bzrtp_setZIDCache(aliceContext, (void *)aliceDB, "alice@sip.linphone.org", "bob@sip.linphone.org"), 0,int,"%x"); /* call to get selfZID, it will create the ZID for alice@sip.linphone.org. */ /* Note: in regular use we must call bzrtp_initBzrtpContext but here we are just testing the getSelfZID */ BC_ASSERT_EQUAL(bzrtp_getSelfZID(aliceContext->zidCache, aliceContext->selfURI, aliceContext->selfZID, aliceContext->RNGContext), 0, int, "%x"); /* get it again, in another buffer and compare */ BC_ASSERT_EQUAL(bzrtp_getSelfZID(aliceDB, "alice@sip.linphone.org", selfZIDalice, aliceContext->RNGContext), 0, int, "%x"); BC_ASSERT_EQUAL(memcmp(selfZIDalice, aliceContext->selfZID, 12), 0, int, "%d"); /* fetch a ZID for an other adress on the same cache, it shall create a new one */ BC_ASSERT_EQUAL(bzrtp_getSelfZID(aliceDB, "ecila@sip.linphone.org", aliceContext->selfZID, aliceContext->RNGContext), 0, int, "%x"); BC_ASSERT_NOT_EQUAL(memcmp(selfZIDalice, aliceContext->selfZID,12), 0, int, "%d"); /* check it is a different one */ /* fetch it again and compare */ BC_ASSERT_EQUAL(bzrtp_getSelfZID(aliceDB, "ecila@sip.linphone.org", selfZIDecila, aliceContext->RNGContext), 0, int, "%x"); BC_ASSERT_EQUAL(memcmp(selfZIDecila, aliceContext->selfZID, 12), 0, int, "%d"); /* fetch again the first one and compare */ BC_ASSERT_EQUAL(bzrtp_getSelfZID(aliceDB, "alice@sip.linphone.org", aliceContext->selfZID, aliceContext->RNGContext), 0, int, "%x"); BC_ASSERT_EQUAL(memcmp(selfZIDalice, aliceContext->selfZID, 12), 0, int, "%d"); /* try to get a zuid on alice/bob+patternZIDbob, at first the row shall be created */ BC_ASSERT_EQUAL(bzrtp_cache_getZuid((void *)aliceDB, "alice@sip.linphone.org", "bob@sip.linphone.org", patternZIDbob, &zuidalicebob), 0, int, "%x"); /* ask for it again and check they are the same */ BC_ASSERT_EQUAL(bzrtp_cache_getZuid((void *)aliceDB, "alice@sip.linphone.org", "bob@sip.linphone.org", patternZIDbob, &zuidCheck), 0, int, "%x"); BC_ASSERT_EQUAL(zuidalicebob, zuidCheck, int, "%d"); /* Then write in cache zrtp table */ BC_ASSERT_EQUAL(bzrtp_cache_write((void *)aliceDB, zuidalicebob, "zrtp", (char **)patternColNames, (uint8_t **)patternColValues, patternColValuesLength, patternLength), 0, int, "%x"); /* Try to write a zuid row in zrtp table while zuid is not present in ziduri table: it shall fail */ BC_ASSERT_EQUAL(bzrtp_cache_write((void *)aliceDB, zuidalicebob+10, "zrtp", (char **)patternColNames, (uint8_t **)patternColValues, patternColValuesLength, patternLength), BZRTP_ZIDCACHE_UNABLETOUPDATE, int, "%x"); /* Now read the data and check they're the same */ BC_ASSERT_EQUAL(bzrtp_cache_read((void *)aliceDB, zuidalicebob, "zrtp", (char **)patternColNames, readValues, readLength, patternLength+1), 0, int, "%x"); for (i=0; iRNGContext), 0, int, "%x"); BC_ASSERT_EQUAL(memcmp(selfZIDalice, patternZIDalice, 12), 0, int, "%x"); /* test the getZuid function */ BC_ASSERT_EQUAL(bzrtp_cache_getZuid((void *)aliceDB, "alice@sip.linphone.org", "bob@sip.linphone.org", patternZIDbob, &zuidalicebob), 0, int, "%x"); BC_ASSERT_EQUAL(zuidalicebob, 5, int, "%d"); /* from the pattern DB: the zuid for alice/bob+provided ZID is 5 */ BC_ASSERT_EQUAL(bzrtp_getSelfZID(aliceDB, "ecila@sip.linphone.org", selfZIDecila, aliceContext->RNGContext), 0, int, "%x"); BC_ASSERT_EQUAL(memcmp(selfZIDecila, patternZIDecila, 12), 0, int, "%x"); bzrtp_destroyBzrtpContext(aliceContext, 0); /* note: we didn't initialised any channel, so just give 0 to destroy, it will destroy the bzrtp context itself */ #else /* ZIDCACHE_ENABLED */ bzrtp_message("Test skipped as ZID cache is disabled\n"); #endif } void test_cache_zrtpSecrets(void) { #ifdef ZIDCACHE_ENABLED bzrtpContext_t *aliceContext; sqlite3 *aliceDB=NULL; uint8_t peerZIDbob[12] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xed, 0xcb, 0xa9, 0x87,}; uint8_t patternRs1[16] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x12}; uint8_t patternRs2[32] = {0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55}; uint8_t patternAux[27] = {0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x75, 0x78, 0x69, 0x6c, 0x69, 0x61, 0x72, 0x79, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74}; char patternFilename[1024]; char *resource_dir = (char *)bc_tester_get_resource_dir_prefix(); int ret; /* we need a bzrtp context */ aliceContext = bzrtp_createBzrtpContext(); /* open the pattern file and set it in the zrtp context as zidcache db */ sprintf(patternFilename, "%s/patternZIDAlice.sqlite", resource_dir); BC_ASSERT_EQUAL((ret = bzrtptester_sqlite3_open(bc_tester_file(patternFilename), &aliceDB)), SQLITE_OK, int, "0x%x"); if (ret != SQLITE_OK) { bzrtp_message("Error: unable to find patternZIDAlice.sqlite file. Did you set correctly the --resource-dir argument(current set: %s)", resource_dir==NULL?"NULL":resource_dir); return; } BC_ASSERT_EQUAL(bzrtp_setZIDCache(aliceContext, (void *)aliceDB, "alice@sip.linphone.org", "bob@sip.linphone.org"),0,int,"%x"); /* get Secrets */ BC_ASSERT_EQUAL(bzrtp_getPeerAssociatedSecrets(aliceContext, peerZIDbob), 0, int, "%x"); BC_ASSERT_EQUAL(aliceContext->zuid, 5, int, "%d"); BC_ASSERT_EQUAL(aliceContext->cachedSecret.rs1Length, 16, int, "%d"); BC_ASSERT_EQUAL(memcmp(aliceContext->cachedSecret.rs1,patternRs1, 16), 0, int, "%d"); BC_ASSERT_EQUAL(aliceContext->cachedSecret.rs2Length, 32, int, "%d"); BC_ASSERT_EQUAL(memcmp(aliceContext->cachedSecret.rs2,patternRs2, 32), 0, int, "%d"); BC_ASSERT_EQUAL(aliceContext->cachedSecret.auxsecretLength, 27, int, "%d"); BC_ASSERT_EQUAL(memcmp(aliceContext->cachedSecret.auxsecret,patternAux, 27), 0, int, "%d"); BC_ASSERT_EQUAL(aliceContext->cachedSecret.pbxsecretLength, 0, int, "%d"); BC_ASSERT_PTR_NULL(aliceContext->cachedSecret.pbxsecret); BC_ASSERT_EQUAL(aliceContext->cachedSecret.previouslyVerifiedSas, 1, int, "%d"); /* now try to retrieve secret for an unknow peer uri */ BC_ASSERT_EQUAL(bzrtp_setZIDCache(aliceContext, (void *)aliceDB, "alice@sip.linphone.org", "eve@sip.linphone.org"),0,int,"%x"); BC_ASSERT_EQUAL(bzrtp_getPeerAssociatedSecrets(aliceContext, peerZIDbob), 0, int, "%x"); BC_ASSERT_EQUAL(aliceContext->cachedSecret.rs1Length, 0, int, "%d"); BC_ASSERT_PTR_NULL(aliceContext->cachedSecret.rs1); BC_ASSERT_EQUAL(aliceContext->cachedSecret.rs2Length, 0, int, "%d"); BC_ASSERT_PTR_NULL(aliceContext->cachedSecret.rs2); BC_ASSERT_EQUAL(aliceContext->cachedSecret.auxsecretLength, 0, int, "%d"); BC_ASSERT_PTR_NULL(aliceContext->cachedSecret.auxsecret); BC_ASSERT_EQUAL(aliceContext->cachedSecret.pbxsecretLength, 0, int, "%d"); BC_ASSERT_PTR_NULL(aliceContext->cachedSecret.pbxsecret); BC_ASSERT_EQUAL(aliceContext->cachedSecret.previouslyVerifiedSas, 0, int, "%d"); #else /* ZIDCACHE_ENABLED */ bzrtp_message("Test skipped as ZID cache is disabled\n"); #endif /* ZIDCACHE_ENABLED */ } void test_cache_migration(void) { #ifdef ZIDCACHE_ENABLED uint8_t pattern_selfZIDalice[12] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb}; uint8_t selfZIDalice[12]; sqlite3 *aliceDB=NULL; /* Parse the xmlCache */ xmlDocPtr cacheXml = xmlParseDoc((xmlChar*)xmlCacheMigration); /* create a new DB file */ remove("tmpZIDAlice.sqlite"); bzrtptester_sqlite3_open(bc_tester_file("tmpZIDAlice.sqlite"), &aliceDB); BC_ASSERT_EQUAL(bzrtp_initCache((void *)aliceDB), BZRTP_CACHE_SETUP, int, "%x"); /* perform migration */ BC_ASSERT_EQUAL(bzrtp_cache_migration((void *)cacheXml, (void *)aliceDB, "sip:alice@sip.linphone.org"), 0, int, "%x"); /* check values in new cache */ BC_ASSERT_EQUAL(bzrtp_getSelfZID(aliceDB, "sip:alice@sip.linphone.org", selfZIDalice, NULL), 0, int, "%x"); BC_ASSERT_EQUAL(memcmp(pattern_selfZIDalice, selfZIDalice, 12), 0, int, "%d"); /* TODO: read values from sql cache lime and zrtp tables and check they are the expected ones */ /* cleaning */ sqlite3_close(aliceDB); xmlFree(cacheXml); #else /* ZIDCACHE_ENABLED */ bzrtp_message("Test skipped as ZID cache is disabled\n"); #endif /* ZIDCACHE_ENABLED */ } bzrtp-1.0.6/test/bzrtpZidCacheTest.h000066400000000000000000000016421313411235300174020ustar00rootroot00000000000000/** @file bzrtpZidCacheTest.h @author Johan Pascal @copyright Copyright (C) 2017 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ void test_cache_getSelfZID(void); void test_cache_zrtpSecrets(void); void test_cache_migration(void); bzrtp-1.0.6/test/patternZIDAlice.sqlite000066400000000000000000000240001313411235300200330ustar00rootroot00000000000000SQLite format 3@ 8 88-â)û û ČÓŠïi,Č;$95alice@sip.linphone.orgeve@sip.linphone.org;$95"3DUfwˆ™Ș»Ìalice@sip.linphone.orgbob@sip.linphone.org;$95"3DUfwˆ™Ș»Ìecila@sip.linphone.orgbob@sip.linphone.org;$95#Eg‰«ÍïíË©‡alice@sip.linphone.orgbob@sip.linphone.org+$9rźkW°=™–=cČecila@sip.linphone.orgself+$9B1òškŒßirŸžalice@sip.linphone.orgself ôôÉ ziduri gȘgA,47""33DDUUffwwˆˆwĘwĘwĘwĘwĘwĘwĘwĘwĘwĘthis is also a secretT,LB4VxšŒȚțÜș˜vT2ȘUȘUȘUȘUȘUȘUȘUȘUȘUȘUȘUȘUȘUȘUȘUȘUthis is an auxiliary secret őûő   ȚüöäđêȚ ź/ćzz+?indexsqlite_autoindex_ziduri_1ziduricƒ!tableziduriziduriCREATE TABLE "ziduri" ( `zuid` INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE, `zid` BLOB NOT NULL DEFAULT '00000000000', `selfuri` TEXT NOT NULL DEFAULT 'unset', `peeruri` TEXT NOT NULL DEFAULT 'unset' )™P++Ytablesqlite_sequencesqlite_sequenceCREATE TABLE sqlite_sequence(name,seq)  ą!ÏŠ!y‚U&… tablelimelimeCREATE TABLE lime (zuid INTEGER NOT NULL DEFAULT 0 UNIQUE,sndKey BLOB DEFAULT NULL,rcvKey BLOB DEFAULT NULL,sndSId BLOB DEFAULT NULL,rcvSId BLOB DEFAULT NULL,sndIndex BLOB DEFAULT NULL,rcvIndex BLOB DEFAULT NULL,valid BLOB DEFAULT NULL,FOREIGN KEY(zuid) REFERENCES ziduri(zuid) ON UPDATE CASCADE ON DELETE CASCADE)'';indexsqlite_autoindex_lime_1lime '%;indexsqlite_autoindex_zrtp_1zrtp‚.$„?tablezrtpzrtpCREATE TABLE "zrtp" ( `zuid` INTEGER NOT NULL DEFAULT 0 UNIQUE, `rs1` BLOB DEFAULT NULL, `rs2` BLOB DEFAULT NULL, `aux` BLOB DEFAULT NULL, `pbx` BLOB DEFAULT NULL, `pvs` BLOB DEFAULT NULL, FOREIGN KEY(`zuid`) REFERENCES `ziduri`(`zuid`) ON UPDATE CASCADE ON DELETE CASCADE )bzrtp-1.0.6/test/testUtils.c000066400000000000000000000322771313411235300160110ustar00rootroot00000000000000/** @file testUtils.c @author Johan Pascal @copyright Copyright (C) 2014 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include "testUtils.h" #include "cryptoUtils.h" #ifndef _WIN32 #if !defined(__QNXNTO__) && !(defined(__ANDROID__) && defined(__LP64__)) #include #include #endif #else #include #endif int verbose = 0; /* trace functions: bzrtp algo code to string */ const char *bzrtp_hash_toString(uint8_t hashAlgo) { switch(hashAlgo) { case(ZRTP_UNSET_ALGO): return "unset"; case(ZRTP_HASH_S256): return "SHA-256"; case(ZRTP_HASH_S384): return "SHA-384"; case(ZRTP_HASH_N256): return "SHA3-256"; case(ZRTP_HASH_N384): return "SHA3-384"; default: return "Unknown Algo"; } } const char *bzrtp_keyAgreement_toString(uint8_t keyAgreementAlgo) { switch(keyAgreementAlgo) { case(ZRTP_UNSET_ALGO): return "unset"; case(ZRTP_KEYAGREEMENT_DH2k): return "DHM-2048"; case(ZRTP_KEYAGREEMENT_EC25): return "ECDH-256"; case(ZRTP_KEYAGREEMENT_DH3k): return "DHM-3072"; case(ZRTP_KEYAGREEMENT_EC38): return "ECDH-384"; case(ZRTP_KEYAGREEMENT_EC52): return "ECDH-521"; case(ZRTP_KEYAGREEMENT_Prsh): return "PreShared"; case(ZRTP_KEYAGREEMENT_Mult): return "MultiStream"; default: return "Unknown Algo"; } } const char *bzrtp_cipher_toString(uint8_t cipherAlgo) { switch(cipherAlgo) { case(ZRTP_UNSET_ALGO): return "unset"; case(ZRTP_CIPHER_AES1): return "AES-128"; case(ZRTP_CIPHER_AES2): return "AES-192"; case(ZRTP_CIPHER_AES3): return "AES-256"; case(ZRTP_CIPHER_2FS1): return "TwoFish-128"; case(ZRTP_CIPHER_2FS2): return "TwoFish-192"; case(ZRTP_CIPHER_2FS3): return "TwoFish-256"; default: return "Unknown Algo"; } } const char *bzrtp_authtag_toString(uint8_t authtagAlgo) { switch(authtagAlgo) { case(ZRTP_UNSET_ALGO): return "unset"; case(ZRTP_AUTHTAG_HS32): return "HMAC-SHA1-32"; case(ZRTP_AUTHTAG_HS80): return "HMAC-SHA1-80"; case(ZRTP_AUTHTAG_SK32): return "Skein-32"; case(ZRTP_AUTHTAG_SK64): return "Skein-64"; default: return "Unknown Algo"; } } const char *bzrtp_sas_toString(uint8_t sasAlgo) { switch(sasAlgo) { case(ZRTP_UNSET_ALGO): return "unset"; case(ZRTP_SAS_B32): return "Base32"; case(ZRTP_SAS_B256): return "PGP-WordList"; default: return "Unknown Algo"; } } void bzrtp_message(const char *fmt, ...) { if (verbose) { va_list args; va_start(args, fmt); vprintf(fmt, args); va_end(args); fflush(NULL); } } void printHex(char *title, uint8_t *data, uint32_t length) { if (verbose) { uint32_t i; printf ("%s : ", title); for (i=0; isourceIdentifier, zrtpPacket->messageLength); if (zrtpPacket->packetString!=NULL) { /* paquet has been built and we need to get his sequence number in the packetString */ printf ("Sequence number: %02x%02x", *(zrtpPacket->packetString+2), *(zrtpPacket->packetString+3)); } else { /* packet has been parsed, so get his sequence number in the structure */ printf ("Sequence number: %04x", zrtpPacket->sequenceNumber); } switch (zrtpPacket->messageType) { case MSGTYPE_HELLO : { bzrtpHelloMessage_t *messageData; uint8_t algoTypeString[4]; printf(" - Message Type : Hello\n"); messageData = (bzrtpHelloMessage_t *)zrtpPacket->messageData; printf ("Version %.4s\nIdentifier %.16s\n", messageData->version, messageData->clientIdentifier); printHex ("H3", messageData->H3, 32); printHex ("ZID", messageData->ZID, 12); printf ("S : %d - M : %d - P : %d\nhc : %x - cc : %x - ac : %x - kc : %x - sc : %x\n", messageData->S, messageData->M, messageData->P, messageData->hc, messageData->cc, messageData->ac, messageData->kc, messageData->sc); printf ("hc "); for (j=0; jhc; j++) { bzrtp_cryptoAlgoTypeIntToString(messageData->supportedHash[j], algoTypeString); printf("%.4s, ", algoTypeString); } printf ("\ncc "); for (j=0; jcc; j++) { bzrtp_cryptoAlgoTypeIntToString(messageData->supportedCipher[j], algoTypeString); printf("%.4s, ", algoTypeString); } printf ("\nac "); for (j=0; jac; j++) { bzrtp_cryptoAlgoTypeIntToString(messageData->supportedAuthTag[j], algoTypeString); printf("%.4s, ", algoTypeString); } printf ("\nkc "); for (j=0; jkc; j++) { bzrtp_cryptoAlgoTypeIntToString(messageData->supportedKeyAgreement[j], algoTypeString); printf("%.4s, ", algoTypeString); } printf ("\nsc "); for (j=0; jsc; j++) { bzrtp_cryptoAlgoTypeIntToString(messageData->supportedSas[j], algoTypeString); printf("%.4s, ", algoTypeString); } printHex("\nMAC", messageData->MAC, 8); } break; /* MSGTYPE_HELLO */ case MSGTYPE_HELLOACK : { printf(" - Message Type : Hello ACK\n"); } break; case MSGTYPE_COMMIT: { uint8_t algoTypeString[4]; bzrtpCommitMessage_t *messageData; printf(" - Message Type : Commit\n"); messageData = (bzrtpCommitMessage_t *)zrtpPacket->messageData; printHex("H2", messageData->H2, 32); printHex("ZID", messageData->ZID, 12); bzrtp_cryptoAlgoTypeIntToString(messageData->hashAlgo, algoTypeString); printf("Hash Algo: %.4s\n", algoTypeString); bzrtp_cryptoAlgoTypeIntToString(messageData->cipherAlgo, algoTypeString); printf("Cipher Algo: %.4s\n", algoTypeString); bzrtp_cryptoAlgoTypeIntToString(messageData->authTagAlgo, algoTypeString); printf("Auth tag Algo: %.4s\n", algoTypeString); bzrtp_cryptoAlgoTypeIntToString(messageData->keyAgreementAlgo, algoTypeString); printf("Key agreement Algo: %.4s\n", algoTypeString); bzrtp_cryptoAlgoTypeIntToString(messageData->sasAlgo, algoTypeString); printf("Sas Algo: %.4s\n", algoTypeString); /* if it is a multistream or preshared commit, get the 16 bytes nonce */ if ((messageData->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Prsh) || (messageData->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Mult)) { printHex("Nonce", messageData->nonce, 16); /* and the keyID for preshared commit only */ if (messageData->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Prsh) { printHex("KeyId", messageData->keyID, 8); } } else { /* it's a DH commit message, get the hvi */ printHex("hvi", messageData->hvi, 32); } printHex("\nMAC", messageData->MAC, 8); } break; case MSGTYPE_DHPART1: case MSGTYPE_DHPART2: { bzrtpDHPartMessage_t *messageData; if (zrtpPacket->messageType == MSGTYPE_DHPART1) { printf(" - Message Type : DHPart1\n"); } else { printf(" - Message Type : DHPart2\n"); } messageData = (bzrtpDHPartMessage_t *)zrtpPacket->messageData; printHex ("H1", messageData->H1, 32); printHex ("rs1ID", messageData->rs1ID, 8); printHex ("rs2ID", messageData->rs2ID, 8); printHex ("auxsecretID", messageData->auxsecretID, 8); printHex ("pbxsecretID", messageData->pbxsecretID, 8); printHex ("rs1ID", messageData->rs1ID, 8); printf("PV length is %d\n", (zrtpPacket->messageLength-84)); printHex ("PV", messageData->pv, (zrtpPacket->messageLength-84)); /* length of fixed part of the message is 84, rest is the variable length PV */ printHex("MAC", messageData->MAC, 8); } break; case MSGTYPE_CONFIRM1: case MSGTYPE_CONFIRM2: { bzrtpConfirmMessage_t *messageData; if (zrtpPacket->messageType == MSGTYPE_CONFIRM1) { printf(" - Message Type : Confirm1\n"); } else { printf(" - Message Type : Confirm2\n"); } messageData = (bzrtpConfirmMessage_t *)zrtpPacket->messageData; printHex("H0", messageData->H0, 32); printf("sig_len %d\n", messageData->sig_len); printf("E %d V %d A %d D %d\n", messageData->E, messageData->V, messageData->A, messageData->D); printf("Cache expiration Interval %08x\n", messageData->cacheExpirationInterval); } break; case MSGTYPE_CONF2ACK: { printf(" - Message Type: Conf2ACK\n"); } } if (addRawMessage) { printHex("Data", zrtpPacket->packetString, zrtpPacket->messageLength+16); } fflush(NULL); } } void dumpContext(char *title, bzrtpContext_t *zrtpContext) { if (verbose) { uint8_t buffer[4]; int i,j; printf("%s context is :\n", title); printHex("selfZID", zrtpContext->selfZID, 12); printHex("peerZID", zrtpContext->peerZID, 12); for (i=0; ichannelContext[i] != NULL) { bzrtpChannelContext_t *channelContext = zrtpContext->channelContext[i]; printf("Channel %i\n self: %08x\n", i, channelContext->selfSSRC); printf (" selfH: "); for (j=0; j<4; j++) { printHex(" ", channelContext->selfH[j], 32); } printf (" peerH: "); for (j=0; j<4; j++) { printHex(" ", channelContext->peerH[j], 32); } bzrtp_cryptoAlgoTypeIntToString(channelContext->hashAlgo, buffer); printf(" Selected algos\n - Hash: %.4s\n", buffer); bzrtp_cryptoAlgoTypeIntToString(channelContext->cipherAlgo, buffer); printf(" - cipher: %.4s\n", buffer); bzrtp_cryptoAlgoTypeIntToString(channelContext->authTagAlgo, buffer); printf(" - auth tag: %.4s\n", buffer); bzrtp_cryptoAlgoTypeIntToString(channelContext->keyAgreementAlgo, buffer); printf(" - key agreement: %.4s\n", buffer); bzrtp_cryptoAlgoTypeIntToString(channelContext->sasAlgo, buffer); printf(" - sas: %.4s\n", buffer); printHex(" initiator auxID", channelContext->initiatorAuxsecretID, 8); printHex(" responder auxID", channelContext->responderAuxsecretID, 8); if (channelContext->s0 != NULL) { printHex(" s0", channelContext->s0, channelContext->hashLength); } if(channelContext->srtpSecrets.sas != NULL) { printf(" sas : %.4s\n", channelContext->srtpSecrets.sas); } if (channelContext->srtpSecrets.selfSrtpKey != NULL) { printHex(" selfsrtp key", channelContext->srtpSecrets.selfSrtpKey, channelContext->srtpSecrets.selfSrtpKeyLength); printHex(" selfsrtp salt", channelContext->srtpSecrets.selfSrtpSalt, channelContext->srtpSecrets.selfSrtpSaltLength); printHex(" peersrtp key", channelContext->srtpSecrets.peerSrtpKey, channelContext->srtpSecrets.peerSrtpKeyLength); printHex(" peersrtp salt", channelContext->srtpSecrets.peerSrtpSalt, channelContext->srtpSecrets.peerSrtpSaltLength); } if (channelContext->mackeyi!=NULL) { printHex(" mackeyi", channelContext->mackeyi, channelContext->hashLength); } if (channelContext->mackeyr!=NULL) { printHex(" mackeyr", channelContext->mackeyr, channelContext->hashLength); } if (channelContext->zrtpkeyi!=NULL) { printHex(" zrtpkeyi", channelContext->zrtpkeyi, channelContext->cipherKeyLength); } if (channelContext->zrtpkeyr!=NULL) { printHex(" zrtpkeyr", channelContext->zrtpkeyr, channelContext->cipherKeyLength); } } } printf("Initiator Shared Secrets :\n"); printHex("rs1ID", zrtpContext->initiatorCachedSecretHash.rs1ID, 8); printHex("rs2ID", zrtpContext->initiatorCachedSecretHash.rs2ID, 8); printHex("pbxID", zrtpContext->initiatorCachedSecretHash.pbxsecretID, 8); printf("Responder Shared Secrets :\n"); printHex("rs1ID", zrtpContext->responderCachedSecretHash.rs1ID, 8); printHex("rs2ID", zrtpContext->responderCachedSecretHash.rs2ID, 8); printHex("pbxID", zrtpContext->responderCachedSecretHash.pbxsecretID, 8); fflush(NULL); } } #ifdef ZIDCACHE_ENABLED #define MAX_PATH_SIZE 1024 int bzrtptester_sqlite3_open(const char *db_file, sqlite3 **db) { char* errmsg = NULL; int ret; int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; #if TARGET_OS_IPHONE /* the secured filesystem of the iPHone doesn't allow writing while the app is in background mode, which is problematic. * We workaround by asking that the open is made with no protection*/ flags |= SQLITE_OPEN_FILEPROTECTION_NONE; #endif ret = sqlite3_open_v2(db_file, db, flags, NULL); if (ret != SQLITE_OK) return ret; // Some platforms do not provide a way to create temporary files which are needed // for transactions... so we work in memory only // see http ://www.sqlite.org/compile.html#temp_store ret = sqlite3_exec(*db, "PRAGMA temp_store=MEMORY", NULL, NULL, &errmsg); if (ret != SQLITE_OK) { sqlite3_free(errmsg); } return ret; } #endif /* ZIDCACHE_ENABLED */ bzrtp-1.0.6/test/testUtils.h000066400000000000000000000030051313411235300160010ustar00rootroot00000000000000/** @file testUtils.c @author Johan Pascal @copyright Copyright (C) 2014 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "typedef.h" #include "packetParser.h" extern int verbose; void bzrtp_message(const char *fmt, ...); void printHex(char *title, uint8_t *data, uint32_t length); void packetDump(bzrtpPacket_t *zrtpPacket, uint8_t addRawMessage); void dumpContext(char *title, bzrtpContext_t *zrtpContext); const char *bzrtp_hash_toString(uint8_t hashAlgo); const char *bzrtp_keyAgreement_toString(uint8_t keyAgreementAlgo); const char *bzrtp_cipher_toString(uint8_t cipherAlgo); const char *bzrtp_authtag_toString(uint8_t authtagAlgo); const char *bzrtp_sas_toString(uint8_t sasAlgo); #ifdef ZIDCACHE_ENABLED int bzrtptester_sqlite3_open(const char *db_file, sqlite3 **db); #endif /* ZIDCACHE_ENABLED */