pax_global_header00006660000000000000000000000064125227043070014514gustar00rootroot0000000000000052 comment=6eb5fdd6d187ee2ecfe715f92c1c68a71d7df8b2 bzrtp-1.0.2/000077500000000000000000000000001252270430700126555ustar00rootroot00000000000000bzrtp-1.0.2/.gitignore000066400000000000000000000004651252270430700146520ustar00rootroot00000000000000Makefile 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.2/AUTHORS000066400000000000000000000000751252270430700137270ustar00rootroot00000000000000Copyright 2014 Belledonne Communications SARL. Johan Pascal bzrtp-1.0.2/Android.mk000066400000000000000000000011231252270430700145630ustar00rootroot00000000000000LOCAL_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/cryptoPolarssl.c \ src/cryptoUtils.c \ src/packetParser.c \ src/stateMachine.c \ src/zidCache.c \ src/pgpwords.c LOCAL_STATIC_LIBRARIES += polarssl \ liblpxml2 LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/include \ $(LOCAL_PATH)/../externals/polarssl/include \ $(LOCAL_PATH)/../externals/libxml2/include \ $(LOCAL_PATH)/../externals/build/libxml2 include $(BUILD_STATIC_LIBRARY) bzrtp-1.0.2/CMakeLists.txt000066400000000000000000000067601252270430700154260ustar00rootroot00000000000000############################################################################ # 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################ cmake_minimum_required(VERSION 3.0) project(BZRTP C) set(BZRTP_VERSION 1.0.2) option(ENABLE_STATIC "Build static library (default is shared library)." NO) option(ENABLE_UNIT_TESTS "Enable compilation of unit tests." NO) 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(CheckLibraryExists) check_library_exists("m" "sqrt" "" HAVE_SQRT) if(ENABLE_TESTS) find_package(CUnit) if(CUNIT_FOUND) check_library_exists(${CUNIT_LIBRARIES} "CU_add_suite" "" HAVE_CU_ADD_SUITE) check_library_exists(${CUNIT_LIBRARIES} "CU_get_suite" "" HAVE_CU_GET_SUITE) check_library_exists(${CUNIT_LIBRARIES} "CU_curses_run_tests" "" HAVE_CU_CURSES) else() message(WARNING "Could not find cunit framework, tests will not be compiled.") set(ENABLE_TESTS OFF CACHE BOOL "Enable compilation of tests" FORCE) endif() endif() find_package(PolarSSL REQUIRED) find_package(XML2) if(XML2_FOUND) set(HAVE_LIBXML2 1) 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") include_directories( include ${CMAKE_CURRENT_BINARY_DIR} ${POLARSSL_INCLUDE_DIRS} ) set(LIBS ${POLARSSL_LIBRARIES}) if(CUNIT_FOUND) include_directories(${CUNIT_INCLUDE_DIRS}) list(APPEND LIBS ${CUNIT_LIBRARIES}) endif() if(XML2_FOUND) include_directories(${XML2_INCLUDE_DIRS}) list(APPEND LIBS ${XML2_LIBRARIES}) endif() if(MSVC) include_directories(${MSVC_INCLUDE_DIR}) endif() add_subdirectory(include) add_subdirectory(src) if(ENABLE_TESTS) enable_testing() add_subdirectory(test) endif() include(CMakePackageConfigHelpers) write_basic_package_version_file( "${CMAKE_CURRENT_BINARY_DIR}/BZRTPConfigVersion.cmake" VERSION ${BZRTP_VERSION} COMPATIBILITY AnyNewerVersion ) export(EXPORT BZRTPTargets FILE "${CMAKE_CURRENT_BINARY_DIR}/BZRTPTargets.cmake" NAMESPACE BelledonneCommunications:: ) configure_file(cmake/BZRTPConfig.cmake "${CMAKE_CURRENT_BINARY_DIR}/BZRTPConfig.cmake" COPYONLY ) set(ConfigPackageLocation lib/cmake/BZRTP) install(EXPORT BZRTPTargets FILE BZRTPTargets.cmake NAMESPACE BelledonneCommunications:: DESTINATION ${ConfigPackageLocation} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/BZRTPConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/BZRTPConfigVersion.cmake" DESTINATION ${ConfigPackageLocation} ) bzrtp-1.0.2/COPYING000066400000000000000000000431101252270430700137070ustar00rootroot00000000000000 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.2/ChangeLog000066400000000000000000000000001252270430700144150ustar00rootroot00000000000000bzrtp-1.0.2/Makefile.am000066400000000000000000000002261252270430700147110ustar00rootroot00000000000000ACLOCAL_AMFLAGS = -I m4 SUBDIRS = src include test test: cd test && $(MAKE) test pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libbzrtp.pc bzrtp-1.0.2/NEWS000066400000000000000000000001761252270430700133600ustar00rootroot00000000000000bzrtp-1.0.2 - Thursday, May 7th 2.15 * bug fixes bzrtp-1.0.0 - Thursday, March 5th 2015 * first official release of bzrtp bzrtp-1.0.2/README000066400000000000000000000021131252270430700135320ustar00rootroot00000000000000bzrtp 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. By default, the upstream package installs into /usr/local. Please use './configure --prefix' to change it Linphone plugin is compiled if both mediastremer2 and ortp are installed ---------------------------------------------------------------------------------- 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 - key agreement DH2048 *** Optional and NOT implemented - zrtp-hash attribute in SDP - Go Clear/Clear ACK messages - SAS signing bzrtp-1.0.2/autogen.sh000077500000000000000000000013551252270430700146620ustar00rootroot00000000000000#!/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.2/cmake/000077500000000000000000000000001252270430700137355ustar00rootroot00000000000000bzrtp-1.0.2/cmake/BZRTPConfig.cmake000066400000000000000000000027461252270430700167770ustar00rootroot00000000000000############################################################################ # 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 include("${CMAKE_CURRENT_LIST_DIR}/BZRTPTargets.cmake") get_filename_component(BZRTP_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) set(BZRTP_INCLUDE_DIRS "${BZRTP_CMAKE_DIR}/../../../include") set(BZRTP_LIBRARIES BelledonneCommunications::bzrtp) set(BZRTP_FOUND 1) bzrtp-1.0.2/cmake/FindCUnit.cmake000066400000000000000000000033331252270430700165640ustar00rootroot00000000000000############################################################################ # FindCUnit.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################ # # - Find the CUnit include file and library # # CUNIT_FOUND - system has CUnit # CUNIT_INCLUDE_DIRS - the CUnit include directory # CUNIT_LIBRARIES - The libraries needed to use CUnit include(CheckIncludeFile) include(CheckLibraryExists) set(_CUNIT_ROOT_PATHS ${CMAKE_INSTALL_PREFIX} ) find_path(CUNIT_INCLUDE_DIRS NAMES CUnit/CUnit.h HINTS _CUNIT_ROOT_PATHS PATH_SUFFIXES include ) if(CUNIT_INCLUDE_DIRS) set(HAVE_CUNIT_CUNIT_H 1) endif() find_library(CUNIT_LIBRARIES NAMES cunit HINTS ${_CUNIT_ROOT_PATHS} PATH_SUFFIXES bin lib ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(CUnit DEFAULT_MSG CUNIT_INCLUDE_DIRS CUNIT_LIBRARIES ) mark_as_advanced(CUNIT_INCLUDE_DIRS CUNIT_LIBRARIES) bzrtp-1.0.2/cmake/FindPolarSSL.cmake000066400000000000000000000047651252270430700172130ustar00rootroot00000000000000############################################################################ # FindPolarSSL.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################ # # - Find the polarssl include file and library # # POLARSSL_FOUND - system has polarssl # POLARSSL_INCLUDE_DIRS - the polarssl include directory # POLARSSL_LIBRARIES - The libraries needed to use polarssl include(CMakePushCheckState) include(CheckIncludeFile) include(CheckCSourceCompiles) include(CheckSymbolExists) set(_POLARSSL_ROOT_PATHS ${CMAKE_INSTALL_PREFIX} ) find_path(POLARSSL_INCLUDE_DIRS NAMES polarssl/ssl.h HINTS _POLARSSL_ROOT_PATHS PATH_SUFFIXES include ) if(POLARSSL_INCLUDE_DIRS) set(HAVE_POLARSSL_SSL_H 1) endif() find_library(POLARSSL_LIBRARIES NAMES polarssl HINTS _POLARSSL_ROOT_PATHS PATH_SUFFIXES bin lib ) if(POLARSSL_LIBRARIES) cmake_push_check_state(RESET) set(CMAKE_REQUIRED_INCLUDES ${POLARSSL_INCLUDE_DIRS}) set(CMAKE_REQUIRED_LIBRARIES ${POLARSSL_LIBRARIES}) check_c_source_compiles("#include #include #if POLARSSL_VERSION_NUMBER >= 0x01030000 #include #endif int main(int argc, char *argv[]) { x509parse_crtpath(0,0); return 0; }" X509PARSE_CRTPATH_OK) check_symbol_exists(ssl_get_dtls_srtp_protection_profile "polarssl/ssl.h" HAVE_SSL_GET_DTLS_SRTP_PROTECTION_PROFILE) cmake_pop_check_state() endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(PolarSSL DEFAULT_MSG POLARSSL_INCLUDE_DIRS POLARSSL_LIBRARIES HAVE_POLARSSL_SSL_H ) mark_as_advanced(POLARSSL_INCLUDE_DIRS POLARSSL_LIBRARIES HAVE_POLARSSL_SSL_H X509PARSE_CRTPATH_OK HAVE_SSL_GET_DTLS_SRTP_PROTECTION_PROFILE) bzrtp-1.0.2/cmake/FindXML2.cmake000066400000000000000000000032561252270430700162700ustar00rootroot00000000000000############################################################################ # 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 set(_XML2_ROOT_PATHS ${CMAKE_INSTALL_PREFIX} ) find_path(XML2_INCLUDE_DIRS NAMES libxml/xmlreader.h HINTS _XML2_ROOT_PATHS PATH_SUFFIXES include/libxml2 ) if(XML2_INCLUDE_DIRS) set(HAVE_LIBXML_XMLREADER_H 1) endif() find_library(XML2_LIBRARIES NAMES xml2 HINTS ${_XML2_ROOT_PATHS} PATH_SUFFIXES bin lib ) 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.2/config.h.cmake000066400000000000000000000021641252270430700153550ustar00rootroot00000000000000/*************************************************************************** * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ****************************************************************************/ #cmakedefine HAVE_CU_ADD_SUITE #cmakedefine HAVE_CU_GET_SUITE #cmakedefine HAVE_CU_CURSES #cmakedefine HAVE_LIBXML2 bzrtp-1.0.2/configure.ac000066400000000000000000000053501252270430700151460ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_INIT([bzrtp],[1.0.2]) 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]) 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(CUNIT, cunit, [found_cunit=yes],[found_cunit=no]) if test "$found_cunit" = "no" ; then AC_CHECK_HEADERS(CUnit/CUnit.h, [ AC_CHECK_LIB(cunit,CU_add_suite,[ found_cunit=yes CUNIT_LIBS+=" -lcunit" ]) ]) fi dnl check polarssl AC_ARG_WITH( polarssl, [ --with-polarssl Set prefix where polarssl can be found (ex:/usr, /usr/local)[default=PREFIX] ], [ polarssl_prefix=${withval}],[ polarssl_prefix=${prefix} ]) if test "$polarssl_prefix" != "NONE" ; then POLARSSL_CFLAGS="-I${polarssl_prefix}/include" POLARSSL_LIBS="-L${polarssl_prefix}/lib" fi POLARSSL_LIBS="$POLARSSL_LIBS -lpolarssl" AC_SUBST(POLARSSL_LIBS) AC_SUBST(POLARSSL_CFLAGS) dnl check libxml2 PKG_CHECK_MODULES(LIBXML2, [libxml-2.0] ,[libxml2_found=yes] ,foo=bar) if test "$libxml2_found" != "yes" ; then AC_MSG_WARN([libxml2 not found. Disabling cache.]) else AC_DEFINE(HAVE_LIBXML2,1,[defined when libxml2 is available]) fi if test "$found_cunit" = "no" ; then AC_MSG_WARN([Could not find cunit framework, tests are not compiled.]) else AC_CHECK_LIB(cunit,CU_get_suite,[ AC_DEFINE(HAVE_CU_GET_SUITE,1,[defined when CU_get_suite is available]) ],[foo=bar],[$CUNIT_LIBS]) AC_CHECK_LIB(cunit,CU_curses_run_tests,[ AC_DEFINE(HAVE_CU_CURSES,1,[defined when CU_curses_run_tests is available]) ],[foo=bar],[$CUNIT_LIBS]) 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_cunit = 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 " 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.2/include/000077500000000000000000000000001252270430700143005ustar00rootroot00000000000000bzrtp-1.0.2/include/CMakeLists.txt000066400000000000000000000002471252270430700170430ustar00rootroot00000000000000file(GLOB HEADER_FILES "bzrtp/*.h") install(FILES ${HEADER_FILES} DESTINATION include/bzrtp PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) bzrtp-1.0.2/include/MSVC/000077500000000000000000000000001252270430700150505ustar00rootroot00000000000000bzrtp-1.0.2/include/MSVC/stdint.h000066400000000000000000000170601252270430700165320ustar00rootroot00000000000000// 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.2/include/Makefile.am000066400000000000000000000001561252270430700163360ustar00rootroot00000000000000SUBDIRS = bzrtp EXTRA_DIST=cryptoUtils.h cryptoWrapper.h packetParser.h stateMachine.h typedef.h zidCache.h bzrtp-1.0.2/include/bzrtp/000077500000000000000000000000001252270430700154415ustar00rootroot00000000000000bzrtp-1.0.2/include/bzrtp/Makefile.am000066400000000000000000000001521252270430700174730ustar00rootroot00000000000000bzrtp_includedir=$(includedir)/bzrtp bzrtp_include_HEADERS= bzrtp.h EXTRA_DIST=$(bzrtp_include_HEADERS) bzrtp-1.0.2/include/bzrtp/bzrtp.h000066400000000000000000000342751252270430700167660ustar00rootroot00000000000000/** @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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef BZRTP_H #define BZRTP_H #include #ifdef _MSC_VER #define BZRTP_EXPORT __declspec(dllexport) #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 */ 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 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 */ } bzrtpSrtpSecrets_t; /** * 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 { /* cache related functions */ int (* bzrtp_loadCache)(void *clientData, uint8_t **cacheBuffer, uint32_t *cacheBufferSize, zrtpFreeBuffer_callback *callback); /**< Cache related function : load the whole cache file in a buffer allocated by the function, return the buffer and its size in bytes */ int (* bzrtp_writeCache)(void *clientData, const uint8_t *input, uint32_t size); /**< Cache related function : write size bytes to cache */ /* 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, 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 char* sas, int32_t verified); /**< ZRTP process ended well, client is given the SAS and may start his SRTP session if not done when calling srtpSecretsAvailable */ /* ready for exported keys */ int (* bzrtp_contextReadyForExportedKeys)(void *clientData, uint8_t peerZID[12], uint8_t role); /**< Tell the client that this is the time to create and store in cache any exported keys, client is given the peerZID 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" #define ZRTP_CLIENT_IDENTIFIER "BZRTP" /* 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 /** * @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 * A channel context is created when creating the zrtp context. * * @param[in] selfSSRC The SSRC given to the channel context created within the zrtpContext * * @return The ZRTP engine context data * */ BZRTP_EXPORT bzrtpContext_t *bzrtp_createBzrtpContext(uint32_t selfSSRC); /** * @brief Perform some initialisation which can't be done without some callback functions: * - get ZID * * @param[in] context The context to initialise */ BZRTP_EXPORT void bzrtp_initBzrtpContext(bzrtpContext_t *context); /** * 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 * */ BZRTP_EXPORT void 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 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, 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 */ BZRTP_EXPORT int bzrtp_addChannel(bzrtpContext_t *zrtpContext, uint32_t selfSSRC); /** * @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 */ 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 Return the status of current channel, 1 if SRTP secrets have been computed and confirmed, 0 otherwise * * @param[in] zrtpContext The ZRTP context hosting the channel * @param[in] selfSSRC The SSRC identifying the channel * * @return 0 if this channel is not ready to secure SRTP communication, 1 if it is ready */ BZRTP_EXPORT int bzrtp_isSecure(bzrtpContext_t *zrtpContext, uint32_t selfSSRC); /** * @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); #define BZRTP_CUSTOMCACHE_USEKDF 1 #define BZRTP_CUSTOMCACHE_PLAINDATA 0 #define BZRTP_CACHE_LOADFILE 0x01 #define BZRTP_CACHE_DONTLOADFILE 0x00 #define BZRTP_CACHE_WRITEFILE 0x10 #define BZRTP_CACHE_DONTWRITEFILE 0x00 /* role mapping */ #define INITIATOR 0 #define RESPONDER 1 /** * @brief Allow client to write data in cache in the current tag. * Data can be written directly or ciphered using the ZRTP Key Derivation Function and current s0. * If useKDF flag is set but no s0 is available, nothing is written in cache and an error is returned * * @param[in/out] zrtpContext The ZRTP context we're dealing with * @param[in] peerZID The ZID identifying the peer node we want to write into * @param[in] tagName The name of the tag to be written * @param[in] tagNameLength The length in bytes of the tagName * @param[in] tagContent The content of the tag to be written(a string, if KDF is used the result will be turned into an hexa string) * @param[in] tagContentLength The length in bytes of tagContent * @param[in] derivedDataLength Used only in KDF mode, length in bytes of the derived data to use (max 32) * @param[in] useKDF A flag, if set to 0, write data as it is provided, if set to 1, write KDF(s0, "tagContent", KDF_Context, negotiated hash length) * @param[in] fileFlag Flag, if LOADFILE bit is set, reload the cache buffer from file before updating. * if WRITEFILE bit is set, update the cache file * * @return 0 on success, errorcode otherwise */ BZRTP_EXPORT int bzrtp_addCustomDataInCache(bzrtpContext_t *zrtpContext, uint8_t peerZID[12], uint8_t *tagName, uint16_t tagNameLength, uint8_t *tagContent, uint16_t tagContentLength, uint8_t derivedDataLength, uint8_t useKDF, uint8_t fileFlag); #endif /* ifndef BZRTP_H */ bzrtp-1.0.2/include/cryptoUtils.h000066400000000000000000000173311252270430700170170ustar00rootroot00000000000000/** @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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef CRYPTOUTILS_H #define CRYPTOUTILS_H #include "typedef.h" #include "packetParser.h" /** * * @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 */ 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 * */ 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 * */ int crypoAlgoAgreement(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 */ int 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 */ void 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 */ uint8_t 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 */ void 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 */ void bzrtp_DestroyKey(uint8_t *key, uint8_t keyLength, void *rngContext); #endif /* CRYPTOUTILS_H */ bzrtp-1.0.2/include/cryptoWrapper.h000066400000000000000000000237231252270430700173410ustar00rootroot00000000000000/** @file cryptoWrapper.h @brief This file contains all functions prototypes to the needed cryptographic operations: - SHA256 - HMAC-SHA256 - AES128-CFB128 - Diffie-Hellman-Merkle 2048 and 3072 bits - Random number generator This functions are implemented by an external lib(polarssl but it can be other) and the functions wrapper depends on the external lib API. @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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef CRYPTOWRAPPER_H #define CRYPTOWRAPPER_H #include #include "bzrtp/bzrtp.h" /** * @brief Get the available crypto functions * - Hash function * - Cipher Block * - Auth Tag (this depends on SRTP implementation, thus returns only mandatory types: "HS32" and "HS80" HMAC-SHA1) * - 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[out] availableTypes mapped to uint8_t value of the 4 char strings giving the available types as string according to rfc section 5.1.2 to 5.1.6 * * @return number of available types, 0 on error */ uint8_t bzrtpCrypto_getAvailableCryptoTypes(uint8_t algoType, uint8_t availableTypes[7]); /** * @brief Get the mandatory crypto functions * - 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[out] mandatoryTypes mapped to uint8_t value of the 4 char strings giving the available types as string according to rfc section 5.1.2 to 5.1.6 * * @return number of mandatory types, 0 on error */ uint8_t bzrtpCrypto_getMandatoryCryptoTypes(uint8_t algoType, uint8_t mandatoryTypes[7]); /** * * @brief The context structure to the Random Number Generator * actually just holds a pointer to the crypto module implementation context * */ typedef struct bzrtpRNGContext_struct { void *cryptoModuleData; /**< a context needed by the actual implementation */ } bzrtpRNGContext_t; /** * * @brief Initialise the random number generator * * @param[in] entropyString Any string providing more entropy to the RNG * @param[in] entropyStringLength Length of previous parameter * @return The context initialised. NULL on error * */ bzrtpRNGContext_t *bzrtpCrypto_startRNG(const uint8_t *entropyString, uint16_t entropyStringLength); /** * * @brief Generate a random number * @param[in] context The RNG context * @param[out] output The random generated * @param[in] outputLength The length(in bytes) of random number to be generated * @return 0 on success. * */ int bzrtpCrypto_getRandom(bzrtpRNGContext_t *context, uint8_t *output, size_t outputLength); /** * * @brief Destroy the RNG context * * @param[in] context The context to be destroyed * @return 0 on success. * */ int bzrtpCrypto_destroyRNG(bzrtpRNGContext_t *context); /** * @brief HMAC-SHA256 wrapper * @param[in] key HMAC secret key * @param[in] keyLength HMAC key length in bytes * @param[in] input Input data buffer * @param[in] inputLength Input data length in bytes * @param[in] hmacLength Length of output required in bytes, HMAC output is truncated to the hmacLength left bytes. 32 bytes maximum * @param[out] output Output data buffer. * */ void bzrtpCrypto_hmacSha256(const uint8_t *key, size_t keyLength, const uint8_t *input, size_t inputLength, uint8_t hmacLength, uint8_t *output); /** * @brief SHA256 wrapper * @param[in] input Input data buffer * @param[in] inputLength Input data length in bytes * @param[in] hmacLength Length of output required in bytes, SHA256 output is truncated to the hashLength left bytes. 32 bytes maximum * @param[out] output Output data buffer. * */ void bzrtpCrypto_sha256(const uint8_t *input, size_t inputLength, uint8_t hashLength, uint8_t *output); /** * @brief HMAC-SHA1 wrapper * @param[in] key HMAC secret key * @param[in] keyLength HMAC key length * @param[in] input Input data buffer * @param[in] inputLength Input data length * @param[in] hmacLength Length of output required in bytes, HMAC output is truncated to the hmacLength left bytes. 32 bytes maximum * @param[out] output Output data buffer * */ void bzrtpCrypto_hmacSha1(const uint8_t *key, size_t keyLength, const uint8_t *input, size_t inputLength, uint8_t hmacLength, uint8_t *output); /** * @brief Wrapper for AES-128 in CFB128 mode encryption * Both key and IV must be 16 bytes long * * @param[in] key encryption key, 128 bits long * @param[in] IV Initialisation vector, 128 bits long, is not modified by this function. * @param[in] input Input data buffer * @param[in] inputLength Input data length * @param[out] output Output data buffer * */ void bzrtpCrypto_aes128CfbEncrypt(const uint8_t *key, const uint8_t *IV, const uint8_t *input, size_t inputLength, uint8_t *output); /** * @brief Wrapper for AES-128 in CFB128 mode decryption * Both key and IV must be 16 bytes long * * @param[in] key decryption key, 128 bits long * @param[in] IV Initialisation vector, 128 bits long, is not modified by this function. * @param[in] input Input data buffer * @param[in] inputLength Input data length * @param[out] output Output data buffer * */ void bzrtpCrypto_aes128CfbDecrypt(const uint8_t *key, const uint8_t *IV, const uint8_t *input, size_t inputLength, uint8_t *output); /** * @brief Wrapper for AES-256 in CFB128 mode encryption * The key must be 32 bytes long and the IV must be 16 bytes long * * @param[in] key encryption key, 256 bits long * @param[in] IV Initialisation vector, 128 bits long, is not modified by this function. * @param[in] input Input data buffer * @param[in] inputLength Input data length * @param[out] output Output data buffer * */ void bzrtpCrypto_aes256CfbEncrypt(const uint8_t *key, const uint8_t *IV, const uint8_t *input, size_t inputLength, uint8_t *output); /** * @brief Wrapper for AES-256 in CFB128 mode decryption * The key must be 32 bytes long and the IV must be 16 bytes long * * @param[in] key decryption key, 256 bits long * @param[in] IV Initialisation vector, 128 bits long, is not modified by this function. * @param[in] input Input data buffer * @param[in] inputLength Input data length * @param[out] output Output data buffer * */ void bzrtpCrypto_aes256CfbDecrypt(const uint8_t *key, const uint8_t *IV, const uint8_t *input, size_t inputLength, uint8_t *output); /** * @brief Context for the Diffie-Hellman-Merkle key exchange * ZRTP specifies the use of RFC3526 values for G and P so we do not need to store them in this context */ typedef struct bzrtpDHMContext_struct { uint8_t algo; /**< Algorithm used for the key exchange mapped to an int */ uint16_t primeLength; /**< Prime number length in bytes(256 or 384)*/ uint8_t *secret; /**< the random secret (X), this field may not be used if the crypto module implementation already store this value in his context */ uint8_t secretLength; /**< in bytes. Shall be twice the AES key length used (rfc 5.1.5) */ uint8_t *key; /**< the key exchanged (G^Y)^X mod P */ uint8_t *self; /**< this side of the public exchange G^X mod P */ uint8_t *peer; /**< the other side of the public exchange G^Y mod P */ void *cryptoModuleData; /**< a context needed by the crypto implementation */ }bzrtpDHMContext_t; /** * * @brief Create a context for the DHM key exchange * This function will also instantiate the context needed by the actual implementation of the crypto module * * @param[in] DHMAlgo The algorithm type(ZRTP_KEYAGREEMENT_DH2k or ZRTP_KEYAGREEMENT_DH3k) * @param[in] secretLength The length in byte of the random secret(X). Shall be twice the AES key length used(rfc 5.1.5) * * @return The initialised context for the DHM calculation(must then be freed calling the destroyDHMContext function), NULL on error * */ bzrtpDHMContext_t *bzrtpCrypto_CreateDHMContext(uint8_t DHMAlgo, uint8_t secretLength); /** * * @brief Generate the private secret X and compute the public value G^X mod P * G, P and X length have been set by previous call to DHM_CreateDHMContext * * @param[in/out] context DHM context, will store the public value in ->self after this call * @param[in] rngFunction pointer to a random number generator used to create the secret X * @param[in] rngContext pointer to the rng context if neeeded * */ void bzrtpCrypto_DHMCreatePublic(bzrtpDHMContext_t *context, int (*rngFunction)(void *, uint8_t *, size_t), void *rngContext); /** * * @brief Compute the secret key G^X^Y mod p * G^X mod P has been computed in previous call to DHMCreatePublic * G^Y mod P must have been set in context->peer * * @param[in/out] context Read the public values from context, export the key to context->key * @param[in] rngFunction Pointer to a random number generation function, used for blinding countermeasure, may be NULL * @param[in] rngContext Pointer to the RNG function context * */ void bzrtpCrypto_DHMComputeSecret(bzrtpDHMContext_t *context, int (*rngFunction)(void *, uint8_t *, size_t), void *rngContext); /** * * @brief Clean DHM context * * @param context The context to deallocate * */ void bzrtpCrypto_DestroyDHMContext(bzrtpDHMContext_t *context); #endif /* ifndef CRYPTOWRAPPER_H */ bzrtp-1.0.2/include/packetParser.h000066400000000000000000000477311252270430700171110ustar00rootroot00000000000000/** @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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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_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[16]; /**< a string identifing the vendor and release of ZRTP software */ 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 */ 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 */ 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 */ 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 * */ 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 * */ 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 */ int bzrtp_packetUpdateSequenceNumber(bzrtpPacket_t *zrtpPacket, uint16_t sequenceNumber); #endif /* PACKETPARSER_H */ bzrtp-1.0.2/include/stateMachine.h000066400000000000000000000164441252270430700170670ustar00rootroot00000000000000/** @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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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.2/include/typedef.h000066400000000000000000000305761252270430700161240ustar00rootroot00000000000000/** @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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 /* some include needed for the cache */ #ifdef HAVE_LIBXML2 #include #include #endif typedef struct bzrtpChannelContext_struct bzrtpChannelContext_t; #include "cryptoWrapper.h" #include "packetParser.h" #include "stateMachine.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 /* 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 */ /* 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 */ /* 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 */ bzrtpRNGContext_t *RNGContext; /**< context for random number generation */ bzrtpDHMContext_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 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) */ 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 HAVE_LIBXML2 xmlDocPtr cacheBuffer; /**< cache file is load in this buffer to be parsed/written */ #endif uint8_t selfZID[12]; /**< The ZRTP Identifier of this ZRTP end point - a random if running cache less */ uint8_t peerZID[12]; /**< The ZRTP Identifier of the peer ZRTP end point - given by the Hello packet */ 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) */ /* 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 */ }; #endif /* ifndef TYPEDEF_H */ bzrtp-1.0.2/include/zidCache.h000066400000000000000000000077211252270430700161720ustar00rootroot00000000000000/** @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) 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef ZIDCACHE_H #define ZIDCACHE_H #include "typedef.h" #define ZRTP_ZIDCACHE_INVALID_CONTEXT 0x2001 #define ZRTP_ZIDCACHE_INVALID_CACHE 0x2002 #define ZRTP_ZIDCACHE_UNABLETOUPDATE 0x2003 /** * @brief : retrieve ZID from cache * ZID is randomly generated if cache is empty or inexistant * ZID is randamly generated in case of cacheless implementation * * @param[in] context The current zrpt context, used to access the random function if needed * and the ZID cache access function * @param[out] selfZID The ZID, retrieved from cache or randomly generated * * @return 0 on success */ int bzrtp_getSelfZID(bzrtpContext_t *context, uint8_t selfZID[12]); /** * @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 and cache access functions and store result * @param[in] peerZID a byte array of the peer ZID * * return 0 on succes, error code otherwise */ int bzrtp_getPeerAssociatedSecretsHash(bzrtpContext_t *context, uint8_t peerZID[12]); /* Define for write peer flags */ /* define positions for bit into the flags */ #define BZRTP_CACHE_ISSTRINGBIT 0x01 #define BZRTP_CACHE_MULTIPLETAGSBIT 0x10 #define BZRTP_CACHE_LOADFILEBIT 0x01 #define BZRTP_CACHE_WRITEFILEBIT 0x10 #define BZRTP_CACHE_TAGISSTRING 0x01 #define BZRTP_CACHE_TAGISBYTE 0x00 #define BZRTP_CACHE_ALLOWMULTIPLETAGS 0x10 #define BZRTP_CACHE_NOMULTIPLETAGS 0x00 /** * @brief Write the given taf into peer Node, if the tag exists, content is replaced * Cache file is locked(TODO), read and updated during this call * * @param[in/out] context the current context, used to get the negotiated Hash algorithm and cache access functions and store result * @param[in] peerZID a byte array of the peer ZID * @param[in] tagName the tagname of node to be written, it MUST be null terminated * @param[in] tagNameLength the length of tagname (not including the null termination char) * @param[in] tagContent the content of the node(a byte buffer which will be converted to hexa string) * @param[in] tagContentLength the length of the content to be written(not including the null termination if it is a string) * @param[in] nodeFlag Flag, if the ISSTRING bit is set write directly the value into the tag, otherwise convert the byte buffer to hexa string * if the MULTIPLETAGS bit is set, allow multiple tags with the same name inside the peer node(only if their value differs) * @param[in] fileFlag Flag, if LOADFILE bit is set, reload the cache buffer from file before updatin. * if WRITEFILE bit is set, update the cache file * * return 0 on success, error code otherwise */ int bzrtp_writePeerNode(bzrtpContext_t *context, uint8_t peerZID[12], uint8_t *tagName, uint8_t tagNameLength, uint8_t *tagContent, uint32_t tagContentLength, uint8_t nodeFlag, uint8_t fileFlag); #endif /* ZIDCACHE_H */ bzrtp-1.0.2/libbzrtp.pc.in000066400000000000000000000004371252270430700154420ustar00rootroot00000000000000# 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.2/src/000077500000000000000000000000001252270430700134445ustar00rootroot00000000000000bzrtp-1.0.2/src/CMakeLists.txt000066400000000000000000000035101252270430700162030ustar00rootroot00000000000000############################################################################ # 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################ set(SOURCE_FILES bzrtp.c cryptoPolarssl.c cryptoUtils.c packetParser.c pgpwords.c stateMachine.c zidCache.c ) if(ENABLE_STATIC) add_library(bzrtp STATIC ${SOURCE_FILES}) target_link_libraries(bzrtp ${LIBS}) else() add_library(bzrtp SHARED ${SOURCE_FILES}) set_target_properties(bzrtp PROPERTIES VERSION 0) target_link_libraries(bzrtp ${LIBS}) if(MSVC) if(CMAKE_BUILD_TYPE STREQUAL "Debug") install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/bzrtp.pdb DESTINATION bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) endif() endif() endif() install(TARGETS bzrtp EXPORT BZRTPTargets RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) bzrtp-1.0.2/src/Makefile.am000066400000000000000000000005241252270430700155010ustar00rootroot00000000000000lib_LTLIBRARIES = libbzrtp.la libbzrtp_la_LIBADD= $(POLARSSL_LIBS) $(LIBXML2_LIBS) libbzrtp_la_SOURCES= bzrtp.c cryptoPolarssl.c cryptoUtils.c packetParser.c zidCache.c stateMachine.c pgpwords.c libbzrtp_la_LDFLAGS=-fvisibility=hidden -no-undefined AM_CPPFLAGS= -I$(top_srcdir)/include AM_CFLAGS= $(POLARSSL_CFLAGS) $(LIBXML2_CFLAGS) bzrtp-1.0.2/src/bzrtp.c000066400000000000000000001006651252270430700147610ustar00rootroot00000000000000/** @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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "bzrtp/bzrtp.h" #include "typedef.h" #include "cryptoWrapper.h" #include "cryptoUtils.h" #include "zidCache.h" #include "packetParser.h" #include "stateMachine.h" #define BZRTP_ERROR_INVALIDCHANNELCONTEXT 0x8001 /* local functions */ int bzrtp_initChannelContext(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext, uint32_t selfSSRC); void bzrtp_destroyChannelContext(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext); bzrtpChannelContext_t *getChannelContext(bzrtpContext_t *zrtpContext, uint32_t selfSSRC); /* * Create context structure and initialise it * A channel context is created to, the selfSSRC is given to it * * @return The ZRTP engine context data * */ bzrtpContext_t *bzrtp_createBzrtpContext(uint32_t selfSSRC) { 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 = bzrtpCrypto_startRNG(NULL, 0); /* 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 */ /* set to NULL all callbacks pointer */ context->zrtpCallbacks.bzrtp_loadCache = NULL; context->zrtpCallbacks.bzrtp_writeCache = NULL; context->zrtpCallbacks.bzrtp_sendData = NULL; context->zrtpCallbacks.bzrtp_srtpSecretsAvailable = NULL; context->zrtpCallbacks.bzrtp_startSrtpSession = NULL; context->zrtpCallbacks.bzrtp_contextReadyForExportedKeys = NULL; /* 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)); bzrtp_initChannelContext(context, context->channelContext[0], selfSSRC); 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 = bzrtpCrypto_getAvailableCryptoTypes(ZRTP_HASH_TYPE, context->supportedHash); context->cc = bzrtpCrypto_getAvailableCryptoTypes(ZRTP_CIPHERBLOCK_TYPE, context->supportedCipher); context->ac = bzrtpCrypto_getAvailableCryptoTypes(ZRTP_AUTHTAG_TYPE, context->supportedAuthTag); context->kc = bzrtpCrypto_getAvailableCryptoTypes(ZRTP_KEYAGREEMENT_TYPE, context->supportedKeyAgreement); context->sc = bzrtpCrypto_getAvailableCryptoTypes(ZRTP_SAS_TYPE, context->supportedSas); /* initialise cached secret buffer to null */ #ifdef HAVE_LIBXML2 context->cacheBuffer = NULL; /* this field is present only if cache is compiled*/ #endif 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; /* initialise key buffers */ context->ZRTPSess = NULL; context->ZRTPSessLength = 0; return context; } /** * @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 callback function have been set * - load cache * - get ZID from cache or generate it * * @param[in] context The context to initialise */ void bzrtp_initBzrtpContext(bzrtpContext_t *context) { /* initialise ZID. Randomly generated if no ZID is found in cache or no cache found */ /* This call will load the cache or create it if the cache callback functions are not null*/ bzrtp_getSelfZID(context, context->selfZID); } /* * 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 * */ void bzrtp_destroyBzrtpContext(bzrtpContext_t *context, uint32_t selfSSRC) { int i; int validChannelsNumber = 0; if (context == NULL) { return; } /* 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; /* we have more valid channels, keep the zrtp context */ } /* We have no more channel, destroy the zrtp context */ if (context->DHMContext != NULL) { bzrtpCrypto_DestroyDHMContext(context->DHMContext); context->DHMContext = NULL; } /* free allocated buffers */ free(context->cachedSecret.rs1); free(context->cachedSecret.rs2); free(context->cachedSecret.pbxsecret); free(context->cachedSecret.auxsecret); free(context->ZRTPSess); context->cachedSecret.rs1=NULL; context->cachedSecret.rs2=NULL; context->cachedSecret.pbxsecret=NULL; context->cachedSecret.auxsecret=NULL; context->ZRTPSess=NULL; #ifdef HAVE_LIBXML2 xmlFreeDoc(context->cacheBuffer); context->cacheBuffer=NULL; #endif /* destroy the RNG context at the end because it may be needed to destroy some keys */ bzrtpCrypto_destroyRNG(context->RNGContext); context->RNGContext = NULL; free(context); return; } int bzrtp_setCallbacks(bzrtpContext_t *context, const bzrtpCallbacks_t *cbs) { context->zrtpCallbacks=*cbs; return 0; } 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; } /* 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; } /* 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); 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_UNABLETOSTARTCHANNEL; } /* 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; zrtpChannelContext->stateMachine(initEvent); return 0; } /* * @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; retval = zrtpChannelContext->stateMachine(event); return retval; } /* * @brief Return the status of current channel, 1 if SRTP secrets have been computed and confirmed, 0 otherwise * * @param[in] zrtpContext The ZRTP context hosting the channel * @param[in] selfSSRC The SSRC identifying the channel * * @return 0 if this channel is not ready to secure SRTP communication, 1 if it is ready */ int bzrtp_isSecure(bzrtpContext_t *zrtpContext, uint32_t selfSSRC) { /* get channel context */ bzrtpChannelContext_t *zrtpChannelContext = getChannelContext(zrtpContext, selfSSRC); if (zrtpChannelContext == NULL) { return 0; /* can't find the channel, return it as non secure */ } return zrtpChannelContext->isSecure; } /* * @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; /* 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_writePeerNode(zrtpContext, zrtpContext->peerZID, (uint8_t *)"pvs", 3, &pvsFlag, 1, BZRTP_CACHE_TAGISBYTE|BZRTP_CACHE_NOMULTIPLETAGS, BZRTP_CACHE_LOADFILE|BZRTP_CACHE_WRITEFILE); } } /* * @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; bzrtp_writePeerNode(zrtpContext, zrtpContext->peerZID, (uint8_t *)"pvs", 3, &pvsFlag, 1, BZRTP_CACHE_TAGISBYTE|BZRTP_CACHE_NOMULTIPLETAGS, BZRTP_CACHE_LOADFILE|BZRTP_CACHE_WRITEFILE); } } /* * @brief Allow client to write data in cache in the current tag. * Data can be written directly or ciphered using the ZRTP Key Derivation Function and current s0. * If useKDF flag is set but no s0 is available, nothing is written in cache and an error is returned * * @param[in/out] zrtpContext The ZRTP context we're dealing with * @param[in] peerZID The ZID identifying the peer node we want to write into * @param[in] tagName The name of the tag to be written * @param[in] tagNameLength The length in bytes of the tagName * @param[in] tagContent The content of the tag to be written(a string, if KDF is used the result will be turned into an hexa string) * @param[in] tagContentLength The length in bytes of tagContent * @param[in] derivedDataLength Used only in KDF mode, length in bytes of the derived data to use (max 32) * @param[in] useKDF A flag, if set to 0, write data as it is provided, if set to 1, write KDF(s0, "tagContent", KDF_Context, negotiated hash length) * @param[in] fileFlag Flag, if LOADFILE bit is set, reload the cache buffer from file before updating. * if WRITEFILE bit is set, update the cache file * * @return 0 on success, errorcode otherwise */ int bzrtp_addCustomDataInCache(bzrtpContext_t *zrtpContext, uint8_t peerZID[12], uint8_t *tagName, uint16_t tagNameLength, uint8_t *tagContent, uint16_t tagContentLength, uint8_t derivedDataLength, uint8_t useKDF, uint8_t fileFlag) { /* check we have a valid context, a cache access callback function and a valid channelContext[0] */ if (zrtpContext == NULL || zrtpContext->zrtpCallbacks.bzrtp_loadCache == NULL || zrtpContext->channelContext[0]==NULL) { return BZRTP_ERROR_INVALIDCONTEXT; } if (useKDF == BZRTP_CUSTOMCACHE_PLAINDATA) { /* write content as provided : content is a string and multiple tag is allowed as we are writing the peer URI(To be modified if needed) */ return bzrtp_writePeerNode(zrtpContext, peerZID, tagName, tagNameLength, tagContent, tagContentLength, BZRTP_CACHE_TAGISSTRING|BZRTP_CACHE_ALLOWMULTIPLETAGS, fileFlag); } else { /* we must derive the content using the key derivation function */ uint8_t derivedContent[32]; /* check we have s0 and KDFContext in channel[0] */ bzrtpChannelContext_t *zrtpChannelContext = zrtpContext->channelContext[0]; if (zrtpChannelContext->s0 == NULL || zrtpChannelContext->KDFContext == NULL) { return BZRTP_ERROR_INVALIDCONTEXT; } /* We derive a maximum of 32 bytes for a 256 bit key */ if (derivedDataLength>32) { derivedDataLength = 32; } bzrtp_keyDerivationFunction(zrtpChannelContext->s0, zrtpChannelContext->hashLength, tagContent, tagContentLength, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, derivedDataLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, derivedContent); /* if derivedDataLength is 4 it means we are writing the session Index, mask the first bit of first byte(MSB) to 0 in order to avoid any counter loop */ if (derivedDataLength == 4) { derivedContent[0] &=0x7F; } /* write it to cache, do not allow multiple tags */ return bzrtp_writePeerNode(zrtpContext, peerZID, tagName, tagNameLength, derivedContent, derivedDataLength, BZRTP_CACHE_TAGISBYTE|BZRTP_CACHE_NOMULTIPLETAGS, fileFlag); } } /* * @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 ((zrtpContext->isSecure == 0) && (zrtpChannelContext->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; } /* 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 */ 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 * 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 * * @return 0 on success, error code otherwise */ int bzrtp_initChannelContext(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext, uint32_t selfSSRC) { int i; 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; /* initialise as initiator, switch to responder later if needed */ zrtpChannelContext->role = INITIATOR; /* create H0 (32 bytes random) and derive using implicit Hash(SHA256) H1,H2,H3 */ bzrtpCrypto_getRandom(zrtpContext->RNGContext, zrtpChannelContext->selfH[0], 32); bzrtpCrypto_sha256(zrtpChannelContext->selfH[0], 32, 32, zrtpChannelContext->selfH[1]); bzrtpCrypto_sha256(zrtpChannelContext->selfH[1], 32, 32, zrtpChannelContext->selfH[2]); bzrtpCrypto_sha256(zrtpChannelContext->selfH[2], 32, 32, zrtpChannelContext->selfH[3]); /* initialisation of packet storage */ for (i=0; iselfPackets[i] = NULL; zrtpChannelContext->peerPackets[i] = NULL; } /* initialise the self Sequence number to a random and peer to 0 */ bzrtpCrypto_getRandom(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; 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; 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 */ 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; } /* 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; isupportedHash, 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 = bzrtpCrypto_getAvailableCryptoTypes(algoType, implementedTypes); switch(algoType) { case ZRTP_HASH_TYPE: zrtpContext->hc = selectCommonAlgo(supportedTypes, supportedTypesCount, implementedTypes, implementedTypesCount, zrtpContext->supportedHash); addMandatoryCryptoTypesIfNeeded(algoType, zrtpContext->supportedHash, &zrtpContext->hc); break; case ZRTP_CIPHERBLOCK_TYPE: zrtpContext->cc = selectCommonAlgo(supportedTypes, supportedTypesCount, implementedTypes, implementedTypesCount, zrtpContext->supportedCipher); addMandatoryCryptoTypesIfNeeded(algoType, zrtpContext->supportedCipher, &zrtpContext->cc); break; case ZRTP_AUTHTAG_TYPE: zrtpContext->ac = selectCommonAlgo(supportedTypes, supportedTypesCount, implementedTypes, implementedTypesCount, zrtpContext->supportedAuthTag); addMandatoryCryptoTypesIfNeeded(algoType, zrtpContext->supportedAuthTag, &zrtpContext->ac); break; case ZRTP_KEYAGREEMENT_TYPE: zrtpContext->kc = selectCommonAlgo(supportedTypes, supportedTypesCount, implementedTypes, implementedTypesCount, zrtpContext->supportedKeyAgreement); addMandatoryCryptoTypesIfNeeded(algoType, zrtpContext->supportedKeyAgreement, &zrtpContext->kc); break; case ZRTP_SAS_TYPE: zrtpContext->sc = selectCommonAlgo(supportedTypes, supportedTypesCount, implementedTypes, implementedTypesCount, zrtpContext->supportedSas); addMandatoryCryptoTypesIfNeeded(algoType, zrtpContext->supportedSas, &zrtpContext->sc); break; } } bzrtp-1.0.2/src/cryptoPolarssl.c000066400000000000000000000426321252270430700166570ustar00rootroot00000000000000/** @file cryptoPolarssl.c @brief bind zrtpCrypto functions to their polarSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include /* Random number generator */ #include "polarssl/entropy.h" #include "polarssl/ctr_drbg.h" /* Hash function sha1(sha2 is different for polarssl v1.2 and v1.3 ) */ #include "polarssl/sha1.h" /* Asymmetrics encryption */ #include "polarssl/dhm.h" /* Symmetric encryption */ #include "polarssl/aes.h" #include "cryptoWrapper.h" /*** Common functions to polarSSL version 1.2 and 1.3 ***/ /** 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) */ uint8_t bzrtpCrypto_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 bzrtpCrypto_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; } } /** * * @brief Structure to store all the contexts data needed for Random Number Generation * */ typedef struct polarsslRNGContext_struct { entropy_context entropyContext; /**< the entropy function context */ ctr_drbg_context rngContext; /**< the random number generator context */ } polarsslRNGContext_t; bzrtpRNGContext_t *bzrtpCrypto_startRNG(const uint8_t *entropyString, uint16_t entropyStringLength) { bzrtpRNGContext_t *context; /* create the polarssl context, it contains entropy and rng contexts */ polarsslRNGContext_t *polarsslContext = (polarsslRNGContext_t *)malloc(sizeof(polarsslRNGContext_t)); entropy_init(&(polarsslContext->entropyContext)); /* init the polarssl entropy engine */ /* init the polarssl rng context */ if (ctr_drbg_init(&(polarsslContext->rngContext), entropy_func, &(polarsslContext->entropyContext), (const unsigned char *)entropyString, entropyStringLength) != 0) { return NULL; } /* create the context and attach the polarssl one in it's unique field */ context = (bzrtpRNGContext_t *)malloc(sizeof(bzrtpRNGContext_t)); context->cryptoModuleData = (void *)polarsslContext; return context; } int bzrtpCrypto_getRandom(bzrtpRNGContext_t *context, uint8_t *output, size_t outputLength) { /* get polarssl context data */ polarsslRNGContext_t *polarsslContext = (polarsslRNGContext_t *)context->cryptoModuleData; return ctr_drbg_random((void *)&(polarsslContext->rngContext), (unsigned char *)output, outputLength); } int bzrtpCrypto_destroyRNG(bzrtpRNGContext_t *context) { /* get polarssl context data */ polarsslRNGContext_t *polarsslContext = (polarsslRNGContext_t *)context->cryptoModuleData; /* free the entropy context (ctr_drbg doesn't seem to need to be freed)*/ /*entropy_free(polarsslContext->entropyContext);*/ /* free the context structures */ free(polarsslContext); free(context); return 0; } /* * @brief HMAC-SHA1 wrapper * @param[in] key HMAC secret key * @param[in] keyLength HMAC key length * @param[in] input Input data buffer * @param[in] inputLength Input data length * @param[in] hmacLength Length of output required in bytes, HMAC output is truncated to the hmacLength left bytes. 20 bytes maximum * @param[out] output Output data buffer. * */ void bzrtpCrypto_hmacSha1(const uint8_t *key, size_t keyLength, const uint8_t *input, size_t inputLength, uint8_t hmacLength, uint8_t *output) { uint8_t hmacOutput[20]; sha1_hmac(key, keyLength, input, inputLength, hmacOutput); /* check output length, can't be>20 */ if (hmacLength>20) { memcpy(output, hmacOutput, 20); } else { memcpy(output, hmacOutput, hmacLength); } } /* initialise de DHM context according to requested algorithm */ bzrtpDHMContext_t *bzrtpCrypto_CreateDHMContext(uint8_t DHMAlgo, uint8_t secretLength) { dhm_context *polarsslDhmContext; /* create the context */ bzrtpDHMContext_t *context = (bzrtpDHMContext_t *)malloc(sizeof(bzrtpDHMContext_t)); memset (context, 0, sizeof(bzrtpDHMContext_t)); /* create the polarssl context for DHM */ polarsslDhmContext=(dhm_context *)malloc(sizeof(dhm_context)); memset(polarsslDhmContext, 0, sizeof(dhm_context)); context->cryptoModuleData=(void *)polarsslDhmContext; /* initialise pointer to NULL to ensure safe call to free() when destroying context */ context->secret = NULL; context->self = NULL; context->key = NULL; context->peer = NULL; /* set parameters in the context */ context->algo=DHMAlgo; context->secretLength = secretLength; switch (DHMAlgo) { case ZRTP_KEYAGREEMENT_DH2k: /* set P and G in the polarssl context */ if ((mpi_read_string(&(polarsslDhmContext->P), 16, POLARSSL_DHM_RFC3526_MODP_2048_P) != 0) || (mpi_read_string(&(polarsslDhmContext->G), 16, POLARSSL_DHM_RFC3526_MODP_2048_G) != 0)) { return NULL; } context->primeLength=256; polarsslDhmContext->len=256; break; case ZRTP_KEYAGREEMENT_DH3k: /* set P and G in the polarssl context */ if ((mpi_read_string(&(polarsslDhmContext->P), 16, POLARSSL_DHM_RFC3526_MODP_3072_P) != 0) || (mpi_read_string(&(polarsslDhmContext->G), 16, POLARSSL_DHM_RFC3526_MODP_3072_G) != 0)) { return NULL; } context->primeLength=384; polarsslDhmContext->len=384; break; default: free(context); return NULL; break; } return context; } /* generate the random secret and compute the public value */ void bzrtpCrypto_DHMCreatePublic(bzrtpDHMContext_t *context, int (*rngFunction)(void *, uint8_t *, size_t), void *rngContext) { /* get the polarssl context */ dhm_context *polarsslContext = (dhm_context *)context->cryptoModuleData; /* allocate output buffer */ context->self = (uint8_t *)malloc(context->primeLength*sizeof(uint8_t)); dhm_make_public(polarsslContext, context->secretLength, context->self, context->primeLength, (int (*)(void *, unsigned char *, size_t))rngFunction, rngContext); } /* clean DHM context */ void bzrtpCrypto_DestroyDHMContext(bzrtpDHMContext_t *context) { if (context!= NULL) { free(context->secret); free(context->self); free(context->key); free(context->peer); dhm_free((dhm_context *)context->cryptoModuleData); free(context->cryptoModuleData); free(context); } } /* * @brief Wrapper for AES-128 in CFB128 mode encryption * Both key and IV must be 16 bytes long, IV is not updated * * @param[in] key encryption key, 128 bits long * @param[in] IV Initialisation vector, 128 bits long, is not modified by this function. * @param[in] input Input data buffer * @param[in] inputLength Input data length * @param[out] output Output data buffer * */ void bzrtpCrypto_aes128CfbEncrypt(const uint8_t key[16], const uint8_t IV[16], const uint8_t *input, size_t inputLength, uint8_t *output) { uint8_t IVbuffer[16]; size_t iv_offset=0; /* is not used by us but needed and updated by polarssl */ aes_context context; memset (&context, 0, sizeof(aes_context)); /* make a local copy of IV which is modified by the polar ssl AES-CFB function */ memcpy(IVbuffer, IV, 16*sizeof(uint8_t)); /* initialise the aes context and key */ aes_setkey_enc(&context, key, 128); /* encrypt */ aes_crypt_cfb128 (&context, AES_ENCRYPT, inputLength, &iv_offset, IVbuffer, input, output); } /* * @brief Wrapper for AES-128 in CFB128 mode decryption * Both key and IV must be 16 bytes long, IV is not updated * * @param[in] key decryption key, 128 bits long * @param[in] IV Initialisation vector, 128 bits long, is not modified by this function. * @param[in] input Input data buffer * @param[in] inputLength Input data length * @param[out] output Output data buffer * */ void bzrtpCrypto_aes128CfbDecrypt(const uint8_t key[16], const uint8_t IV[16], const uint8_t *input, size_t inputLength, uint8_t *output) { uint8_t IVbuffer[16]; size_t iv_offset=0; /* is not used by us but needed and updated by polarssl */ aes_context context; memset (&context, 0, sizeof(aes_context)); /* make a local copy of IV which is modified by the polar ssl AES-CFB function */ memcpy(IVbuffer, IV, 16*sizeof(uint8_t)); /* initialise the aes context and key - use the aes_setkey_enc function as requested by the documentation of aes_crypt_cfb128 function */ aes_setkey_enc(&context, key, 128); /* encrypt */ aes_crypt_cfb128 (&context, AES_DECRYPT, inputLength, &iv_offset, IVbuffer, input, output); } /* * @brief Wrapper for AES-256 in CFB128 mode encryption * The key must be 32 bytes long and the IV must be 16 bytes long, IV is not updated * * @param[in] key encryption key, 256 bits long * @param[in] IV Initialisation vector, 128 bits long, is not modified by this function. * @param[in] input Input data buffer * @param[in] inputLength Input data length * @param[out] output Output data buffer * */ void bzrtpCrypto_aes256CfbEncrypt(const uint8_t key[32], const uint8_t IV[16], const uint8_t *input, size_t inputLength, uint8_t *output) { uint8_t IVbuffer[16]; size_t iv_offset=0; aes_context context; memcpy(IVbuffer, IV, 16*sizeof(uint8_t)); memset (&context, 0, sizeof(aes_context)); aes_setkey_enc(&context, key, 256); /* encrypt */ aes_crypt_cfb128 (&context, AES_ENCRYPT, inputLength, &iv_offset, IVbuffer, input, output); } /* * @brief Wrapper for AES-256 in CFB128 mode decryption * The key must be 32 bytes long and the IV must be 16 bytes long, IV is not updated * * @param[in] key decryption key, 256 bits long * @param[in] IV Initialisation vector, 128 bits long, is not modified by this function. * @param[in] input Input data buffer * @param[in] inputLength Input data length * @param[out] output Output data buffer * */ void bzrtpCrypto_aes256CfbDecrypt(const uint8_t key[32], const uint8_t IV[16], const uint8_t *input, size_t inputLength, uint8_t *output) { uint8_t IVbuffer[16]; size_t iv_offset=0; aes_context context; memcpy(IVbuffer, IV, 16*sizeof(uint8_t)); memset (&context, 0, sizeof(aes_context)); aes_setkey_enc(&context, key, 256); /* decrypt */ aes_crypt_cfb128 (&context, AES_DECRYPT, inputLength, &iv_offset, IVbuffer, input, output); } /*** End of code common to polarSSL version 1.2 and 1.3 ***/ /* check polarssl version */ #include #if POLARSSL_VERSION_NUMBER >= 0x01030000 /* for Polarssl version 1.3 */ /* Hashs */ #include "polarssl/sha256.h" /* * @brief SHA256 wrapper * @param[in] input Input data buffer * @param[in] inputLength Input data length in bytes * @param[in] hmacLength Length of output required in bytes, HMAC output is truncated to the hmacLength left bytes. 32 bytes maximum * @param[out] output Output data buffer. * */ void bzrtpCrypto_sha256(const uint8_t *input, size_t inputLength, uint8_t hashLength, uint8_t *output) { uint8_t hashOutput[32]; sha256(input, inputLength, hashOutput, 0); /* last param to zero to select SHA256 and not SHA224 */ /* check output length, can't be>32 */ if (hashLength>32) { memcpy(output, hashOutput, 32); } else { memcpy(output, hashOutput, hashLength); } } /* * HMAC-SHA-256 wrapper * @param[in] key HMAC secret key * @param[in] keyLength HMAC key length * @param[in] input Input data buffer * @param[in] inputLength Input data length * @param[in] hmacLength Length of output required in bytes, HMAC output is truncated to the hmacLength left bytes. 32 bytes maximum * @param[out] output Output data buffer. * */ void bzrtpCrypto_hmacSha256(const uint8_t *key, size_t keyLength, const uint8_t *input, size_t inputLength, uint8_t hmacLength, uint8_t *output) { uint8_t hmacOutput[32]; sha256_hmac(key, keyLength, input, inputLength, hmacOutput, 0); /* last param to zero to select SHA256 and not SHA224 */ /* check output length, can't be>32 */ if (hmacLength>32) { memcpy(output, hmacOutput, 32); } else { memcpy(output, hmacOutput, hmacLength); } } /* compute secret - the ->peer field of context must have been set before calling this function */ void bzrtpCrypto_DHMComputeSecret(bzrtpDHMContext_t *context, int (*rngFunction)(void *, uint8_t *, size_t), void *rngContext) { size_t keyLength; /* import the peer public value G^Y mod P in the polar ssl context */ dhm_read_public((dhm_context *)(context->cryptoModuleData), context->peer, context->primeLength); /* compute the secret key */ keyLength = context->primeLength; /* undocumented but this value seems to be in/out, so we must set it to the expected key length */ context->key = (uint8_t *)malloc(keyLength*sizeof(uint8_t)); /* allocate key buffer */ dhm_calc_secret((dhm_context *)(context->cryptoModuleData), context->key, &keyLength, (int (*)(void *, unsigned char *, size_t))rngFunction, rngContext); } #else /* POLAR SSL VERSION 1.2 */ /* Hashs */ #include "polarssl/sha2.h" /* * @brief SHA256 wrapper * @param[in] input Input data buffer * @param[in] inputLength Input data length in bytes * @param[in] hmacLength Length of output required in bytes, HMAC output is truncated to the hmacLength left bytes. 32 bytes maximum * @param[out] output Output data buffer. * */ void bzrtpCrypto_sha256(const uint8_t *input, size_t inputLength, uint8_t hashLength, uint8_t *output) { uint8_t hashOutput[32]; sha2(input, inputLength, hashOutput, 0); /* last param to zero to select SHA256 and not SHA224 */ /* check output length, can't be>32 */ if (hashLength>32) { memcpy(output, hashOutput, 32); } else { memcpy(output, hashOutput, hashLength); } } /* * HMAC-SHA-256 wrapper * @param[in] key HMAC secret key * @param[in] keyLength HMAC key length * @param[in] input Input data buffer * @param[in] inputLength Input data length * @param[in] hmacLength Length of output required in bytes, HMAC output is truncated to the hmacLength left bytes. 32 bytes maximum * @param[out] output Output data buffer. * */ void bzrtpCrypto_hmacSha256(const uint8_t *key, size_t keyLength, const uint8_t *input, size_t inputLength, uint8_t hmacLength, uint8_t *output) { uint8_t hmacOutput[32]; sha2_hmac(key, keyLength, input, inputLength, hmacOutput, 0); /* last param to zero to select SHA256 and not SHA224 */ /* check output length, can't be>32 */ if (hmacLength>32) { memcpy(output, hmacOutput, 32); } else { memcpy(output, hmacOutput, hmacLength); } } /* compute secret - the ->peer field of context must have been set before calling this function */ void bzrtpCrypto_DHMComputeSecret(bzrtpDHMContext_t *context, int (*rngFunction)(void *, uint8_t *, size_t), void *rngContext) { size_t keyLength; /* import the peer public value G^Y mod P in the polar ssl context */ dhm_read_public((dhm_context *)(context->cryptoModuleData), context->peer, context->primeLength); /* compute the secret key */ keyLength = context->primeLength; /* undocumented but this value seems to be in/out, so we must set it to the expected key length */ context->key = (uint8_t *)malloc(keyLength*sizeof(uint8_t)); /* allocate key buffer */ dhm_calc_secret((dhm_context *)(context->cryptoModuleData), context->key, &keyLength); } #endif /* POLARSSL Version 1.2 */ bzrtp-1.0.2/src/cryptoUtils.c000066400000000000000000000620631252270430700161600ustar00rootroot00000000000000/** @file cryptoUtils.c @brief Security related functions implementations - Key Derivation Function - CRC - Base32 @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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "cryptoUtils.h" #include "cryptoWrapper.h" 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 crypoAlgoAgreement(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 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 updateCryptoFunctionPointers(bzrtpChannelContext_t *zrtpChannelContext) { if (zrtpChannelContext==NULL) { return ZRTP_CRYPTOAGREEMENT_INVALIDCONTEXT; } /* Hash algo */ switch (zrtpChannelContext->hashAlgo) { case ZRTP_HASH_S256 : zrtpChannelContext->hashFunction = bzrtpCrypto_sha256; zrtpChannelContext->hmacFunction = bzrtpCrypto_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 = bzrtpCrypto_aes128CfbEncrypt; zrtpChannelContext->cipherDecryptionFunction = bzrtpCrypto_aes128CfbDecrypt; zrtpChannelContext->cipherKeyLength = 16; break; case ZRTP_CIPHER_AES3 : zrtpChannelContext->cipherEncryptionFunction = bzrtpCrypto_aes256CfbEncrypt; zrtpChannelContext->cipherDecryptionFunction = bzrtpCrypto_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 #include #include "typedef.h" #include "packetParser.h" #include "cryptoWrapper.h" #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; } #define MIN(a, b) (((a) < (b)) ? (a) : (b)) /* 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 : { /* allocate a Hello message structure */ bzrtpHelloMessage_t *messageData; messageData = (bzrtpHelloMessage_t *)malloc(sizeof(bzrtpHelloMessage_t)); /* fill it */ memcpy(messageData->version, messageContent, 4); messageContent +=4; memcpy(messageData->clientIdentifier, messageContent, 16); 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] = cryptoAlgoTypeStringToInt(messageContent, ZRTP_HASH_TYPE); messageContent +=4; } for (i=0; icc; i++) { messageData->supportedCipher[i] = cryptoAlgoTypeStringToInt(messageContent, ZRTP_CIPHERBLOCK_TYPE); messageContent +=4; } for (i=0; iac; i++) { messageData->supportedAuthTag[i] = cryptoAlgoTypeStringToInt(messageContent, ZRTP_AUTHTAG_TYPE); messageContent +=4; } for (i=0; ikc; i++) { messageData->supportedKeyAgreement[i] = cryptoAlgoTypeStringToInt(messageContent, ZRTP_KEYAGREEMENT_TYPE); messageContent +=4; } for (i=0; isc; i++) { messageData->supportedSas[i] = cryptoAlgoTypeStringToInt(messageContent, ZRTP_SAS_TYPE); messageContent +=4; } addMandatoryCryptoTypesIfNeeded(ZRTP_HASH_TYPE, messageData->supportedHash, &messageData->hc); addMandatoryCryptoTypesIfNeeded(ZRTP_CIPHERBLOCK_TYPE, messageData->supportedCipher, &messageData->cc); addMandatoryCryptoTypesIfNeeded(ZRTP_AUTHTAG_TYPE, messageData->supportedAuthTag, &messageData->ac); addMandatoryCryptoTypesIfNeeded(ZRTP_KEYAGREEMENT_TYPE, messageData->supportedKeyAgreement, &messageData->kc); 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) */ bzrtpCrypto_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) */ bzrtpCrypto_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 = cryptoAlgoTypeStringToInt(messageContent, ZRTP_HASH_TYPE); messageContent += 4; messageData->cipherAlgo = cryptoAlgoTypeStringToInt(messageContent, ZRTP_CIPHERBLOCK_TYPE); messageContent += 4; messageData->authTagAlgo = cryptoAlgoTypeStringToInt(messageContent, ZRTP_AUTHTAG_TYPE); messageContent += 4; messageData->keyAgreementAlgo = 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 = 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 == 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) */ bzrtpCrypto_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) */ bzrtpCrypto_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; } } 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)) */ bzrtpCrypto_sha256(messageData->H1, 32, 32, checkH2); bzrtpCrypto_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) */ bzrtpCrypto_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 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_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 == 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 == 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]; bzrtpCrypto_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 == 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) */ bzrtpCrypto_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) */ bzrtpCrypto_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)) */ bzrtpCrypto_sha256(checkH1, 32, 32, checkH2); bzrtpCrypto_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) */ bzrtpCrypto_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) */ bzrtpCrypto_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) */ bzrtpCrypto_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++) { cryptoAlgoTypeIntToString(messageData->supportedHash[i], messageString); messageString +=4; } for (i=0; icc; i++) { cryptoAlgoTypeIntToString(messageData->supportedCipher[i], messageString); messageString +=4; } for (i=0; iac; i++) { cryptoAlgoTypeIntToString(messageData->supportedAuthTag[i], messageString); messageString +=4; } for (i=0; ikc; i++) { cryptoAlgoTypeIntToString(messageData->supportedKeyAgreement[i], messageString); messageString +=4; } for (i=0; isc; i++) { 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; cryptoAlgoTypeIntToString(messageData->hashAlgo, messageString); messageString += 4; cryptoAlgoTypeIntToString(messageData->cipherAlgo, messageString); messageString += 4; cryptoAlgoTypeIntToString(messageData->authTagAlgo, messageString); messageString += 4; cryptoAlgoTypeIntToString(messageData->keyAgreementAlgo, messageString); messageString += 4; 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 == INITIATOR) { if ((zrtpChannelContext->zrtpkeyi == NULL) || (zrtpChannelContext->mackeyi == NULL)) { return BZRTP_BUILDER_ERROR_INVALIDCONTEXT; } confirmMessageKey = zrtpChannelContext->zrtpkeyi; confirmMessageMacKey = zrtpChannelContext->mackeyi; } if (zrtpChannelContext->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 */ bzrtpCrypto_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); 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)) { bzrtpCrypto_getRandom(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 */ 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; } zrtpContext->DHMContext = bzrtpCrypto_CreateDHMContext(zrtpChannelContext->keyAgreementAlgo, secretLength); if (zrtpContext->DHMContext == NULL) { free(zrtpPacket); free(zrtpDHPartMessage); *exitCode = BZRTP_CREATE_ERROR_UNABLETOCREATECRYPTOCONTEXT; return NULL; } /* now compute the public value */ bzrtpCrypto_DHMCreatePublic(zrtpContext->DHMContext, (int (*)(void *, uint8_t *, size_t))bzrtpCrypto_getRandom, 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 */ bzrtpCrypto_getRandom(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.2/src/pgpwords.c000066400000000000000000000202011252270430700154500ustar00rootroot00000000000000// 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.2/src/stateMachine.c000066400000000000000000003202731252270430700162240ustar00rootroot00000000000000/** @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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "typedef.h" #include "packetParser.h" #include "cryptoUtils.h" #include "zidCache.h" #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, 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[HELLO_MESSAGE_STORE_ID] == NULL)) { 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; } /* 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; /*bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_ERROR_CACHEMISMATCH;*/ } } } /* 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; /*bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_ERROR_CACHEMISMATCH;*/ } 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; /*bzrtp_freeZrtpPacket(zrtpPacket); return BZRTP_ERROR_CACHEMISMATCH;*/ } } 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; /*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; zrtpContext->cachedSecret.previouslyVerifiedSas = 0; bzrtp_writePeerNode(zrtpContext, zrtpContext->peerZID, (uint8_t *)"pvs", 3, &pvsFlag, 1, BZRTP_CACHE_TAGISBYTE|BZRTP_CACHE_NOMULTIPLETAGS, BZRTP_CACHE_LOADFILE|BZRTP_CACHE_WRITEFILE); } /* 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); bzrtpCrypto_DHMComputeSecret(zrtpContext->DHMContext, (int (*)(void *, uint8_t *, size_t))bzrtpCrypto_getRandom, (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 = 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 = 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 = RESPONDER; } } else { /* DHM mode, compare the hvi */ if (memcmp(selfCommitMessage->hvi, peerCommitMessage->hvi, 32) < 0) { /* self hvi < peer hvi */ zrtpChannelContext->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 == 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 responder(computed 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 isn't match responder 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; zrtpContext->cachedSecret.previouslyVerifiedSas = 0; bzrtp_writePeerNode(zrtpContext, zrtpContext->peerZID, (uint8_t *)"pvs", 3, &pvsFlag, 1, BZRTP_CACHE_TAGISBYTE|BZRTP_CACHE_NOMULTIPLETAGS, BZRTP_CACHE_LOADFILE|BZRTP_CACHE_WRITEFILE); } /* Check that the received PV is not 1 or Prime-1 TODO*/ /* 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); bzrtpCrypto_DHMComputeSecret(zrtpContext->DHMContext, (int (*)(void *, uint8_t *, size_t))bzrtpCrypto_getRandom, (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); /* 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); /* 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.sas, zrtpContext->cachedSecret.previouslyVerifiedSas); } 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 = RESPONDER; zrtpChannelContext->hashAlgo = commitMessage->hashAlgo; zrtpChannelContext->cipherAlgo = commitMessage->cipherAlgo; zrtpChannelContext->authTagAlgo = commitMessage->authTagAlgo; zrtpChannelContext->keyAgreementAlgo = commitMessage->keyAgreementAlgo; zrtpChannelContext->sasAlgo = commitMessage->sasAlgo; 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 receives, it contains the commit 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 = crypoAlgoAgreement(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 */ /* 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_getPeerAssociatedSecretsHash(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 */ bzrtpCrypto_getRandom(zrtpContext->RNGContext, zrtpContext->initiatorCachedSecretHash.rs1ID, 8); bzrtpCrypto_getRandom(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 */ bzrtpCrypto_getRandom(zrtpContext->RNGContext, zrtpContext->initiatorCachedSecretHash.rs2ID, 8); bzrtpCrypto_getRandom(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 */ bzrtpCrypto_getRandom(zrtpContext->RNGContext, zrtpContext->initiatorCachedSecretHash.pbxsecretID, 8); bzrtpCrypto_getRandom(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 */ bzrtpCrypto_getRandom(zrtpContext->RNGContext, zrtpChannelContext->initiatorAuxsecretID, 8); bzrtpCrypto_getRandom(zrtpContext->RNGContext, zrtpChannelContext->responderAuxsecretID, 8); } /* 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; } /* 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 == 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; } 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); /* now derive the other keys */ return bzrtp_deriveKeysFromS0(zrtpContext, zrtpChannelContext); /* destroy all cached keys in context */ /* TODO : Check secret cache update?? */ /*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; }*/ return 0; } /** * @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 == 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 == 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; /* 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); } 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) { /* 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) { bzrtp_writePeerNode(zrtpContext, zrtpContext->peerZID, (uint8_t *)"rs2", 3, zrtpContext->cachedSecret.rs1, zrtpContext->cachedSecret.rs1Length, BZRTP_CACHE_TAGISBYTE|BZRTP_CACHE_NOMULTIPLETAGS, BZRTP_CACHE_LOADFILE|BZRTP_CACHE_WRITEFILE); } } /* compute rs1 = KDF(s0, "retained secret", KDF_Context, 256) */ if (zrtpContext->cachedSecret.rs1 == NULL) { zrtpContext->cachedSecret.rs1 = (uint8_t *)malloc(RETAINED_SECRET_LENGTH); 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); bzrtp_writePeerNode(zrtpContext, zrtpContext->peerZID, (uint8_t *)"rs1", 3, zrtpContext->cachedSecret.rs1, zrtpContext->cachedSecret.rs1Length, BZRTP_CACHE_TAGISBYTE|BZRTP_CACHE_NOMULTIPLETAGS, BZRTP_CACHE_LOADFILE|BZRTP_CACHE_WRITEFILE); /* 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->peerZID, zrtpChannelContext->role); } /* destroy s0 */ bzrtp_DestroyKey(zrtpChannelContext->s0, zrtpChannelContext->hashLength, zrtpContext->RNGContext); free(zrtpChannelContext->s0); zrtpChannelContext->s0 = NULL; return 0; } bzrtp-1.0.2/src/zidCache.c000066400000000000000000000462371252270430700153360ustar00rootroot00000000000000/** @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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "zidCache.h" #include "typedef.h" #ifdef HAVE_LIBXML2 #include #include #define MIN_VALID_CACHE_LENGTH 56 /* root tag + selfZID tag size */ #define XML_HEADER_STRING "" #define XML_HEADER_SIZE 38 /* Local functions prototypes */ void bzrtp_strToUint8(uint8_t *outputBytes, uint8_t *inputString, uint16_t inputLength); void bzrtp_int8ToStr(uint8_t *outputString, uint8_t *inputBytes, uint16_t inputBytesLength); uint8_t bzrtp_byteToChar(uint8_t inputByte); uint8_t bzrtp_charToByte(uint8_t inputChar); void bzrtp_writeCache(bzrtpContext_t *zrtpContext); int bzrtp_getSelfZID(bzrtpContext_t *context, uint8_t selfZID[12]) { uint8_t *selfZidHex = NULL; if (context == NULL) { return ZRTP_ZIDCACHE_INVALID_CONTEXT; } /* load the cache buffer and parse it to an xml doc. TODO: lock it as we may write it */ if (context->zrtpCallbacks.bzrtp_loadCache != NULL) { uint8_t *cacheStringBuffer; uint32_t cacheStringLength; zrtpFreeBuffer_callback cb=NULL; context->zrtpCallbacks.bzrtp_loadCache(context->channelContext[0]->clientData, &cacheStringBuffer, &cacheStringLength, &cb); context->cacheBuffer = xmlParseDoc(cacheStringBuffer); if (cb!=NULL) cb(cacheStringBuffer); } else { /* we are running cacheless, return a random number */ bzrtpCrypto_getRandom(context->RNGContext, selfZID, 12); return 0; } if (context->cacheBuffer != NULL ) { /* there is a cache, try to find our ZID */ xmlNodePtr cur = xmlDocGetRootElement(context->cacheBuffer); /* if we found a root element, parse its children node */ if (cur!=NULL) { cur = cur->xmlChildrenNode; } while (cur!=NULL) { if ((!xmlStrcmp(cur->name, (const xmlChar *)"selfZID"))){ /* self ZID found, extract it */ selfZidHex = xmlNodeListGetString(context->cacheBuffer, cur->xmlChildrenNode, 1); /* convert it from hexa string to bytes string */ bzrtp_strToUint8(selfZID, selfZidHex, strlen((char *)selfZidHex)); break; } cur = cur->next; } } /* if we didn't found anything in cache, or we have no cache at all: generate ZID, cache string and write it to file */ if (selfZidHex==NULL) { uint8_t newZidHex[25]; xmlNodePtr rootNode; /* generate a random ZID */ bzrtpCrypto_getRandom(context->RNGContext, selfZID, 12); /* convert it to an Hexa String */ bzrtp_int8ToStr(newZidHex, selfZID, 12); newZidHex[24] = '\0'; /* the string must be null terminated for libxml2 to add it correctly in the element */ xmlFree(context->cacheBuffer); /* Create a new xml doc */ context->cacheBuffer = xmlNewDoc((const xmlChar *)"1.0"); /* root tag is "cache" */ rootNode = xmlNewDocNode(context->cacheBuffer, NULL, (const xmlChar *)"cache", NULL); xmlDocSetRootElement(context->cacheBuffer, rootNode); /* add the ZID child */ xmlNewTextChild(rootNode, NULL, (const xmlChar *)"selfZID", newZidHex); /* write the cache file and unlock it(TODO)*/ bzrtp_writeCache(context); } /* TODO unlock the cache */ xmlFree(selfZidHex); 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 and cache access functions and store result * @param[in] peerZID a byte array of the peer ZID * * return 0 on succes, error code otherwise */ int bzrtp_getPeerAssociatedSecretsHash(bzrtpContext_t *context, uint8_t peerZID[12]) { if (context == NULL) { return ZRTP_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; /* parse the cache to find the peer element matching the given ZID */ if (context->cacheBuffer != NULL ) { /* there is a cache, try to find our peer element */ uint8_t peerZidHex[24]; xmlNodePtr cur; bzrtp_int8ToStr(peerZidHex, peerZID, 12); /* compute the peerZID as an Hexa string */ cur = xmlDocGetRootElement(context->cacheBuffer); /* if we found a root element, parse its children node */ if (cur!=NULL) { cur = cur->xmlChildrenNode; } while (cur!=NULL) { if ((!xmlStrcmp(cur->name, (const xmlChar *)"peer"))){ /* found a peer, check his ZID element */ xmlChar *currentZidHex = xmlNodeListGetString(context->cacheBuffer, cur->xmlChildrenNode->xmlChildrenNode, 1); /* ZID is the first element of peer */ if (memcmp(currentZidHex, peerZidHex, 24) == 0) { /* we found the peer element we are looking for */ xmlNodePtr peerNode = cur->xmlChildrenNode->next; /* no need to parse the first child as it is the ZID node */ while (peerNode != NULL) { /* get all the needed information : rs1, rs2, pbx and aux if we found them */ xmlChar *nodeContent = NULL; if (!xmlStrcmp(peerNode->name, (const xmlChar *)"rs1")) { nodeContent = xmlNodeListGetString(context->cacheBuffer, peerNode->xmlChildrenNode, 1); context->cachedSecret.rs1 = (uint8_t *)malloc(RETAINED_SECRET_LENGTH); context->cachedSecret.rs1Length = RETAINED_SECRET_LENGTH; bzrtp_strToUint8(context->cachedSecret.rs1, nodeContent, 2*RETAINED_SECRET_LENGTH); /* RETAINED_SECRET_LENGTH is in byte, the nodeContent buffer is in hexa string so twice the length of byte string */ } if (!xmlStrcmp(peerNode->name, (const xmlChar *)"rs2")) { nodeContent = xmlNodeListGetString(context->cacheBuffer, peerNode->xmlChildrenNode, 1); context->cachedSecret.rs2 = (uint8_t *)malloc(RETAINED_SECRET_LENGTH); context->cachedSecret.rs2Length = RETAINED_SECRET_LENGTH; bzrtp_strToUint8(context->cachedSecret.rs2, nodeContent, 2*RETAINED_SECRET_LENGTH); /* RETAINED_SECRET_LENGTH is in byte, the nodeContent buffer is in hexa string so twice the length of byte string */ } if (!xmlStrcmp(peerNode->name, (const xmlChar *)"aux")) { nodeContent = xmlNodeListGetString(context->cacheBuffer, peerNode->xmlChildrenNode, 1); context->cachedSecret.auxsecretLength = strlen((const char *)nodeContent)/2; context->cachedSecret.auxsecret = (uint8_t *)malloc(context->cachedSecret.auxsecretLength); /* aux secret is of user defined length, node Content is an hexa string */ bzrtp_strToUint8(context->cachedSecret.auxsecret, nodeContent, 2*context->cachedSecret.auxsecretLength); } if (!xmlStrcmp(peerNode->name, (const xmlChar *)"pbx")) { nodeContent = xmlNodeListGetString(context->cacheBuffer, peerNode->xmlChildrenNode, 1); context->cachedSecret.pbxsecret = (uint8_t *)malloc(RETAINED_SECRET_LENGTH); context->cachedSecret.pbxsecretLength = RETAINED_SECRET_LENGTH; bzrtp_strToUint8(context->cachedSecret.pbxsecret, nodeContent, 2*RETAINED_SECRET_LENGTH); /* RETAINED_SECRET_LENGTH is in byte, the nodeContent buffer is in hexa string so twice the length of byte string */ } if (!xmlStrcmp(peerNode->name, (const xmlChar *)"pvs")) { /* this one is the previously verified sas flag */ nodeContent = xmlNodeListGetString(context->cacheBuffer, peerNode->xmlChildrenNode, 1); if (nodeContent[1] == *"1") { /* pvs is a boolean but is stored as a byte, on 2 hex chars */ context->cachedSecret.previouslyVerifiedSas = 1; } } xmlFree(nodeContent); peerNode = peerNode->next; } xmlFree(currentZidHex); currentZidHex=NULL; break; } xmlFree(currentZidHex); currentZidHex=NULL; } cur = cur->next; } } return 0; } /** * @brief Write the given taf into peer Node, if the tag exists, content is replaced * Cache file is locked(TODO), read and updated during this call * * @param[in/out] context the current context, used to get the negotiated Hash algorithm and cache access functions and store result * @param[in] peerZID a byte array of the peer ZID * @param[in] tagName the tagname of node to be written, it MUST be null terminated * @param[in] tagNameLength the length of tagname (not including the null termination char) * @param[in] tagContent the content of the node(a byte buffer which will be converted to hexa string) * @param[in] tagContentLength the length of the content to be written(not including the null termination) * @param[in] nodeFlag Flag, if the ISSTRING bit is set write directly the value into the tag, otherwise convert the byte buffer to hexa string * if the MULTIPLETAGS bit is set, allow multiple tags with the same name inside the peer node(only if their value differs) * @param[in] fileFlag Flag, if LOADFILE bit is set, reload the cache buffer from file before updatin. * if WRITEFILE bit is set, update the cache file * * Note : multiple tags mode manage string content only * * return 0 on success, error code otherwise */ int bzrtp_writePeerNode(bzrtpContext_t *context, uint8_t peerZID[12], uint8_t *tagName, uint8_t tagNameLength, uint8_t *tagContent, uint32_t tagContentLength, uint8_t nodeFlag, uint8_t fileFlag) { uint8_t *tagContentHex; /* this one will store the actual value to be written in cache */ if ((context == NULL) || (context->zrtpCallbacks.bzrtp_loadCache == NULL)) { return ZRTP_ZIDCACHE_INVALID_CONTEXT; } if ((nodeFlag&BZRTP_CACHE_ISSTRINGBIT) == BZRTP_CACHE_TAGISBYTE) { /* tag content is a byte buffer, convert it to hexa string */ /* turn the tagContent to an hexa string null terminated */ tagContentHex = (uint8_t *)malloc(2*tagContentLength+1); bzrtp_int8ToStr(tagContentHex, tagContent, tagContentLength); tagContentHex[2*tagContentLength] = '\0'; } else { /* tag content is a string, write it directly */ tagContentHex = (uint8_t *)malloc(tagContentLength+1); memcpy(tagContentHex, tagContent, tagContentLength+1); /* duplicate the string to have it in the same variable in both case and be able to free it at the end */ } if ((fileFlag&BZRTP_CACHE_LOADFILEBIT) == BZRTP_CACHE_LOADFILE) { /* we must reload the cache from file */ uint8_t *cacheStringBuffer; uint32_t cacheStringLength; zrtpFreeBuffer_callback cb=NULL; /* reload cache from file locking it (TODO: lock) */ xmlFreeDoc(context->cacheBuffer); context->cacheBuffer = NULL; context->zrtpCallbacks.bzrtp_loadCache(context->channelContext[0]->clientData, &cacheStringBuffer, &cacheStringLength,&cb); context->cacheBuffer = xmlParseDoc(cacheStringBuffer); if (cb) cb(cacheStringBuffer); } /* parse the cache to find the peer element matching the given ZID */ if (context->cacheBuffer != NULL ) { /* there is a cache, try to find our peer element */ uint8_t peerZidHex[25]; xmlNodePtr rootNode; xmlNodePtr cur = NULL; uint8_t nodeUpdated = 0; /* a boolean flag set if node is updated */ bzrtp_int8ToStr(peerZidHex, peerZID, 12); /* compute the peerZID as an Hexa string */ peerZidHex[24]='\0'; rootNode = xmlDocGetRootElement(context->cacheBuffer); /* if we found a root element, parse its children node */ if (rootNode!=NULL) { cur = rootNode->xmlChildrenNode->next; /* first node is selfZID, don't parse it */ } while (cur!=NULL) { if ((!xmlStrcmp(cur->name, (const xmlChar *)"peer"))){ /* found a peer, check his ZID element */ xmlChar *currentZidHex = xmlNodeListGetString(context->cacheBuffer, cur->xmlChildrenNode->xmlChildrenNode, 1); /* ZID is the first element of peer */ if (!xmlStrcmp(currentZidHex, (const xmlChar *)peerZidHex)) { /* we found the peer element we are looking for */ xmlNodePtr peerNodeChildren = cur->xmlChildrenNode->next; while (peerNodeChildren != NULL && nodeUpdated==0) { /* look for the tag we want to write */ if ((!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)tagName))){ /* check if we already have the tag we want to write */ if ((nodeFlag&BZRTP_CACHE_MULTIPLETAGSBIT) == BZRTP_CACHE_ALLOWMULTIPLETAGS) { /* multiple nodes with the same name are allowed, check the current one have a different value */ /* check if the node found have the same content than the one we want to add */ xmlChar *currentNodeContent = xmlNodeListGetString(context->cacheBuffer, peerNodeChildren->xmlChildrenNode, 1); if (!xmlStrcmp((const xmlChar *)currentNodeContent, (const xmlChar *)tagContent)) { /* contents are the same, do nothing and get out */ nodeUpdated = 1; } else { /* tagname is the same but content differs, keep on parsing this peer node */ peerNodeChildren = peerNodeChildren->next; } xmlFree(currentNodeContent); } else { /* no multiple tags with the same name allowed, overwrite the content in any case */ xmlNodeSetContent(peerNodeChildren, (const xmlChar *)tagContentHex); nodeUpdated = 1; } } else { peerNodeChildren = peerNodeChildren->next; } } if (nodeUpdated == 0) { /* if we didn't found our node, add it at the end of peer node */ xmlNewTextChild(cur, NULL, (const xmlChar *)tagName, tagContentHex); nodeUpdated = 1; } xmlFree(currentZidHex); currentZidHex=NULL; break; } xmlFree(currentZidHex); currentZidHex=NULL; } cur = cur->next; } /* we didn't find the peer element, create it with nodes ZID and tagName */ if (nodeUpdated == 0) { xmlNodePtr peerNode = xmlNewNode(NULL, (const xmlChar *)"peer"); xmlNewTextChild(peerNode, NULL, (const xmlChar *)"ZID", peerZidHex); xmlNewTextChild(peerNode, NULL, (const xmlChar *)tagName, tagContentHex); xmlAddChild(rootNode, peerNode); } /* write the cache file if requested and unlock it(TODO)*/ if ((fileFlag&BZRTP_CACHE_WRITEFILEBIT) == BZRTP_CACHE_WRITEFILE) { bzrtp_writeCache(context); } } free(tagContentHex); return 0; } /*** Local functions implementations ***/ /** * @brief write the cache from the xmlDoc to cache file * * @param[in/out] zrtpContext The zrtp context containing the cacheBuffer * */ void bzrtp_writeCache(bzrtpContext_t *zrtpContext) { /* dump the xml document into a string */ xmlChar *xmlStringOutput; int xmlStringLength; xmlDocDumpFormatMemoryEnc(zrtpContext->cacheBuffer, &xmlStringOutput, &xmlStringLength, "UTF-8", 0); /* write it to the file */ zrtpContext->zrtpCallbacks.bzrtp_writeCache(zrtpContext->channelContext[0]->clientData, xmlStringOutput, xmlStringLength); xmlFree(xmlStringOutput); } /** * @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) { int i; for (i=0; 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; } #else /* NOT HAVE_LIBXML2 */ int bzrtp_getSelfZID(bzrtpContext_t *context, uint8_t selfZID[12]) { if (context == NULL) { return ZRTP_ZIDCACHE_INVALID_CONTEXT; } /* we are running cacheless, return a random number */ bzrtpCrypto_getRandom(context->RNGContext, selfZID, 12); return 0; } int bzrtp_getPeerAssociatedSecretsHash(bzrtpContext_t *context, uint8_t peerZID[12]) { if (context == NULL) { return ZRTP_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; } /* just do nothing for the write peer node */ int bzrtp_writePeerNode(bzrtpContext_t *context, uint8_t peerZID[12], uint8_t *tagName, uint8_t tagNameLength, uint8_t *tagContent, uint32_t tagContentLength, uint8_t nodeFlag, uint8_t fileFlag) { return 0; } #endif /* HAVE LIBXML2 */ bzrtp-1.0.2/test/000077500000000000000000000000001252270430700136345ustar00rootroot00000000000000bzrtp-1.0.2/test/CMakeLists.txt000066400000000000000000000034321252270430700163760ustar00rootroot00000000000000############################################################################ # 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################ set(TEST_SOURCES bzrtpCryptoTest.c bzrtpParserTest.c bzrtpTest.c testUtils.c ${CMAKE_SOURCE_DIR}/src/bzrtp.c ${CMAKE_SOURCE_DIR}/src/cryptoPolarssl.c ${CMAKE_SOURCE_DIR}/src/cryptoUtils.c ${CMAKE_SOURCE_DIR}/src/packetParser.c ${CMAKE_SOURCE_DIR}/src/pgpwords.c ${CMAKE_SOURCE_DIR}/src/stateMachine.c ${CMAKE_SOURCE_DIR}/src/zidCache.c ) add_executable(bzrtpTest ${TEST_SOURCES}) set_target_properties(bzrtpTest PROPERTIES LINK_FLAGS "${LINK_FLAGS}") if("${CMAKE_VERSION}" VERSION_GREATER "2.8.10") target_include_directories(bzrtpTest PUBLIC ${CUNIT_INCLUDE_DIR}) else() include_directories(${CUNIT_INCLUDE_DIR}) endif() target_link_libraries(bzrtpTest ${CUNIT_LIBRARIES} bzrtp) if(HAVE_SQRT) target_link_libraries(bzrtpTest m) endif() add_test(NAME bzrtpTest COMMAND bzrtpTest) bzrtp-1.0.2/test/Makefile.am000066400000000000000000000006231252270430700156710ustar00rootroot00000000000000if ENABLE_TESTS noinst_PROGRAMS=bzrtpTest bzrtpTest_SOURCES=bzrtpTest.c \ testUtils.c testUtils.h \ bzrtpCryptoTest.c bzrtpCryptoTest.h \ bzrtpParserTest.c bzrtpParserTest.h bzrtpTest_CFLAGS=$(CUNIT_CFLAGS) $(LIBXML2_CFLAGS) bzrtpTest_LDADD=$(top_builddir)/src/libbzrtp.la $(CUNIT_LIBS) $(LIBXML2_LIBS) -lm AM_CPPFLAGS=-I$(top_srcdir)/include test: bzrtpTest ./bzrtpTest endif bzrtp-1.0.2/test/ZIDAlice.txt000066400000000000000000000006001252270430700157550ustar00rootroot00000000000000 ef7692d0792a67491ae2d44e005dbe0399643d953a2202dd4ad68d1c48c0452bdc65a0d03f9fa226f5ecd9696dbd79f6b0aa54f61adb0f61f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605ec1f9c4575e7bb95de84f8363c68d7c4ecfd41f214df10292922ce89f0f89e61301 bzrtp-1.0.2/test/ZIDBob.txt000066400000000000000000000006001252270430700154420ustar00rootroot00000000000000 005dbe0399643d953a2202ddef7692d0792a67491ae2d44e4ad68d1c48c0452bdc65a0d03f9fa226f5ecd9696dbd79f6b0aa54f61adb0f61f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605ec1f9c4575e7bb95de84f8363c68d7c4ecfd41f214df10292922ce89f0f89e61301 bzrtp-1.0.2/test/bzrtpCryptoTest.c000066400000000000000000001430701252270430700172070ustar00rootroot00000000000000/** @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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "CUnit/Basic.h" #include "bzrtp/bzrtp.h" #include "cryptoWrapper.h" #include "cryptoUtils.h" #include "testUtils.h" /** * * @brief Test the Random Number Generator with a serie of 32 bits integers * This test doesn't really test the quality of the RNG * It just compute the mean and standard deviation of the generated number * Being a discrete uniform distribution, standard deviation is supposed to be * (max-min)/sqrt(12), in our case (0xFFFFFFFF - 0)/sqrt(12). * To get an more readable perspective, mean and sqrt are divided by 0xFFFFFFFF * and result are tested agains 0.5 and 1/sqrt(12) * */ #define NB_INT32_TESTED 100000 void test_RNG(void) { uint8_t buffer[4]; uint32_t rnBuffer; long double m0=0.0,s0=0.0, m1=0.0; uint8_t start=0; int i; /* init the RNG */ bzrtpRNGContext_t *context = bzrtpCrypto_startRNG((uint8_t *)"36 15 Grouiik vous souhaite une bonne journee", 46); if (context == NULL) { CU_FAIL("Cant' start RNG engine"); return; } for (i=0; i0.49 && m0<0.51) { CU_PASS("RNG mean value ok"); } else { CU_FAIL("RNG mean value incorrect"); } /* sigma value/0xFFFFFFFF shall be around 1/sqrt(12)[0.288675]*/ s0 = sqrt(s0/i-1)/(long double)0xFFFFFFFF; if (s0>0.278 && s0<0.299) { CU_PASS("RNG sigma value ok"); } else { CU_FAIL("RNG sigma value incorrect"); } bzrtp_message ("%d 32 bits integers generated Mean %Lf Sigma/Mean %Lf\n", NB_INT32_TESTED, m0, s0); /* destroy the RNG context */ bzrtpCrypto_destroyRNG(context); } /** * * Test pattern for SHA256 * */ #define NB_SHA256_TESTS 8 static const uint8_t patternSHA256Input[NB_SHA256_TESTS][70] = { {""}, {"abc"}, {"message digest"}, {"secure hash algorithm"}, {"SHA256 is considered to be safe"}, {"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, {"For this sample, this 63-byte string will be used as input data"}, {"This is exactly 64 bytes long, not counting the terminating byte"}, }; static const uint8_t patternSHA256Output[NB_SHA256_TESTS][32] = { {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}, {0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}, {0xf7, 0x84, 0x6f, 0x55, 0xcf, 0x23, 0xe1, 0x4e, 0xeb, 0xea, 0xb5, 0xb4, 0xe1, 0x55, 0x0c, 0xad, 0x5b, 0x50, 0x9e, 0x33, 0x48, 0xfb, 0xc4, 0xef, 0xa3, 0xa1, 0x41, 0x3d, 0x39, 0x3c, 0xb6, 0x50}, {0xf3, 0x0c, 0xeb, 0x2b, 0xb2, 0x82, 0x9e, 0x79, 0xe4, 0xca, 0x97, 0x53, 0xd3, 0x5a, 0x8e, 0xcc, 0x00, 0x26, 0x2d, 0x16, 0x4c, 0xc0, 0x77, 0x08, 0x02, 0x95, 0x38, 0x1c, 0xbd, 0x64, 0x3f, 0x0d}, {0x68, 0x19, 0xd9, 0x15, 0xc7, 0x3f, 0x4d, 0x1e, 0x77, 0xe4, 0xe1, 0xb5, 0x2d, 0x1f, 0xa0, 0xf9, 0xcf, 0x9b, 0xea, 0xea, 0xd3, 0x93, 0x9f, 0x15, 0x87, 0x4b, 0xd9, 0x88, 0xe2, 0xa2, 0x36, 0x30}, {0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1}, {0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42}, {0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8} }; /** * * Tests for SHA256 * */ void test_sha256(void) { int i; uint8_t outputSha256[32]; for (i=0; ipeer = (uint8_t *)malloc(DHMaContext->primeLength*sizeof(uint8_t)); DHMbContext->peer = (uint8_t *)malloc(DHMbContext->primeLength*sizeof(uint8_t)); memcpy (DHMaContext->peer, DHMbContext->self, DHMaContext->primeLength*sizeof(uint8_t)); memcpy (DHMbContext->peer, DHMaContext->self, DHMbContext->primeLength*sizeof(uint8_t)); bzrtp_message("Call compute secret\n"); /* compute secret key */ bzrtpCrypto_DHMComputeSecret(DHMaContext, (int (*)(void *, uint8_t *, size_t))bzrtpCrypto_getRandom, (void *)RNGcontext); bzrtpCrypto_DHMComputeSecret(DHMbContext, (int (*)(void *, uint8_t *, size_t))bzrtpCrypto_getRandom, (void *)RNGcontext); CU_ASSERT_TRUE(memcmp(DHMaContext->key, DHMbContext->key, 256) == 0); /* generated key shall be 256 bytes long */ /* free context */ bzrtpCrypto_DestroyDHMContext(DHMaContext); bzrtpCrypto_DestroyDHMContext(DHMbContext); /* create an unused context and destroy it to check the correct implementation of the create/destroy functions */ DHMcContext = bzrtpCrypto_CreateDHMContext(ZRTP_KEYAGREEMENT_DH2k, 32); bzrtpCrypto_DestroyDHMContext(DHMcContext); /* destroy the RNG context */ bzrtpCrypto_destroyRNG(RNGcontext); } /** * * Tests for DHM-2048: just performe a key exchange and check that generated secrets are the same * */ void test_dhm3072(void) { bzrtpRNGContext_t *RNGcontext; bzrtpDHMContext_t *DHMaContext; bzrtpDHMContext_t *DHMbContext; bzrtpDHMContext_t *DHMcContext; /* start the Random Number Generator */ RNGcontext = bzrtpCrypto_startRNG((uint8_t *)"36 15 Grouiik vous souhaite une bonne journee", 46); /* Create the context for Alice */ DHMaContext = bzrtpCrypto_CreateDHMContext(ZRTP_KEYAGREEMENT_DH3k, 32); /* Create the public value for Alice G^Xa mod P */ bzrtpCrypto_DHMCreatePublic(DHMaContext, (int (*)(void *, uint8_t *, size_t))bzrtpCrypto_getRandom, (void *)RNGcontext); /* Create the context for Bob */ DHMbContext = bzrtpCrypto_CreateDHMContext(ZRTP_KEYAGREEMENT_DH3k, 32); /* Create the public value for Bob G^Xb mod P */ bzrtpCrypto_DHMCreatePublic(DHMbContext, (int (*)(void *, uint8_t *, size_t))bzrtpCrypto_getRandom, (void *)RNGcontext); /* exchange public values */ DHMaContext->peer = (uint8_t *)malloc(DHMaContext->primeLength*sizeof(uint8_t)); DHMbContext->peer = (uint8_t *)malloc(DHMbContext->primeLength*sizeof(uint8_t)); memcpy (DHMaContext->peer, DHMbContext->self, DHMaContext->primeLength*sizeof(uint8_t)); memcpy (DHMbContext->peer, DHMaContext->self, DHMbContext->primeLength*sizeof(uint8_t)); /* compute secret key */ bzrtpCrypto_DHMComputeSecret(DHMaContext, (int (*)(void *, uint8_t *, size_t))bzrtpCrypto_getRandom, (void *)RNGcontext); bzrtpCrypto_DHMComputeSecret(DHMbContext, (int (*)(void *, uint8_t *, size_t))bzrtpCrypto_getRandom, (void *)RNGcontext); CU_ASSERT_TRUE(memcmp(DHMaContext->key, DHMbContext->key, 384) == 0); /* generated key shall be 384 bytes long */ /* free context */ bzrtpCrypto_DestroyDHMContext(DHMaContext); bzrtpCrypto_DestroyDHMContext(DHMbContext); /* create an unused context and destroy it to check the correct implementation of the create/destroy functions */ DHMcContext = bzrtpCrypto_CreateDHMContext(ZRTP_KEYAGREEMENT_DH3k, 32); bzrtpCrypto_DestroyDHMContext(DHMcContext); /* destroy the RNG context */ bzrtpCrypto_destroyRNG(RNGcontext); } /** * * 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(0x12345678); bzrtpPacket_t *helloPacket = NULL; 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); } CU_ASSERT_FALSE(crypoAlgoAgreement(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 */ CU_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) { CU_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) { CU_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) { CU_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) { CU_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) { CU_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) { CU_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) { CU_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) { CU_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) { 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) { CU_ASSERT_TRUE(testAddMandatoryCryptoTypesIfNeeded(crypto_type->algoType, crypto_type->algoTypes, crypto_type->algoTypesCount, crypto_type->expectedTypes, crypto_type->expectedTypesCount)); crypto_type++; } } bzrtp-1.0.2/test/bzrtpCryptoTest.h000066400000000000000000000021621252270430700172100ustar00rootroot00000000000000/** @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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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.2/test/bzrtpParserTest.c000066400000000000000000003352141252270430700171660ustar00rootroot00000000000000/** @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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "CUnit/Basic.h" #ifndef WIN32 #include #else #include #endif #include "bzrtp/bzrtp.h" #include "typedef.h" #include "packetParser.h" #include "cryptoUtils.h" #include "zidCache.h" #include "testUtils.h" /** * 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 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} }; /* 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(void) { int i, retval; bzrtpPacket_t *zrtpPacket; /* Create zrtp Context to use H0-H3 chains and others */ bzrtpContext_t *context87654321 = bzrtp_createBzrtpContext(0x87654321); bzrtpContext_t *context12345678 = bzrtp_createBzrtpContext(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; updateCryptoFunctionPointers(context87654321->channelContext[0]); 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 = RESPONDER; for (i=0; ichannelContext[0]:context87654321->channelContext[0], patternZRTPPackets[i], patternZRTPMetaData[i][0], zrtpPacket); /*printf("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 */ if (zrtpPacket->messageType==MSGTYPE_HELLO) { if (patternZRTPMetaData[i][2]==0x87654321) { context12345678->channelContext[0]->peerPackets[HELLO_MESSAGE_STORE_ID] = zrtpPacket; } else { context87654321->channelContext[0]->peerPackets[HELLO_MESSAGE_STORE_ID] = zrtpPacket; } 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) { CU_ASSERT_TRUE(memcmp(zrtpPacket->packetString, patternZRTPPackets[i], patternZRTPMetaData[i][0]) == 0); } else { CU_FAIL("Unable to build packet"); } if (freePacketFlag == 1) { bzrtp_freeZrtpPacket(zrtpPacket); } } bzrtp_destroyBzrtpContext(context87654321, 0x87654321); bzrtp_destroyBzrtpContext(context12345678, 0x12345678); } /* 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; char zidFilename[80]; /* nom du fichier de cache */ } my_Context_t; static void freeBuf(void* p){ free(p); } int floadAlice(void *clientData, uint8_t **output, uint32_t *size, zrtpFreeBuffer_callback *cb) { /* get filename from ClientData */ my_Context_t *clientContext = (my_Context_t *)clientData; char *filename = clientContext->zidFilename; FILE *ALICECACHE = fopen(filename, "r+"); fseek(ALICECACHE, 0L, SEEK_END); /* Position to end of file */ *size = ftell(ALICECACHE); /* Get file length */ rewind(ALICECACHE); /* Back to start of file */ *output = (uint8_t *)malloc(*size*sizeof(uint8_t)+1); if (fread(*output, 1, *size, ALICECACHE)==0){ fprintf(stderr,"floadAlice() fread() error\n"); } *(*output+*size) = '\0'; *size += 1; fclose(ALICECACHE); *cb=freeBuf; return *size; } int fwriteAlice(void *clientData, const uint8_t *input, uint32_t size) { /* get filename from ClientData */ my_Context_t *clientContext = (my_Context_t *)clientData; char *filename = clientContext->zidFilename; FILE *ALICECACHE = fopen(filename, "w+"); int retval = fwrite(input, 1, size, ALICECACHE); fclose(ALICECACHE); return retval; } int floadBob(void *clientData, uint8_t **output, uint32_t *size, zrtpFreeBuffer_callback *cb) { /* get filename from ClientData */ my_Context_t *clientContext = (my_Context_t *)clientData; char *filename = clientContext->zidFilename; FILE *BOBCACHE = fopen(filename, "r+"); fseek(BOBCACHE, 0L, SEEK_END); /* Position to end of file */ *size = ftell(BOBCACHE); /* Get file length */ rewind(BOBCACHE); /* Back to start of file */ *output = (uint8_t *)malloc(*size*sizeof(uint8_t)+1); if (fread(*output, 1, *size, BOBCACHE)==0){ fprintf(stderr,"floadBob(): fread error.\n"); return -1; } *(*output+*size) = '\0'; *size += 1; fclose(BOBCACHE); *cb=freeBuf; return *size; } int fwriteBob(void *clientData, const uint8_t *input, uint32_t size) { /* get filename from ClientData */ my_Context_t *clientContext = (my_Context_t *)clientData; char *filename = clientContext->zidFilename; FILE *BOBCACHE = fopen(filename, "w+"); int retval = fwrite(input, 1, size, BOBCACHE); fclose(BOBCACHE); return retval; } 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(0x12345678); /* Alice's SSRC of main channel is 12345678 */ bzrtpContext_t *contextBob = bzrtp_createBzrtpContext(0x87654321); /* Bob's SSRC of main channel is 87654321 */ 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; bzrtpCallbacks_t cbs={0}; /* Create the client context, used for zidFilename only */ my_Context_t clientContextAlice; my_Context_t clientContextBob; memcpy(clientContextAlice.zidFilename, "./ZIDAlice.txt", 18); memcpy(clientContextBob.zidFilename, "./ZIDBob.txt", 16); /* attach the clientContext to the bzrtp Context */ retval = bzrtp_setClientData(contextAlice, 0x12345678, (void *)&clientContextAlice); retval += bzrtp_setClientData(contextBob, 0x87654321, (void *)&clientContextBob); /* set the cache related callback functions */ cbs.bzrtp_loadCache=floadAlice; cbs.bzrtp_writeCache=fwriteAlice; bzrtp_setCallbacks(contextAlice, &cbs); cbs.bzrtp_loadCache=floadBob; cbs.bzrtp_writeCache=fwriteBob; bzrtp_setCallbacks(contextBob, &cbs); bzrtp_message ("Init the contexts\n"); /* end the context init */ bzrtp_initBzrtpContext(contextAlice); bzrtp_initBzrtpContext(contextBob); /* 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 = crypoAlgoAgreement(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 = crypoAlgoAgreement(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_getPeerAssociatedSecretsHash(contextAlice, alice_HelloFromBob_message->ZID); bzrtp_getPeerAssociatedSecretsHash(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 */ bzrtpCrypto_getRandom(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 */ bzrtpCrypto_getRandom(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 */ bzrtpCrypto_getRandom(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 */ bzrtpCrypto_getRandom(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 */ bzrtpCrypto_getRandom(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 */ bzrtpCrypto_getRandom(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 */ bzrtpCrypto_getRandom(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 */ bzrtpCrypto_getRandom(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 */ bzrtpCrypto_getRandom(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 */ bzrtpCrypto_getRandom(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 */ bzrtpCrypto_getRandom(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 */ bzrtpCrypto_getRandom(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 */ bzrtpCrypto_getRandom(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 */ bzrtpCrypto_getRandom(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 */ bzrtpCrypto_getRandom(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 */ bzrtpCrypto_getRandom(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 = 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); bzrtpCrypto_DHMComputeSecret(contextAlice->DHMContext, (int (*)(void *, uint8_t *, size_t))bzrtpCrypto_getRandom, (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); bzrtpCrypto_DHMComputeSecret(contextBob->DHMContext, (int (*)(void *, uint8_t *, size_t))bzrtpCrypto_getRandom, (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"); CU_PASS("Secret Key exchange OK"); } else { CU_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"); CU_PASS("Total Hash match"); } else { bzrtp_message("AARGG!! total hash mismatch"); CU_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"); CU_PASS("s0 match"); } else { bzrtp_message("ERROR s0 differs\n"); CU_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"); CU_PASS("ZRTPSess match"); } else { bzrtp_message("ERROR ZRTPSess differs\n"); CU_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"); CU_PASS("SAS Hash match"); } else { bzrtp_message("ERROR SAS Hash differs\n"); CU_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"); CU_PASS("keys match"); } else { bzrtp_message("ERROR keys differ\n"); CU_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 */ 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 */ 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 = 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"); CU_PASS("Total Hash match"); } else { bzrtp_message("AARGG!! total hash mismatch"); CU_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"); CU_PASS("KDFContext match"); } else { bzrtp_message("AARGG!! KDF Context mismatch"); CU_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"); CU_PASS("s0 match"); } else { bzrtp_message("AARGG!! s0 mismatch"); CU_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"); CU_PASS("keys match"); } else { bzrtp_message("ERROR keys differ\n"); CU_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(0x12345678); /* Alice's SSRC of main channel is 12345678 */ bzrtpContext_t *contextBob = bzrtp_createBzrtpContext(0x87654321); /* Bob's SSRC of main channel is 87654321 */ /* set the cache related callback functions */ cbs.bzrtp_loadCache=floadAlice; cbs.bzrtp_writeCache=fwriteAlice; cbs.bzrtp_sendData=bzrtp_sendData; bzrtp_setCallbacks(contextAlice, &cbs); cbs.bzrtp_loadCache=floadBob; cbs.bzrtp_writeCache=fwriteBob; 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]; memcpy(aliceClientData.zidFilename, "./ZIDAlice.txt", 18); memcpy(bobClientData.zidFilename, "./ZIDBob.txt", 16); retval = bzrtp_setClientData(contextAlice, 0x12345678, (void *)&aliceClientData); retval += bzrtp_setClientData(contextBob, 0x87654321, (void *)&bobClientData); bzrtp_message("Set client data return %x\n", retval); /* run the init */ bzrtp_initBzrtpContext(contextAlice); bzrtp_initBzrtpContext(contextBob); /* 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 */ CU_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 { CU_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); } bzrtp-1.0.2/test/bzrtpParserTest.h000066400000000000000000000016201252270430700171620ustar00rootroot00000000000000/** @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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ void test_parser(void); void test_parserComplete(void); void test_stateMachine(void); bzrtp-1.0.2/test/bzrtpTest.c000066400000000000000000000065201252270430700160040ustar00rootroot00000000000000/** @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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "CUnit/Basic.h" #include "bzrtpCryptoTest.h" #include "bzrtpParserTest.h" #include "typedef.h" #include "testUtils.h" #ifdef HAVE_LIBXML2 #include #endif int main(int argc, char *argv[] ) { int i, fails_count=0; CU_pSuite cryptoWrapperTestSuite, cryptoUtilsTestSuite, parserTestSuite; CU_pSuite *suites[] = { &cryptoWrapperTestSuite, &cryptoUtilsTestSuite, &parserTestSuite, NULL }; if (argc>1) { if (argv[1][0] == '-') { if (strcmp(argv[1], "-verbose") == 0) { verbose = 1; } else { printf ("Usage:\n %s [-verbose] to enable extensive logging\n", argv[0]); return 1; } } else { printf ("Usage:\n %s [-verbose] to enable extensive logging\n", argv[0]); return 1; } } #ifdef HAVE_LIBXML2 xmlInitParser(); #endif /* initialize the CUnit test registry */ if (CUE_SUCCESS != CU_initialize_registry()) { return CU_get_error(); } /* Add the cryptoWrapper suite to the registry */ cryptoWrapperTestSuite = CU_add_suite("Bzrtp Crypto Wrappers", NULL, NULL); CU_add_test(cryptoWrapperTestSuite, "RNG", test_RNG); CU_add_test(cryptoWrapperTestSuite, "SHA256", test_sha256); CU_add_test(cryptoWrapperTestSuite, "HMAC-SHA256", test_hmacSha256); CU_add_test(cryptoWrapperTestSuite, "AES128-CFB", test_aes128CFB); CU_add_test(cryptoWrapperTestSuite, "DHM2048", test_dhm2048); CU_add_test(cryptoWrapperTestSuite, "DHM3072", test_dhm3072); /* Add the cryptoUtils suite to the registry */ cryptoUtilsTestSuite = CU_add_suite("Bzrtp Crypto Utils", NULL, NULL); CU_add_test(cryptoUtilsTestSuite, "zrtpKDF", test_zrtpKDF); CU_add_test(cryptoUtilsTestSuite, "CRC32", test_CRC32); CU_add_test(cryptoUtilsTestSuite, "algo agreement", test_algoAgreement); CU_add_test(cryptoUtilsTestSuite, "context algo setter and getter", test_algoSetterGetter); CU_add_test(cryptoUtilsTestSuite, "adding mandatory crypto algorithms if needed", test_addMandatoryCryptoTypesIfNeeded); /* Add the parser suite to the registry */ parserTestSuite = CU_add_suite("Bzrtp ZRTP Packet Parser", NULL, NULL); CU_add_test(parserTestSuite, "Parse", test_parser); CU_add_test(parserTestSuite, "Parse Exchange", test_parserComplete); CU_add_test(parserTestSuite, "State machine", test_stateMachine); /* Run all suites */ for(i=0; suites[i]; i++){ CU_basic_run_suite(*suites[i]); fails_count += CU_get_number_of_tests_failed(); } /* cleanup the CUnit registry */ CU_cleanup_registry(); #ifdef HAVE_LIBXML2 /* cleanup libxml2 */ xmlCleanupParser(); #endif return (fails_count == 0 ? 0 : 1); } bzrtp-1.0.2/test/testUtils.c000066400000000000000000000241101252270430700157760ustar00rootroot00000000000000/** @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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "testUtils.h" #include "cryptoUtils.h" int verbose = 0; void bzrtp_message(const char *fmt, ...) { if (verbose) { va_list args; va_start(args, fmt); vprintf(fmt, args); va_end(args); } } void printHex(char *title, uint8_t *data, uint32_t length) { if (verbose) { int 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++) { cryptoAlgoTypeIntToString(messageData->supportedHash[j], algoTypeString); printf("%.4s, ", algoTypeString); } printf ("\ncc "); for (j=0; jcc; j++) { cryptoAlgoTypeIntToString(messageData->supportedCipher[j], algoTypeString); printf("%.4s, ", algoTypeString); } printf ("\nac "); for (j=0; jac; j++) { cryptoAlgoTypeIntToString(messageData->supportedAuthTag[j], algoTypeString); printf("%.4s, ", algoTypeString); } printf ("\nkc "); for (j=0; jkc; j++) { cryptoAlgoTypeIntToString(messageData->supportedKeyAgreement[j], algoTypeString); printf("%.4s, ", algoTypeString); } printf ("\nsc "); for (j=0; jsc; j++) { 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); cryptoAlgoTypeIntToString(messageData->hashAlgo, algoTypeString); printf("Hash Algo: %.4s\n", algoTypeString); cryptoAlgoTypeIntToString(messageData->cipherAlgo, algoTypeString); printf("Cipher Algo: %.4s\n", algoTypeString); cryptoAlgoTypeIntToString(messageData->authTagAlgo, algoTypeString); printf("Auth tag Algo: %.4s\n", algoTypeString); cryptoAlgoTypeIntToString(messageData->keyAgreementAlgo, algoTypeString); printf("Key agreement Algo: %.4s\n", algoTypeString); 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); } } } 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); } cryptoAlgoTypeIntToString(channelContext->hashAlgo, buffer); printf(" Selected algos\n - Hash: %.4s\n", buffer); cryptoAlgoTypeIntToString(channelContext->cipherAlgo, buffer); printf(" - cipher: %.4s\n", buffer); cryptoAlgoTypeIntToString(channelContext->authTagAlgo, buffer); printf(" - auth tag: %.4s\n", buffer); cryptoAlgoTypeIntToString(channelContext->keyAgreementAlgo, buffer); printf(" - key agreement: %.4s\n", buffer); 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); } } bzrtp-1.0.2/test/testUtils.h000066400000000000000000000021631252270430700160070ustar00rootroot00000000000000/** @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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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);