pax_global_header00006660000000000000000000000064131341070130014503gustar00rootroot0000000000000052 comment=99472e6e08368ff843c7905f785c98f4f038a29d bctoolbox-0.6.0/000077500000000000000000000000001313410701300135015ustar00rootroot00000000000000bctoolbox-0.6.0/AUTHORS000066400000000000000000000001101313410701300145410ustar00rootroot00000000000000Belledonne Communications SARL bctoolbox-0.6.0/CMakeLists.txt000066400000000000000000000200501313410701300162360ustar00rootroot00000000000000############################################################################ # CMakeLists.txt # Copyright (C) 2016 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################################################ cmake_minimum_required(VERSION 2.8.12) set(CMAKE_MACOSX_RPATH ON) # Before cmake 3.0.0, MACOSX_RPATH was not set to ON by default - however this is no good reason to not enable it by default project(bctoolbox) set(BCTOOLBOX_VERSION_MAJOR 0) set(BCTOOLBOX_VERSION_MINOR 6) set(BCTOOLBOX_VERSION_PATCH 0) set(BCTOOLBOX_SO_VERSION 1) set(BCTOOLBOXTESTER_SO_VERSION 1) set(BCTOOLBOX_VERSION "${BCTOOLBOX_VERSION_MAJOR}.${BCTOOLBOX_VERSION_MINOR}.${BCTOOLBOX_VERSION_PATCH}") set(PROJECT_VERSION_MAJOR ${BCTOOLBOX_VERSION_MAJOR}) set(PROJECT_VERSION_MINOR ${BCTOOLBOX_VERSION_MINOR}) set(PROJECT_VERSION_PATCH ${BCTOOLBOX_VERSION_PATCH}) set(PROJECT_VERSION "${BCTOOLBOX_VERSION}") option(ENABLE_SHARED "Build shared library." ON) option(ENABLE_STATIC "Build static library." ON) option(ENABLE_POLARSSL "Enable polarssl support" ON) option(ENABLE_MBEDTLS "Enable mabedtls support" ON) option(ENABLE_STRICT "Pass strict flags to the compiler" ON) option(ENABLE_TESTS_COMPONENT "Enable compilation of tests helper library" ON) option(ENABLE_TESTS "Enable compilation of tests" ON) include(CheckLibraryExists) include(CheckSymbolExists) include(CheckCSourceCompiles) include(CMakePushCheckState) include(GNUInstallDirs) include(cmake/BcToolboxCMakeUtils.cmake) add_subdirectory(build) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") if(NOT CPACK_GENERATOR AND NOT CMAKE_INSTALL_RPATH AND CMAKE_INSTALL_PREFIX) set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}) message(STATUS "Setting install rpath to ${CMAKE_INSTALL_RPATH}") endif() if(ENABLE_MBEDTLS) find_package(MbedTLS) if(MBEDTLS_FOUND) message(STATUS "Using mbedTLS") endif() endif() if(ENABLE_POLARSSL AND NOT MBEDTLS_FOUND) find_package(PolarSSL REQUIRED) if(POLARSSL_FOUND) message(STATUS "Using polarSSL") if(CTR_DRBG_FREE) set(HAVE_CTR_DRGB_FREE 1) endif() endif() endif() if(HAVE_SSL_GET_DTLS_SRTP_PROTECTION_PROFILE) message(STATUS "DTLS SRTP available") set(HAVE_DTLS_SRTP 1) else() message(STATUS "DTLS SRTP not available") endif() if(MBEDTLS_FOUND) get_filename_component(mbedtls_library_path "${MBEDTLS_LIBRARIES}" PATH) string(REPLACE ";" " " MBEDTLS_LIBRARIES_STR "${MBEDTLS_LIBRARIES}") set(LIBS_PRIVATE "${LIBS_PRIVATE} ${MBEDTLS_LIBRARIES_STR}") endif() if(POLARSSL_FOUND) get_filename_component(polarssl_library_path "${POLARSSL_LIBRARIES}" PATH) set(LIBS_PRIVATE "${LIBS_PRIVATE} -L${polarssl_library_path} -lpolarssl") endif() if(ENABLE_TESTS_COMPONENT) find_package(BcUnit REQUIRED) cmake_push_check_state(RESET) list(APPEND CMAKE_REQUIRED_INCLUDES ${BCUNIT_INCLUDE_DIRS}) list(APPEND CMAKE_REQUIRED_LIBRARIES ${BCUNIT_LIBRARIES}) check_symbol_exists("CU_get_suite" "BCUnit/BCUnit.h" HAVE_CU_GET_SUITE) check_symbol_exists("CU_curses_run_tests" "BCUnit/BCUnit.h" HAVE_CU_CURSES) check_symbol_exists("CU_set_trace_handler" "BCUnit/Util.h" HAVE_CU_SET_TRACE_HANDLER) cmake_pop_check_state() set(TESTER_REQUIRES_PRIVATE "bcunit") endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/bctoolbox.pc.in ${CMAKE_CURRENT_BINARY_DIR}/bctoolbox.pc) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/bctoolbox.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) if(ENABLE_TESTS_COMPONENT AND BCUNIT_FOUND) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/bctoolbox-tester.pc.in ${CMAKE_CURRENT_BINARY_DIR}/bctoolbox-tester.pc) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/bctoolbox-tester.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) endif() find_package(Threads REQUIRED) include_directories( include src ${CMAKE_CURRENT_BINARY_DIR} ) set(BCTOOLBOX_CPPFLAGS ) if(ENABLE_STATIC) set(BCTBX_STATIC 1) list(APPEND BCTOOLBOX_CPPFLAGS "-DBCTBX_STATIC") endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/config.h PROPERTIES GENERATED ON) add_definitions("-DHAVE_CONFIG_H") set(STRICT_OPTIONS_CPP ) set(STRICT_OPTIONS_C ) if(CMAKE_VERSION VERSION_LESS 3.1 AND NOT APPLE AND NOT MSVC) set(STRICT_OPTIONS_CXX "-std=c++11") else() set(STRICT_OPTIONS_CXX ) endif() if(MSVC) if(ENABLE_STRICT) list(APPEND STRICT_OPTIONS_CPP "/WX") endif() else() list(APPEND STRICT_OPTIONS_CPP "-Wall" "-Wuninitialized") if(CMAKE_C_COMPILER_ID STREQUAL "Clang") list(APPEND STRICT_OPTIONS_CPP "-Wno-error=unknown-warning-option" "-Qunused-arguments" "-Wno-tautological-compare" "-Wno-builtin-requires-header" "-Wno-unused-function" "-Wno-gnu-designator" "-Wno-array-bounds") elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU") list(APPEND STRICT_OPTIONS_CPP "-Wno-error=pragmas") endif() if(APPLE) list(APPEND STRICT_OPTIONS_CPP "-Wno-error=unknown-warning-option" "-Qunused-arguments" "-Wno-tautological-compare" "-Wno-unused-function" "-Wno-array-bounds") endif() if(ENABLE_STRICT) list(APPEND STRICT_OPTIONS_CPP "-Werror" "-Wextra" "-Wno-unused-parameter" "-Wno-error=unknown-pragmas" "-Wuninitialized" "-Wno-missing-field-initializers" "-fno-strict-aliasing") list(APPEND STRICT_OPTIONS_C "-Werror" "-Wdeclaration-after-statement" "-Wstrict-prototypes") endif() endif() if(STRICT_OPTIONS_CPP) list(REMOVE_DUPLICATES STRICT_OPTIONS_CPP) string(REPLACE ";" " " STRICT_OPTIONS_CPP "${STRICT_OPTIONS_CPP}") endif() if(STRICT_OPTIONS_C) list(REMOVE_DUPLICATES STRICT_OPTIONS_C) string(REPLACE ";" " " STRICT_OPTIONS_C "${STRICT_OPTIONS_C}") endif() set(LINK_FLAGS ) if(APPLE) list(APPEND LINK_FLAGS "-framework Foundation") if(IOS) list(APPEND LINK_FLAGS "-framework CoreFoundation" "-framework CFNetwork" "-framework UIKit") endif() endif() string(REPLACE ";" " " LINK_FLAGS_STR "${LINK_FLAGS}") if(LINPHONE_BUILDER_GROUP_EXTERNAL_SOURCE_PATH_BUILDERS) set(EXPORT_TARGETS_NAME "LinphoneBuilder") else() set(EXPORT_TARGETS_NAME "BcToolbox") endif() check_library_exists("rt" "clock_gettime" "" HAVE_LIBRT) check_library_exists("dl" "dladdr" "" HAVE_LIBDL) check_include_file("execinfo.h" HAVE_EXECINFO) add_subdirectory(include) add_subdirectory(src) if(ENABLE_TESTS AND ENABLE_TESTS_COMPONENT AND BCUNIT_FOUND) add_subdirectory(tester) endif() include(CMakePackageConfigHelpers) write_basic_package_version_file( "${CMAKE_CURRENT_BINARY_DIR}/BcToolboxConfigVersion.cmake" VERSION ${PROJECT_VERSION} COMPATIBILITY AnyNewerVersion ) configure_file(cmake/BcToolboxConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/BcToolboxConfig.cmake" @ONLY ) configure_file(cmake/BcToolboxCMakeUtils.cmake "${CMAKE_CURRENT_BINARY_DIR}/BcToolboxCMakeUtils.cmake" COPYONLY) configure_file(cmake/BcGitVersion.cmake "${CMAKE_CURRENT_BINARY_DIR}/BcGitVersion.cmake" COPYONLY) configure_file(cmake/gitversion.h.in "${CMAKE_CURRENT_BINARY_DIR}/gitversion.h.in" COPYONLY) set(CONFIG_PACKAGE_LOCATION "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/cmake") install(EXPORT ${EXPORT_TARGETS_NAME}Targets FILE BcToolboxTargets.cmake DESTINATION ${CONFIG_PACKAGE_LOCATION} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/BcToolboxConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/BcToolboxConfigVersion.cmake" "${CMAKE_CURRENT_BINARY_DIR}/BcToolboxCMakeUtils.cmake" "${CMAKE_CURRENT_BINARY_DIR}/BcGitVersion.cmake" "${CMAKE_CURRENT_BINARY_DIR}/gitversion.h.in" DESTINATION ${CONFIG_PACKAGE_LOCATION} ) bctoolbox-0.6.0/COPYING000066400000000000000000000431271313410701300145430ustar00rootroot00000000000000 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. bctoolbox-0.6.0/ChangeLog000066400000000000000000000000001313410701300152410ustar00rootroot00000000000000bctoolbox-0.6.0/Makefile.am000066400000000000000000000004471313410701300155420ustar00rootroot00000000000000SUBDIRS=include src pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = bctoolbox.pc bctoolbox-tester.pc EXTRA_DIST=bctoolbox.pc.in \ bctoolbox-tester.pc.in \ build/CMakeLists.txt \ CMakeLists.txt \ include/CMakeLists.txt \ src/CMakeLists.txt \ tester/CMakeLists.txt \ README.md bctoolbox-0.6.0/NEWS000066400000000000000000000011771313410701300142060ustar00rootroot00000000000000bctoolbox-0.6.0 -- July 20th, 2017 * Add API to escape/unescape strings (SIP, VCARD). * Bug fixes. bctoolbox-0.5.1 -- February 22nd, 2017 * security bugfix: TLS session could be successfully established whereas the common name did not match the server name. * "const char * to void *" map feature bctoolbox-0.2.0 -- August 8th, 2016 * Creating a Virtual File System bctbx_vfs allowing direct file access and I/Os. * integrate OS abstraction layer, list API, logging API from oRTP * integrate getaddrinfo() abstraction api, in order to provide consistent getaddrinfo() support on all platforms. January 2016: * Initial commit bctoolbox-0.6.0/README.md000066400000000000000000000035401313410701300147620ustar00rootroot00000000000000BcToolbox ========= Utilities library used by Belledonne Communications softwares like belle-sip, mediastreamer2 and linphone. Depends ------- - **mbedtls[1]**: implementation of TLS interface of BcToolbox. For backward compatibility, support of polarssl is also provided. - **bcunit[2]** for unitary test tools. (optional) To compile ---------- cmake . -DCMAKE_INSTALL_PREFIX= -DCMAKE_PREFIX_PATH= make make install To make an rpm package ---------------------- cmake . -DCMAKE_INSTALL_PREFIX=/usr -DCPACK_GENERATOR="RPM" make package Options ------- - `CMAKE_INSTALL_PREFIX=`: install prefix. - `CMAKE_PREFIX_PATH=`: search path prefix for dependencies e.g. mbedtls. - `ENABLE_MBEDTLS=NO`: do not look for mbedtls. Then, polarssl will be selected. - `ENABLE_POLARSSL=NO`: do not look for polarssl. That ensure to use mbedtls. - `ENABLE_SHARED=NO`: do not build the shared libraries. - `ENABLE_STATIC=NO`: do not build the static libraries. - `ENABLE_STRICT=NO`: do not build with strict compilator flags e.g. `-Wall -Werror`. - `ENABLE_TESTS=NO`: do not build testing binaries. - `ENABLE_TESTS_COMPONENT=NO`: do not build libbctoolbox-tester. Notes ----- For backward compatibility with distributions not having the required 2.8.12 cmake version, an automake/autoconf build system is also available. It is maintained as a best effort and then should be used only in last resort. Note for packagers ------------------ Our CMake scripts may automatically add some paths into research paths of generated binaries. To ensure that the installed binaries are striped of any rpath, use `-DCMAKE_SKIP_INSTALL_RPATH=ON` while you invoke cmake. -------------------- - [1] - [2] git://git.linphone.org/bctoolbox.git or bctoolbox-0.6.0/autogen.sh000077500000000000000000000023701313410701300155040ustar00rootroot00000000000000#!/bin/sh srcdir=`dirname $0` test -z "$srcdir" && srcdir=. THEDIR=`pwd` cd $srcdir #AM_VERSION="1.10" if ! type aclocal-$AM_VERSION 1>/dev/null 2>&1; then # automake-1.10 (recommended) is not available on Fedora 8 AUTOMAKE=automake ACLOCAL=aclocal else ACLOCAL=aclocal-${AM_VERSION} AUTOMAKE=automake-${AM_VERSION} fi libtoolize="libtoolize" for lt in glibtoolize libtoolize15 libtoolize14 libtoolize13 ; do if test -x /usr/bin/$lt ; then libtoolize=$lt ; break fi if test -x /usr/local/bin/$lt ; then libtoolize=$lt ; break fi if test -x /opt/local/bin/$lt ; then libtoolize=$lt ; break fi done if test -d /usr/local/share/aclocal ; then ACLOCAL_ARGS="$ACLOCAL_ARGS -I /usr/local/share/aclocal" fi if test -d /share/aclocal ; then ACLOCAL_ARGS="$ACLOCAL_ARGS -I /share/aclocal" fi set -x rm -rf config.cache autom4te.cache $libtoolize --copy --force $ACLOCAL -I m4 $ACLOCAL_ARGS autoheader $AUTOMAKE --force-missing --add-missing --copy autoconf #install git pre-commit hooks if possible if [ -d .git/hooks ] && [ ! -f .git/hooks/pre-commit ]; then cp .git-pre-commit .git/hooks/pre-commit chmod +x .git/hooks/pre-commit fi cd $THEDIR bctoolbox-0.6.0/bctoolbox-tester.pc.in000066400000000000000000000005601313410701300177320ustar00rootroot00000000000000# This is a comment prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@CMAKE_INSTALL_PREFIX@ Name: bctoolbox-tester Description: A common set of tester wrappers used by Belledonne Communications's softwares Requires.private: @TESTER_REQUIRES_PRIVATE@ Version: @PROJECT_VERSION@ Libs: -L@CMAKE_INSTALL_FULL_LIBDIR@ -lbctoolbox-tester Cflags: -I@CMAKE_INSTALL_FULL_INCLUDEDIR@ bctoolbox-0.6.0/bctoolbox.pc.in000066400000000000000000000005111313410701300164220ustar00rootroot00000000000000# This is a comment prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@CMAKE_INSTALL_PREFIX@ Name: bctoolbox Description: A common set of tools used by Belledonne Communication's softwares Version: @PROJECT_VERSION@ Libs: -L@CMAKE_INSTALL_FULL_LIBDIR@ -lbctoolbox Libs.private: @LIBS_PRIVATE@ Cflags: -I@CMAKE_INSTALL_FULL_INCLUDEDIR@ bctoolbox-0.6.0/build/000077500000000000000000000000001313410701300146005ustar00rootroot00000000000000bctoolbox-0.6.0/build/CMakeLists.txt000077500000000000000000000074421313410701300173520ustar00rootroot00000000000000############################################################################ # CMakeLists.txt # Copyright (C) 2016 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################################################ if(NOT CPACK_PACKAGE_NAME) set(CPACK_PACKAGE_NAME "${PROJECT_NAME}") endif() set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Toolbox package used by Belledonne Communications projects") set(CPACK_PACKAGE_VENDOR "Belledonne Communications") set(CPACK_PACKAGE_CONTACT "jehan.monnier@linphone.org") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/../COPYING") set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR}) set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH}) set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}-${PROJECT_VERSION}) set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}") set(CPACK_SOURCE_GENERATOR "TGZ") set(CPACK_SOURCE_IGNORE_FILES "^${CMAKE_BINARY_DIR}" "^${PROJECT_SOURCE_DIR}/\\\\.git.*" ) #set(CPACK_COMPONENTS_ALL runtime devel) #set(CPACK_COMPONENT_DEVEL_DEPENDS runtime) #set(CPACK_COMPONENT_RUNTIME_DISPLAY_NAME ${PACKAGE}) #set(CPACK_COMPONENT_DEVEL_DISPLAY_NAME ${PACKAGE}-devel) find_package(Git 1.7.10) # --count option of git rev-list is available only since (more or less) git 1.7.10 if(GIT_EXECUTABLE) execute_process( COMMAND ${GIT_EXECUTABLE} rev-list --count ${PROJECT_VERSION}..HEAD OUTPUT_VARIABLE PROJECT_VERSION_BUILD OUTPUT_STRIP_TRAILING_WHITESPACE WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} ) # if BUILD VERSION is available, append it to package filename set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-${PROJECT_VERSION_BUILD}") set(CPACK_RPM_PACKAGE_RELEASE "${PROJECT_VERSION_BUILD}") set(CPACK_DEBIAN_PACKAGE_VERSION "${PROJECT_VERSION}-${PROJECT_VERSION_BUILD}") endif() set(CPACK_RPM_COMPONENT_INSTALL OFF) if("${CPACK_GENERATOR}" STREQUAL "RPM") set (CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION ${CMAKE_INSTALL_FULL_LIBDIR}/pkgconfig ${CMAKE_INSTALL_FULL_LIBDIR}/cmake) endif() if("${CPACK_GENERATOR}" STREQUAL "RPM" OR "${CPACK_GENERATOR}" STREQUAL "DEB") if (NOT CPACK_PACKAGING_INSTALL_PREFIX AND CMAKE_INSTALL_PREFIX) set(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) message(STATUS "Setting packaging install prefix to ${CPACK_PACKAGING_INSTALL_PREFIX}") endif() endif() if("${CPACK_GENERATOR}" STREQUAL "DEB") set(CPACK_DEBIAN_PACKAGE_DEBUG ON) set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) set(CPACK_PROJECT_CONFIG_FILE "${CMAKE_BINARY_DIR}/CPackEnv.cmake") file(WRITE "${CPACK_PROJECT_CONFIG_FILE}" "set(ENV{LD_LIBRARY_PATH} \"./${CMAKE_INSTALL_FULL_LIBDIR}\")") set(SHLIBS_FILE "${CMAKE_CURRENT_BINARY_DIR}/shlibs") file(WRITE "${SHLIBS_FILE}" "libbctoolbox ${BCTOOLBOX_SO_VERSION} ${CPACK_PACKAGE_NAME}\n") file(APPEND "${SHLIBS_FILE}" "libbctoolbox-tester ${BCTOOLBOXTESTER_SO_VERSION} ${CPACK_PACKAGE_NAME}\n") execute_process(COMMAND chmod 644 "${SHLIBS_FILE}") set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA ${SHLIBS_FILE}) endif() include(CPack) bctoolbox-0.6.0/build/android/000077500000000000000000000000001313410701300162205ustar00rootroot00000000000000bctoolbox-0.6.0/build/android/Android-mbedtls.mk000066400000000000000000000006021313410701300215570ustar00rootroot00000000000000 LOCAL_PATH:= $(call my-dir)/../../src/ include $(CLEAR_VARS) LOCAL_MODULE:= libbctoolbox LOCAL_SRC_FILES := \ crypto/mbedtls.c LOCAL_CFLAGS += -Wno-maybe-uninitialized -DHAVE_DTLS_SRTP LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/ \ $(LOCAL_PATH)/../include \ $(LOCAL_PATH)/../../externals/mbedtls/include LOCAL_STATIC_LIBRARIES := \ mbedtls include $(BUILD_STATIC_LIBRARY) bctoolbox-0.6.0/build/android/Android-polarssl.mk000066400000000000000000000006051313410701300217670ustar00rootroot00000000000000 LOCAL_PATH:= $(call my-dir)/../../src/ include $(CLEAR_VARS) LOCAL_MODULE:= libbctoolbox LOCAL_SRC_FILES := \ crypto/polarssl.c LOCAL_CFLAGS += -Wno-maybe-uninitialized -DHAVE_DTLS_SRTP LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/ \ $(LOCAL_PATH)/../include \ $(LOCAL_PATH)/../../externals/polarssl/include LOCAL_STATIC_LIBRARIES := \ polarssl include $(BUILD_STATIC_LIBRARY) bctoolbox-0.6.0/build/android/Android-tester.mk000066400000000000000000000006241313410701300214370ustar00rootroot00000000000000LOCAL_PATH:= $(call my-dir)/../../src/ include $(CLEAR_VARS) LOCAL_MODULE:= libbctoolbox_tester LOCAL_SRC_FILES := \ tester/utils.c LOCAL_CFLAGS += -Wno-maybe-uninitialized -DIN_BCUNIT_SOURCES -DHAVE_CU_SET_TRACE_HANDLER=1 -DHAVE_CU_GET_SUITE=1 LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/ \ $(LOCAL_PATH)/../include \ $(LOCAL_PATH)/../../externals/bcunit/BCUnit/Headers include $(BUILD_STATIC_LIBRARY) bctoolbox-0.6.0/build/osx/000077500000000000000000000000001313410701300154115ustar00rootroot00000000000000bctoolbox-0.6.0/build/osx/Info.plist.in000066400000000000000000000025721313410701300177740ustar00rootroot00000000000000 CFBundleDevelopmentRegion English CFBundleExecutable bctoolbox CFBundleGetInfoString ${MACOSX_BUNDLE_INFO_STRING} CFBundleIconFile ${MACOSX_BUNDLE_ICON_FILE} CFBundleIdentifier ${MACOSX_FRAMEWORK_IDENTIFIER} LSMinimumSystemVersion ${MIN_OS} MinimumOSVersion ${MIN_OS} CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString ${MACOSX_BUNDLE_LONG_VERSION_STRING} CFBundleName ${MACOSX_BUNDLE_BUNDLE_NAME} CFBundlePackageType FMWK CFBundleShortVersionString ${BCTOOLBOX_VERSION} CFBundleSignature ???? CFBundleVersion ${BCTOOLBOX_VERSION} CSResourcesFileMapped NSHumanReadableCopyright ${MACOSX_BUNDLE_COPYRIGHT} NSPrincipalClass NSApplication NSHighResolutionCapable True bctoolbox-0.6.0/cmake/000077500000000000000000000000001313410701300145615ustar00rootroot00000000000000bctoolbox-0.6.0/cmake/BcGitVersion.cmake000066400000000000000000000041761313410701300201310ustar00rootroot00000000000000############################################################################ # BcGitVersion.cmake # Copyright (C) 2017 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################################################ if(GIT_EXECUTABLE) macro(GIT_COMMAND OUTPUT_VAR) set(GIT_ARGS ${ARGN}) execute_process( COMMAND ${GIT_EXECUTABLE} ${ARGN} WORKING_DIRECTORY ${WORK_DIR} OUTPUT_VARIABLE ${OUTPUT_VAR} OUTPUT_STRIP_TRAILING_WHITESPACE ) endmacro() GIT_COMMAND(GIT_DESCRIBE describe --always) GIT_COMMAND(GIT_TAG describe --abbrev=0) GIT_COMMAND(GIT_REVISION rev-parse HEAD) endif() string(TOUPPER "${PROJECT_NAME}" PREFIX_GIT_VERSION) string(REPLACE "-" "_" PREFIX_GIT_VERSION "${PREFIX_GIT_VERSION}") if(GIT_DESCRIBE) if(NOT GIT_TAG STREQUAL PROJECT_VERSION) message(WARNING "Project version (${PROJECT_VERSION}) and git tag (${GIT_TAG}) differ. Please put them identical") endif() set(PROJECT_GIT_VERSION "${GIT_DESCRIBE}") configure_file("${TEMPLATE_DIR}/gitversion.h.in" "${OUTPUT_DIR}/gitversion.h" @ONLY) elseif(GIT_REVISION) set(PROJECT_GIT_VERSION "${LINPHONE_VERSION}_${GIT_REVISION}") configure_file("${TEMPLATE_DIR}/gitversion.h.in" "${OUTPUT_DIR}/gitversion.h" @ONLY) else() if(NOT EXISTS "${OUTPUT_DIR}/gitversion.h") execute_process(COMMAND ${CMAKE_COMMAND} -E touch "${OUTPUT_DIR}/gitversion.h") endif() endif() bctoolbox-0.6.0/cmake/BcToolboxCMakeUtils.cmake000066400000000000000000000060671313410701300214110ustar00rootroot00000000000000############################################################################ # BcToolboxCMakeUtils.cmake # Copyright (C) 2017 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################################################ set(BCTOOLBOX_CMAKE_UTILS_DIR "${CMAKE_CURRENT_LIST_DIR}") macro(bc_apply_compile_flags SOURCE_FILES) if(${SOURCE_FILES}) set(options "") foreach(a ${ARGN}) if(${a}) string(REPLACE ";" " " options_${a} "${${a}}") set(options "${options} ${options_${a}}") endif() endforeach() if(options) set_source_files_properties(${${SOURCE_FILES}} PROPERTIES COMPILE_FLAGS "${options}") endif() endif() endmacro() macro(bc_git_version PROJECT_NAME PROJECT_VERSION) find_package(Git) add_custom_target(${PROJECT_NAME}-git-version COMMAND ${CMAKE_COMMAND} -DGIT_EXECUTABLE=${GIT_EXECUTABLE} -DPROJECT_NAME=${PROJECT_NAME} -DPROJECT_VERSION=${PROJECT_VERSION} -DWORK_DIR=${CMAKE_CURRENT_SOURCE_DIR} -DTEMPLATE_DIR=${BCTOOLBOX_CMAKE_UTILS_DIR} -DOUTPUT_DIR=${CMAKE_CURRENT_BINARY_DIR} -P ${BCTOOLBOX_CMAKE_UTILS_DIR}/BcGitVersion.cmake BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/gitversion.h" ) endmacro() macro(bc_project_build_version PROJECT_VERSION PROJECT_BUILD_VERSION) find_program (WC wc) if (WC) set(GIT_MINIMUN_VERSION 1.7.1) #might be even lower else() set(GIT_MINIMUN_VERSION 1.7.10) # --count option of git rev-list is available only since (more or less) git 1.7.10) endif() find_package(Git ${GIT_MINIMUN_VERSION}) string(COMPARE GREATER "${GIT_VERSION_STRING}" "1.7.10" GIT_REV_LIST_HAS_COUNT) if (GIT_REV_LIST_HAS_COUNT) set(GIT_REV_LIST_COMMAND "${GIT_EXECUTABLE}" "rev-list" "--count" "${PROJECT_VERSION}..HEAD") set(WC_COMMAND "more") #nop else() set(GIT_REV_LIST_COMMAND "${GIT_EXECUTABLE}" "rev-list" "${PROJECT_VERSION}..HEAD") set(WC_COMMAND "${WC}" "-l") endif() if(GIT_EXECUTABLE) execute_process( COMMAND ${GIT_REV_LIST_COMMAND} COMMAND ${WC_COMMAND} OUTPUT_VARIABLE PROJECT_VERSION_BUILD OUTPUT_STRIP_TRAILING_WHITESPACE WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} ) endif() if (NOT PROJECT_VERSION_BUILD) set(PROJECT_VERSION_BUILD 0) endif() endmacro() bctoolbox-0.6.0/cmake/BcToolboxConfig.cmake.in000066400000000000000000000074601313410701300212200ustar00rootroot00000000000000############################################################################ # BcToolboxConfig.cmake # Copyright (C) 2015 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################################################ # # Config file for the bctoolbox package. # Some components can be asked for: core, tester. # # It defines the following variables: # # BCTOOLBOX_FOUND - system has bctoolbox # BCTOOLBOX_INCLUDE_DIRS - the bctoolbox include directory # BCTOOLBOX_LIBRARIES - The libraries needed to use bctoolbox # BCTOOLBOX_CPPFLAGS - The compilation flags needed to use bctoolbox # BCTOOLBOX_LDFLAGS - The linking flags needed to use bctoolbox # BCTOOLBOX_${comp}_FOUND - system has bctoolbox "comp" component # BCTOOLBOX_${comp}_INCLUDE_DIRS - the bctoolbox "comp" component include directory # BCTOOLBOX_${comp}_LIBRARIES - The libraries needed to use bctoolbox "comp" component if(NOT LINPHONE_BUILDER_GROUP_EXTERNAL_SOURCE_PATH_BUILDERS) include("${CMAKE_CURRENT_LIST_DIR}/BcToolboxTargets.cmake") endif() list(APPEND BcToolbox_FIND_COMPONENTS core) list(REMOVE_DUPLICATES BcToolbox_FIND_COMPONENTS) set(BcToolbox_FIND_REQUIRED_core TRUE) set(BCTOOLBOX_CPPFLAGS @BCTOOLBOX_CPPFLAGS@) set(BCTOOLBOX_LDFLAGS "@LINK_FLAGS_STR@") set(BCTOOLBOX_LIBRARIES ) foreach(comp ${BcToolbox_FIND_COMPONENTS}) string(TOUPPER ${comp} uppercomp) if(comp STREQUAL "core") set(targetname bctoolbox) else() set(targetname bctoolbox-${comp}) endif() if(@ENABLE_SHARED@) set(BCTOOLBOX_${uppercomp}_LIBRARIES ${targetname}) else() set(targetname ${targetname}-static) if(TARGET ${targetname}) if(LINPHONE_BUILDER_GROUP_EXTERNAL_SOURCE_PATH_BUILDERS) set(BCTOOLBOX_${uppercomp}_LIBRARIES ${targetname}) else() get_target_property(BCTOOLBOX_${uppercomp}_LIBRARIES ${targetname} LOCATION) endif() get_target_property(BCTOOLBOX_${uppercomp}_LINK_LIBRARIES ${targetname} INTERFACE_LINK_LIBRARIES) if(BCTOOLBOX_${uppercomp}_LINK_LIBRARIES) list(APPEND BCTOOLBOX_${uppercomp}_LIBRARIES ${BCTOOLBOX_${uppercomp}_LINK_LIBRARIES}) endif() endif() endif() if(TARGET ${targetname}) get_target_property(BCTOOLBOX_${uppercomp}_INCLUDE_DIRS ${targetname} INTERFACE_INCLUDE_DIRECTORIES) if(LINPHONE_BUILDER_GROUP_EXTERNAL_SOURCE_PATH_BUILDERS) list(INSERT BCTOOLBOX_${uppercomp}_INCLUDE_DIRS 0 "${EP_bctoolbox_INCLUDE_DIR}") else() list(INSERT BCTOOLBOX_${uppercomp}_INCLUDE_DIRS 0 "@CMAKE_INSTALL_FULL_INCLUDEDIR@") endif() list(REMOVE_DUPLICATES BCTOOLBOX_${uppercomp}_INCLUDE_DIRS) list(APPEND BCTOOLBOX_LIBRARIES ${BCTOOLBOX_${uppercomp}_LIBRARIES}) list(APPEND BCTOOLBOX_INCLUDE_DIRS ${BCTOOLBOX_${uppercomp}_INCLUDE_DIRS}) set(BCTOOLBOX_${uppercomp}_FOUND 1) if(comp STREQUAL "core") set(BCTOOLBOX_FOUND 1) endif() elseif(BcToolbox_FIND_REQUIRED_${comp}) message(FATAL_ERROR "Required bctoolbox component \"${comp}\" cannot be found") endif() endforeach() if(BCTOOLBOX_INCLUDE_DIRS) list(REMOVE_DUPLICATES BCTOOLBOX_INCLUDE_DIRS) endif() include("${CMAKE_CURRENT_LIST_DIR}/BcToolboxCMakeUtils.cmake") bctoolbox-0.6.0/cmake/FindMbedTLS.cmake000066400000000000000000000052131313410701300176170ustar00rootroot00000000000000############################################################################ # FindMdebTLS.txt # Copyright (C) 2015 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################################################ # # - Find the mbedTLS include file and library # # MBEDTLS_FOUND - system has mbedTLS # MBEDTLS_INCLUDE_DIRS - the mbedTLS include directory # MBEDTLS_LIBRARIES - The libraries needed to use mbedTLS include(CMakePushCheckState) include(CheckIncludeFile) include(CheckCSourceCompiles) include(CheckSymbolExists) find_path(MBEDTLS_INCLUDE_DIRS NAMES mbedtls/ssl.h PATH_SUFFIXES include ) # find the three mbedtls library find_library(MBEDTLS_LIBRARY NAMES mbedtls ) find_library(MBEDX509_LIBRARY NAMES mbedx509 ) find_library(MBEDCRYPTO_LIBRARY NAMES mbedcrypto ) # check we have a mbedTLS version 2 or above(all functions are prefixed mbedtls_) if(MBEDTLS_LIBRARY AND MBEDX509_LIBRARY AND MBEDCRYPTO_LIBRARY) cmake_push_check_state(RESET) set(CMAKE_REQUIRED_INCLUDES ${MBEDTLS_INCLUDE_DIRS}) set(CMAKE_REQUIRED_LIBRARIES ${MBEDTLS_LIBRARY} ${MBEDX509_LIBRARY} ${MBEDCRYPTO_LIBRARY}) check_symbol_exists(mbedtls_ssl_init "mbedtls/ssl.h" MBEDTLS_V2) cmake_pop_check_state() endif() if(MBEDTLS_V2) set (MBEDTLS_LIBRARIES ${MBEDTLS_LIBRARY} ${MBEDX509_LIBRARY} ${MBEDCRYPTO_LIBRARY} ) endif() if(MBEDTLS_LIBRARIES) cmake_push_check_state(RESET) set(CMAKE_REQUIRED_INCLUDES ${MBEDTLS_INCLUDE_DIRS}) set(CMAKE_REQUIRED_LIBRARIES ${MBEDTLS_LIBRARIES}) check_symbol_exists(mbedtls_ssl_get_dtls_srtp_protection_profile "mbedtls/ssl.h" HAVE_SSL_GET_DTLS_SRTP_PROTECTION_PROFILE) cmake_pop_check_state() endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(MbedTLS DEFAULT_MSG MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARIES ) mark_as_advanced(MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARIES HAVE_SSL_GET_DTLS_SRTP_PROTECTION_PROFILE) bctoolbox-0.6.0/cmake/FindPolarSSL.cmake000066400000000000000000000047451313410701300200350ustar00rootroot00000000000000############################################################################ # 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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) find_path(POLARSSL_INCLUDE_DIRS NAMES polarssl/ssl.h PATH_SUFFIXES include ) if(POLARSSL_INCLUDE_DIRS) set(HAVE_POLARSSL_SSL_H 1) endif() find_library(POLARSSL_LIBRARIES NAMES polarssl mbedtls PATH_SUFFIXES bin lib ) if(POLARSSL_LIBRARIES) #x509parse_crtpath is present in polarssl1.3 but not 1.2, use it to check what version is present cmake_push_check_state(RESET) set(CMAKE_REQUIRED_INCLUDES ${POLARSSL_INCLUDE_DIRS}) set(CMAKE_REQUIRED_LIBRARIES ${POLARSSL_LIBRARIES}) check_c_source_compiles(" #include int main(int argc, char *argv[]) { x509_crt_parse_path(0,0); return 0; }" POLARSSL_VERSION13_OK) check_symbol_exists(ssl_get_dtls_srtp_protection_profile "polarssl/ssl.h" HAVE_SSL_GET_DTLS_SRTP_PROTECTION_PROFILE) check_symbol_exists(ctr_drbg_free "polarssl/ctr_drbg.h" CTR_DRBG_FREE) 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 POLARSSL_VERSION13_OK CTR_DRGB_FREE HAVE_SSL_GET_DTLS_SRTP_PROTECTION_PROFILE) bctoolbox-0.6.0/cmake/gitversion.h.in000066400000000000000000000014641313410701300175350ustar00rootroot00000000000000/* linphone Copyright (C) 2010-2017 Belledonne Communications SARL This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #define @PREFIX_GIT_VERSION@_GIT_VERSION "@PROJECT_GIT_VERSION@"bctoolbox-0.6.0/config.h.cmake000066400000000000000000000023411313410701300161760ustar00rootroot00000000000000/*************************************************************************** * config.h.cmake * Copyright (C) 2014 Belledonne Communications, Grenoble France * **************************************************************************** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ #cmakedefine HAVE_DTLS_SRTP 1 #cmakedefine HAVE_CTR_DRGB_FREE 1 #cmakedefine HAVE_CU_GET_SUITE 1 #cmakedefine HAVE_CU_CURSES 1 #cmakedefine HAVE_CU_SET_TRACE_HANDLER 1 #cmakedefine HAVE_LIBRT 1 #cmakedefine BCTBX_STATIC bctoolbox-0.6.0/configure.ac000077500000000000000000000152001313410701300157700ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.63]) AC_INIT([bctoolbox],[0.5.1],[jehan.monnier@linphone.org]) BCTOOLBOX_SO_CURRENT=1 dnl increment this number when you add/change/remove an interface BCTOOLBOX_SO_REVISION=1 dnl increment this number when you change source code, without changing interfaces; set to 0 when incrementing CURRENT BCTOOLBOX_SO_AGE=0 dnl increment this number when you add an interface, set to 0 if you remove an interface BCTOOLBOX_SO_VERSION=$BCTOOLBOX_SO_CURRENT:$BCTOOLBOX_SO_REVISION:$BCTOOLBOX_SO_AGE AC_SUBST(BCTOOLBOX_SO_CURRENT, $BCTOOLBOX_SO_CURRENT) AC_SUBST(BCTOOLBOX_SO_VERSION) AC_CONFIG_SRCDIR([src/crypto/mbedtls.c]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_HEADERS([config.h]) AC_CANONICAL_SYSTEM LT_INIT([shared disable-static]) dnl initialize pkg-config so that we can use it within if else fi statements. PKG_PROG_PKG_CONFIG() AM_INIT_AUTOMAKE([subdir-objects foreign]) AM_SILENT_RULES(yes) # Checks for programs. dnl do not put anythingelse before AC_PROG_CC unless checking if macro still work for clang dnl because of tunnel library wrapper, C++ is required. AC_PROG_CXX(["xcrun clang++" g++]) AC_PROG_CC(["xcrun clang" gcc]) AC_PROG_OBJC(["xcrun clang" gcc]) AM_PROG_CC_C_O case $INSTALL in *ginstall*) INSTALL="$INSTALL -C" ;; esac dnl AC_PROG_CC_C99 CFLAGS="$CFLAGS " if test "$debug" = "no" ; then CFLAGS="$CFLAGS -g -O2" else CFLAGS="$CFLAGS -g" fi CXXFLAGS="$CXXFLAGS -std=c++11" AC_ARG_ENABLE(strict, [ --enable-strict Turn on strict mode compilation, no warnings allowed (default=yes)], [case "${enableval}" in yes) strict=true ;; no) strict=false ;; *) AC_MSG_ERROR(bad value ${enableval} for --enable-strict) ;; esac],[strict=true]) STRICT_OPTIONS="-Wall" if test "$strict" = "true" ; then STRICT_OPTIONS="$STRICT_OPTIONS -Werror -Wextra -Wno-unused-parameter -Wno-missing-field-initializers" fi AC_SUBST(STRICT_OPTIONS) # Checks for libraries. # Checks for header files. dnl check for argument supplied. If value is yes, no arg was supplied so set path to default value. AC_ARG_WITH( mbedtls, [ --with-mbedtls Set prefix where mbedtls can be found (ex:/usr or /usr/local)[default=PREFIX] ], [case "${withval}" in yes) mbedtls_prefix="/usr" ;; *) mbedtls_prefix=${withval} ;; esac], [ mbedtls_prefix=${prefix} ]) AC_ARG_WITH( polarssl, [ --with-polarssl Set prefix where polarssl can be found (ex:/usr or /usr/local)[default=PREFIX] ], [case "${withval}" in yes) polarssl_prefix="/usr" ;; *) polarssl_prefix=${withval} ;; esac], [ polarssl_prefix=${prefix} ]) AC_ARG_WITH( bcunit, [ --with-bcunit Set prefix where bcunit can be found (ex:/usr or /usr/local)[default=PREFIX] ], [case "${withval}" in yes) bcunit_prefix="/usr/local" ;; *) bcunit_prefix=${withval} ;; esac], [ bcunit_prefix=${prefix} ]) if test "$mbedtls_prefix" = "NONE" ; then mbedtls_prefix=/usr fi if test "$polarssl_prefix" = "NONE" ; then polarssl_prefix=/usr fi if test "$bcunit_prefix" = "NONE" ; then bcunit_prefix=/usr/local fi if test "$mbedtls_prefix" != "/usr" ; then MBEDTLS_CFLAGS="-I${mbedtls_prefix}/include" MBEDTLS_LIBS="-L${mbedtls_prefix}/lib" fi if test "$bcunit_prefix" != "/usr/local" ; then BCUNIT_CFLAGS="-I${bcunit_prefix}/include" BCUNIT_LIBS="-L${bcunit_prefix}/lib" fi CPPFLAGS_save=$CPPFLAGS LIBS_save=$LIBS CPPFLAGS="$CPPFLAGS $BCUNIT_CFLAGS" LIBS="$LIBS $BCUNIT_LIBS" AC_CHECK_HEADER(BCUnit/BCUnit.h, [ AC_CHECK_LIB(bcunit, CU_get_error, [BCUNIT_LIBS="$BCUNIT_LIBS -lbcunit"; bcunit_found=true], [bcunit_found=false]) ], [bcunit_found=false] ) if test "$bcunit_found" != "true" ; then AC_MSG_ERROR("BCUnit not found") else AC_CHECK_LIB(bcunit, CU_get_suite, [ AC_DEFINE(HAVE_CU_GET_SUITE, 1, [Defined when CU_get_suite is available])] ) AC_CHECK_LIB(bcunit, CU_set_trace_handler, [ AC_DEFINE(HAVE_CU_SET_TRACE_HANDLER, 1, [Defined when CU_set_trace_handler is available])] ) AC_CHECK_HEADERS(BCUnit/CUCurses.h) fi CPPFLAGS=$CPPFLAGS_save LIBS=$LIBS_save AC_SUBST(BCUNIT_CFLAGS) AC_SUBST(BCUNIT_LIBS) CPPFLAGS_save=$CPPFLAGS LIBS_save=$LIBS CPPFLAGS="$CPPFLAGS $MBEDTLS_CFLAGS" LIBS="$LIBS $MBEDTLS_LIBS" AC_CHECK_HEADER(mbedtls/ssl.h, [ AC_CHECK_LIB(mbedtls, mbedtls_pk_parse_key, [mbedtls_found=true; MBEDTLS_LIBS="$MBEDTLS_LIBS -lmbedtls -lmbedcrypto -lmbedx509"], [mbedtls_found=false], [-lmbedcrypto]) ], [mbedtls_found=false] ) CPPFLAGS=$CPPFLAGS_save LIBS=$LIBS_save AC_CHECK_LIB(dl, dladdr) AM_CONDITIONAL(ENABLE_MBEDTLS, test "$mbdetls_found" = "true") if test "$mbedtls_found" = "false" ; then MBEDTLS_CFLAGS= MBEDTLS_LIBS= if test "$polarssl_prefix" != "/usr" ; then POLARSSL_CFLAGS="-I${polarssl_prefix}" POLARSSL_LIBS="-L${polarssl_prefix}/lib" fi CPPFLAGS_save=$CPPFLAGS LIBS_save=$LIBS CPPFLAGS="$CPPFLAGS $POLARSSL_CFLAGS" LIBS="$LIBS $POLARSSL_LIBS" AC_CHECK_HEADER(polarssl/ssl.h, [ AC_CHECK_LIB(polarssl, ssl_read, [polarssl_found=true; POLARSSL_LIBS="$POLARSSL_LIBS -lpolarssl"], [polarssl_found=false]) ], [polarssl_found=false] ) if test "$polarssl_found" = "false" ; then AC_MSG_ERROR("Neither polarssl nor mbedtls were found.") fi AC_CHECK_HEADER(polarssl/compat-1.2.h, [polarssl_post_12_found=true], [polarssl_post_12_found=false]) CPPFLAGS=$CPPFLAGS_save LIBS=$LIBS_save fi dnl add thread flags case $host in i386-apple*|armv6-apple*|armv7-apple*|armv7s-apple*|aarch64-apple*|arm64-apple*|*-darwin.ios) ios_found=yes ;; x86_64-apple*|i686-apple*) macosx_found=yes ;; *nto-qnx*) ;; *) CFLAGS="$CFLAGS -pthread -D_REENTRANT" CXXFLAGS="$CXXFLAGS -pthread -D_REENTRANT" LIBS="$LIBS -pthread -lpthread" ;; esac AC_SUBST(MBEDTLS_CFLAGS) AC_SUBST(MBEDTLS_LIBS) AC_SUBST(POLARSSL_CFLAGS) AC_SUBST(POLARSSL_LIBS) AM_CONDITIONAL(ENABLE_POLARSSL12, test "$polarssl_post_12_found" = "false") AM_CONDITIONAL(ENABLE_POLARSSL, test "$polarssl_post_12_found" = "true") AM_CONDITIONAL(ENABLE_MBEDTLS, test "$mbedtls_found" = "true") dnl substitute variables used by .pc files if test "$prefix" = "NONE" ; then install_prefix=/usr/local else install_prefix=$prefix fi PROJECT_VERSION=$VERSION CMAKE_INSTALL_PREFIX=$install_prefix CMAKE_INSTALL_FULL_LIBDIR=${libdir} CMAKE_INSTALL_FULL_INCLUDEDIR=${install_prefix}/include AC_SUBST(PROJECT_VERSION) AC_SUBST(CMAKE_INSTALL_PREFIX) AC_SUBST(CMAKE_INSTALL_FULL_LIBDIR) AC_SUBST(CMAKE_INSTALL_FULL_INCLUDEDIR) AC_SUBST(TESTER_REQUIRES_PRIVATE) LIBS_PRIVATE="$LIBS_PRIVATE $MBEDTLS_LIBS $POLARSSL_LIBS" AC_SUBST(LIBS_PRIVATE) AC_CONFIG_FILES( [ Makefile include/Makefile include/bctoolbox/Makefile src/Makefile bctoolbox-tester.pc bctoolbox.pc ]) AC_OUTPUT bctoolbox-0.6.0/include/000077500000000000000000000000001313410701300151245ustar00rootroot00000000000000bctoolbox-0.6.0/include/CMakeLists.txt000066400000000000000000000031731313410701300176700ustar00rootroot00000000000000############################################################################ # CMakeLists.txt # Copyright (C) 2016 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################################################ set(HEADER_FILES crypto.h defs.h list.h logging.h map.h port.h vfs.h vconnect.h parser.h ) if(ENABLE_TESTS_COMPONENT) list(APPEND HEADER_FILES tester.h) endif() if(HAVE_EXECINFO) list(APPEND HEADER_FILES exception.hh) endif() set(BCTOOLBOX_HEADER_FILES ) foreach(HEADER_FILE ${HEADER_FILES}) list(APPEND BCTOOLBOX_HEADER_FILES "${CMAKE_CURRENT_LIST_DIR}/bctoolbox/${HEADER_FILE}") endforeach() set(BCTOOLBOX_HEADER_FILES ${BCTOOLBOX_HEADER_FILES} PARENT_SCOPE) install(FILES ${BCTOOLBOX_HEADER_FILES} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/bctoolbox PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ ) bctoolbox-0.6.0/include/Makefile.am000066400000000000000000000000221313410701300171520ustar00rootroot00000000000000SUBDIRS=bctoolbox bctoolbox-0.6.0/include/bctoolbox/000077500000000000000000000000001313410701300171175ustar00rootroot00000000000000bctoolbox-0.6.0/include/bctoolbox/Makefile.am000066400000000000000000000002671313410701300211600ustar00rootroot00000000000000bctoolboxdir=$(includedir)/bctoolbox bctoolbox_HEADERS=tester.h crypto.h defs.h map.h list.h port.h logging.h vfs.h vconnect.h exception.hh parser.h EXTRA_DIST=$(bctoolbox_HEADERS) bctoolbox-0.6.0/include/bctoolbox/crypto.h000066400000000000000000001055231313410701300206160ustar00rootroot00000000000000/* crypto.h Copyright (C) 2016 Belledonne Communications SARL This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef BCTBX_CRYPTO_H #define BCTBX_CRYPTO_H #include /* DHM settings defines */ #define BCTBX_DHM_UNSET 0 #define BCTBX_DHM_2048 1 #define BCTBX_DHM_3072 2 /* SSL settings defines */ #define BCTBX_SSL_UNSET -1 #define BCTBX_SSL_IS_CLIENT 0 #define BCTBX_SSL_IS_SERVER 1 #define BCTBX_SSL_TRANSPORT_STREAM 0 #define BCTBX_SSL_TRANSPORT_DATAGRAM 1 #define BCTBX_SSL_VERIFY_NONE 0 #define BCTBX_SSL_VERIFY_OPTIONAL 1 #define BCTBX_SSL_VERIFY_REQUIRED 2 /* Encryption/decryption defines */ #define BCTBX_GCM_ENCRYPT 1 #define BCTBX_GCM_DECRYPT 0 /* Error codes : All error codes are negative and defined on 32 bits on format -0x7XXXXXXX * in order to be sure to not overlap on crypto librairy (polarssl or mbedtls for now) which are defined on 16 bits 0x[7-0]XXX */ #define BCTBX_ERROR_UNSPECIFIED_ERROR -0x70000000 #define BCTBX_ERROR_OUTPUT_BUFFER_TOO_SMALL -0x70001000 #define BCTBX_ERROR_INVALID_BASE64_INPUT -0x70002000 #define BCTBX_ERROR_INVALID_INPUT_DATA -0x70004000 #define BCTBX_ERROR_UNAVAILABLE_FUNCTION -0x70008000 /* key related */ #define BCTBX_ERROR_UNABLE_TO_PARSE_KEY -0x70010000 /* Certificate related */ #define BCTBX_ERROR_INVALID_CERTIFICATE -0x70020000 #define BCTBX_ERROR_CERTIFICATE_GENERATION_FAIL -0x70020001 #define BCTBX_ERROR_CERTIFICATE_WRITE_PEM -0x70020002 #define BCTBX_ERROR_CERTIFICATE_PARSE_PEM -0x70020004 #define BCTBX_ERROR_UNSUPPORTED_HASH_FUNCTION -0x70020008 /* SSL related */ #define BCTBX_ERROR_INVALID_SSL_CONFIG -0x70030001 #define BCTBX_ERROR_INVALID_SSL_TRANSPORT -0x70030002 #define BCTBX_ERROR_INVALID_SSL_ENDPOINT -0x70030004 #define BCTBX_ERROR_INVALID_SSL_AUTHMODE -0x70030008 #define BCTBX_ERROR_INVALID_SSL_CONTEXT -0x70030010 #define BCTBX_ERROR_NET_WANT_READ -0x70032000 #define BCTBX_ERROR_NET_WANT_WRITE -0x70034000 #define BCTBX_ERROR_SSL_PEER_CLOSE_NOTIFY -0x70038000 #define BCTBX_ERROR_NET_CONN_RESET -0x70030000 /* Symmetric ciphers related */ #define BCTBX_ERROR_AUTHENTICATION_FAILED -0x70040000 /* certificate verification flags codes */ #define BCTBX_CERTIFICATE_VERIFY_ALL_FLAGS 0xFFFFFFFF #define BCTBX_CERTIFICATE_VERIFY_BADCERT_EXPIRED 0x01 /**< The certificate validity has expired. */ #define BCTBX_CERTIFICATE_VERIFY_BADCERT_REVOKED 0x02 /**< The certificate has been revoked (is on a CRL). */ #define BCTBX_CERTIFICATE_VERIFY_BADCERT_CN_MISMATCH 0x04 /**< The certificate Common Name (CN) does not match with the expected CN. */ #define BCTBX_CERTIFICATE_VERIFY_BADCERT_NOT_TRUSTED 0x08 /**< The certificate is not correctly signed by the trusted CA. */ #define BCTBX_CERTIFICATE_VERIFY_BADCERT_MISSING 0x10 /**< Certificate was missing. */ #define BCTBX_CERTIFICATE_VERIFY_BADCERT_SKIP_VERIFY 0x20 /**< Certificate verification was skipped. */ #define BCTBX_CERTIFICATE_VERIFY_BADCERT_OTHER 0x0100 /**< Other reason (can be used by verify callback) */ #define BCTBX_CERTIFICATE_VERIFY_BADCERT_FUTURE 0x0200 /**< The certificate validity starts in the future. */ #define BCTBX_CERTIFICATE_VERIFY_BADCERT_KEY_USAGE 0x0400 /**< Usage does not match the keyUsage extension. */ #define BCTBX_CERTIFICATE_VERIFY_BADCERT_EXT_KEY_USAGE 0x0800 /**< Usage does not match the extendedKeyUsage extension. */ #define BCTBX_CERTIFICATE_VERIFY_BADCERT_NS_CERT_TYPE 0x1000 /**< Usage does not match the nsCertType extension. */ #define BCTBX_CERTIFICATE_VERIFY_BADCERT_BAD_MD 0x2000 /**< The certificate is signed with an unacceptable hash. */ #define BCTBX_CERTIFICATE_VERIFY_BADCERT_BAD_PK 0x4000 /**< The certificate is signed with an unacceptable PK alg (eg RSA vs ECDSA). */ #define BCTBX_CERTIFICATE_VERIFY_BADCERT_BAD_KEY 0x8000 /**< The certificate is signed with an unacceptable key (eg bad curve, RSA too short). */ #define BCTBX_CERTIFICATE_VERIFY_BADCRL_FUTURE 0x10000 /**< The CRL is from the future */ #define BCTBX_CERTIFICATE_VERIFY_BADCRL_NOT_TRUSTED 0x20000 /**< CRL is not correctly signed by the trusted CA. */ #define BCTBX_CERTIFICATE_VERIFY_BADCRL_EXPIRED 0x40000 /**< CRL is expired. */ #define BCTBX_CERTIFICATE_VERIFY_BADCRL_BAD_MD 0x80000 /**< The CRL is signed with an unacceptable hash. */ #define BCTBX_CERTIFICATE_VERIFY_BADCRL_BAD_PK 0x100000 /**< The CRL is signed with an unacceptable PK alg (eg RSA vs ECDSA). */ #define BCTBX_CERTIFICATE_VERIFY_BADCRL_BAD_KEY 0x200000 /**< The CRL is signed with an unacceptable key (eg bad curve, RSA too short). */ /* Hash functions type */ typedef enum bctbx_md_type { BCTBX_MD_UNDEFINED, BCTBX_MD_SHA1, BCTBX_MD_SHA224, BCTBX_MD_SHA256, BCTBX_MD_SHA384, BCTBX_MD_SHA512} bctbx_md_type_t; /* Dtls srtp protection profile */ typedef enum bctbx_srtp_profile { BCTBX_SRTP_UNDEFINED, BCTBX_SRTP_AES128_CM_HMAC_SHA1_80, BCTBX_SRTP_AES128_CM_HMAC_SHA1_32, BCTBX_SRTP_NULL_HMAC_SHA1_80, BCTBX_SRTP_NULL_HMAC_SHA1_32 } bctbx_dtls_srtp_profile_t; #ifdef __cplusplus extern "C"{ #endif /*****************************************************************************/ /****** Utils ******/ /*****************************************************************************/ /** * @brief Return a string translation of an error code * PolarSSL and mbedTLS error codes are on 16 bits always negatives, and these are forwarded to the crypto library error to string translation * Specific bctoolbox error code are on 32 bits, all in the form -0x7XXX XXXX * Output string is truncated if the buffer is too small and always include a null termination char * * @param[in] error_code The error code * @param[in/out] buffer Buffer to place error string representation * @param[in] buffer_length Size of the buffer in bytes. */ BCTBX_PUBLIC void bctbx_strerror(int32_t error_code, char *buffer, size_t buffer_length); /** * @brief Encode a buffer into base64 format * @param[out] output base64 encoded buffer * @param[in/out] output_length output buffer max size and actual size of buffer after encoding * @param[in] input source plain buffer * @param[in] input_length Length in bytes of plain buffer to be encoded * * @return 0 if success or BCTBX_ERROR_OUTPUT_BUFFER_TOO_SMALL if the output buffer cannot contain the encoded data * * @note If the function is called with *output_length=0, set the requested buffer size in output_length */ BCTBX_PUBLIC int32_t bctbx_base64_encode(unsigned char *output, size_t *output_length, const unsigned char *input, size_t input_length); /** * @brief Decode a base64 formatted buffer. * @param[out] output plain buffer * @param[in/out] output_length output buffer max size and actual size of buffer after decoding * @param[in] input source base64 encoded buffer * @param[in] input_length Length in bytes of base64 buffer to be decoded * * @return 0 if success, BCTBX_ERROR_OUTPUT_BUFFER_TOO_SMALL if the output buffer cannot contain the decoded data * or BCTBX_ERROR_INVALID_BASE64_INPUT if encoded buffer was incorrect base64 data * * @note If the function is called with *output_length=0, set the requested buffer size in output_length */ BCTBX_PUBLIC int32_t bctbx_base64_decode(unsigned char *output, size_t *output_length, const unsigned char *input, size_t input_length); /*****************************************************************************/ /****** Random Number Generation ******/ /*****************************************************************************/ /** @brief An opaque structure used to store RNG context * Instanciate pointers only and allocate them using the bctbx_rng_context_new() function */ typedef struct bctbx_rng_context_struct bctbx_rng_context_t; /** * @brief Create and initialise the Random Number Generator context * @return a pointer to the RNG context */ BCTBX_PUBLIC bctbx_rng_context_t *bctbx_rng_context_new(void); /** * @brief Get some random material * * @param[in/out] context The RNG context to be used * @param[out] output A destination buffer for the random material generated * @param[in] output_length Size in bytes of the output buffer and requested random material * * @return 0 on success */ BCTBX_PUBLIC int32_t bctbx_rng_get(bctbx_rng_context_t *context, unsigned char*output, size_t output_length); /** * @brief Clear the RNG context and free internal buffer * * @param[in] context The RNG context to clear */ BCTBX_PUBLIC void bctbx_rng_context_free(bctbx_rng_context_t *context); /*****************************************************************************/ /***** Signing key *****/ /*****************************************************************************/ /** @brief An opaque structure used to store the signing key context * Instanciate pointers only and allocate them using the bctbx_signing_key_new() function */ typedef struct bctbx_signing_key_struct bctbx_signing_key_t; /** * @brief Create and initialise a signing key context * @return a pointer to the signing key context */ BCTBX_PUBLIC bctbx_signing_key_t *bctbx_signing_key_new(void); /** * @brief Clear the signing key context and free internal buffer * * @param[in] key The signing key context to clear */ BCTBX_PUBLIC void bctbx_signing_key_free(bctbx_signing_key_t *key); /** * @brief Write the key in a buffer as a PEM string * * @param[in] key The signing key to be extracted in PEM format * * @return a pointer to a null terminated string containing the key in PEM format. This buffer must then be freed by caller. NULL on failure. */ BCTBX_PUBLIC char *bctbx_signing_key_get_pem(bctbx_signing_key_t *key); /** * @brief Parse signing key in PEM format from a null terminated string buffer * * @param[in/out] key An already initialised signing key context * @param[in] buffer The input buffer containing a PEM format key in a null terminated string * @param[in] buffer_length The length of input buffer, including the NULL termination char * @param[in] password Password for decryption(may be NULL) * @param[in] passzord_length size of password * * @return 0 on success */ BCTBX_PUBLIC int32_t bctbx_signing_key_parse(bctbx_signing_key_t *key, const char *buffer, size_t buffer_length, const unsigned char *password, size_t password_length); /** * @brief Parse signing key from a file * * @param[in/out] key An already initialised signing key context * @param[in] path filename to read the key from * @param[in] password Password for decryption(may be NULL) * * @return 0 on success */ BCTBX_PUBLIC int32_t bctbx_signing_key_parse_file(bctbx_signing_key_t *key, const char *path, const char *password); /*****************************************************************************/ /***** X509 Certificate *****/ /*****************************************************************************/ /** @brief An opaque structure used to store the certificate context * Instanciate pointers only and allocate them using the bctbx_x509_certificate_new() function */ typedef struct bctbx_x509_certificate_struct bctbx_x509_certificate_t; /** * @brief Create and initialise a x509 certificate context * @return a pointer to the certificate context */ BCTBX_PUBLIC bctbx_x509_certificate_t *bctbx_x509_certificate_new(void); /** * @brief Clear the certificate context and free internal buffer * * @param[in] cert The x509 certificate context to clear */ BCTBX_PUBLIC void bctbx_x509_certificate_free(bctbx_x509_certificate_t *cert); /** * @brief Write the certificate in a buffer as a PEM string * * @param[in] cert The certificate to be extracted in PEM format * * @return a pointer to a null terminated string containing the certificate in PEM format. This buffer must then be freed by caller. NULL on failure. */ BCTBX_PUBLIC char *bctbx_x509_certificates_chain_get_pem(bctbx_x509_certificate_t *cert); /** * @brief Return an informational string about the certificate * * @param[out] buf Buffer to receive the output * @param[in] size Maximum output buffer size * @param[in] prefix A line prefix * @param[in] cert The x509 certificate * * @return The length of the string written or a negative error code */ BCTBX_PUBLIC int32_t bctbx_x509_certificate_get_info_string(char *buf, size_t size, const char *prefix, const bctbx_x509_certificate_t *cert); /** * @brief Parse an x509 certificate in PEM format from a null terminated string buffer * * @param[in/out] cert An already initialised x509 certificate context * @param[in] buffer The input buffer containing a PEM format certificate in a null terminated string * @param[in] buffer_length The length of input buffer, including the NULL termination char * * @return 0 on success, negative error code otherwise */ BCTBX_PUBLIC int32_t bctbx_x509_certificate_parse(bctbx_x509_certificate_t *cert, const char *buffer, size_t buffer_length); /** * @brief Load one or more certificates and add them to the chained list * * @param[in/out] cert points to the start of the chain, can be an empty initialised certificate context * @param[in] path filename to read the certificate from * * @return 0 on success, negative error code otherwise */ BCTBX_PUBLIC int32_t bctbx_x509_certificate_parse_file(bctbx_x509_certificate_t *cert, const char *path); /** * @brief Load one or more certificates files from a path and add them to the chained list * * @param[in/out] cert points to the start of the chain, can be an empty initialised certificate context * @param[in] path directory to read certicates files from * * @return 0 on success, negative error code otherwise */ BCTBX_PUBLIC int32_t bctbx_x509_certificate_parse_path(bctbx_x509_certificate_t *cert, const char *path); /** * @brief Get the length in bytes of a certifcate chain in DER format * * @param[in] cert The certificate chain * * @return The length in bytes of the certificate buffer in DER format, 0 if no certificate found */ BCTBX_PUBLIC int32_t bctbx_x509_certificate_get_der_length(bctbx_x509_certificate_t *cert); /** * @brief Get the certificate in DER format in a null terminated string * * @param[in] cert The certificate chain * @param[in/out] buffer The buffer to hold the certificate * @param[in] buffer_length Maximum output buffer size * * @return 0 on success, negative error code otherwise */ BCTBX_PUBLIC int32_t bctbx_x509_certificate_get_der(bctbx_x509_certificate_t *cert, unsigned char *buffer, size_t buffer_length); /** * @brief Store the certificate subject DN in printable form into buf * * @param[in] cert The x509 certificate * @param[in/out] dn A buffer to store the DN string * @param[in] dn_length Maximum size to be written in buffer * * @return The length of the string written (not including the terminated nul byte), or a negative error code */ BCTBX_PUBLIC int32_t bctbx_x509_certificate_get_subject_dn(bctbx_x509_certificate_t *cert, char *dn, size_t dn_length); /** * @brief Generate certificate fingerprint (hash of the DER format certificate) hexadecimal format in a null terminated string * * @param[in] cert The x509 certificate * @param[in/out] fingerprint The buffer to hold the fingerprint(null terminated string in hexadecimal) * @param[in] fingerprint_length Maximum length of the fingerprint buffer * @param[in] hash_algorithm set to BCTBX_MD_UNDEFINED to use the hash used in certificate signature(recommended) * or specify an other hash algorithm(BCTBX_MD_SHA1, BCTBX_MD_SHA224, BCTBX_MD_SHA256, BCTBX_MD_SHA384, BCTBX_MD_SHA512) * @return length of written on success, negative error code otherwise */ BCTBX_PUBLIC int32_t bctbx_x509_certificate_get_fingerprint(const bctbx_x509_certificate_t *cert, char *fingerprint, size_t fingerprint_length, bctbx_md_type_t hash_algorithm); /** * @brief Retrieve the certificate signature hash function * * @param[in] cert The x509 certificate * @param[out] hash_algorithm The hash algorithm used for the certificate signature or BCTBX_MD_UNDEFINED if unable to retrieve it * * @return 0 on success, negative error code otherwise */ BCTBX_PUBLIC int32_t bctbx_x509_certificate_get_signature_hash_function(const bctbx_x509_certificate_t *certificate, bctbx_md_type_t *hash_algorithm); /** * @brief Generate a self-signed certificate using RSA 3072 bits signature algorithm * * @param[in] subject The certificate subject * @param[in/out] certificate An empty intialised certificate pointer to hold the generated certificate * @param[in/out] pkey An empty initialised signing key pointer to hold the key generated and used to sign the certificate (RSA 3072 bits) * @param[out] pem If not null, a buffer to hold a PEM string of the certificate and key * @param[in] pem_length pem buffer length * * @return 0 on success, negative error code otherwise */ BCTBX_PUBLIC int32_t bctbx_x509_certificate_generate_selfsigned(const char *subject, bctbx_x509_certificate_t *certificate, bctbx_signing_key_t *pkey, char *pem, size_t pem_length); /** * @brief Convert underlying crypto library certificate flags into a printable string * * @param[out] buffer a buffer to hold the output string * @param[in] buffer_size maximum buffer size * @param[in] flags The flags from the underlying crypto library, provided in callback functions * * @return 0 on success, negative error code otherwise */ BCTBX_PUBLIC int32_t bctbx_x509_certificate_flags_to_string(char *buffer, size_t buffer_size, uint32_t flags); /** * @brief Set a certificate flags (using underlying crypto library defines) * * @param[in/out] flags The certificate flags holder directly provided by crypto library in a callback function * @param[in] flags_to_set Flags to be set, bctoolbox defines * * @return 0 on success, negative error code otherwise */ BCTBX_PUBLIC int32_t bctbx_x509_certificate_set_flag(uint32_t *flags, uint32_t flags_to_set); /** * @brief convert certificate flags from underlying crypto library defines to bctoolbox ones * * @param[in] flags certificate flags provided by the crypto library in a callback function * * @return same flag but using the bctoolbox API definitions */ BCTBX_PUBLIC uint32_t bctbx_x509_certificate_remap_flag(uint32_t flags); /** * @brief Unset a certificate flags (using underlying crypto library defines) * * @param[in/out] flags The certificate flags holder directly provided by crypto library in a callback function * @param[in] flags_to_set Flags to be unset, bctoolbox defines * * @return 0 on success, negative error code otherwise */ BCTBX_PUBLIC int32_t bctbx_x509_certificate_unset_flag(uint32_t *flags, uint32_t flags_to_unset); /*****************************************************************************/ /***** SSL *****/ /*****************************************************************************/ typedef struct bctbx_ssl_context_struct bctbx_ssl_context_t; typedef struct bctbx_ssl_config_struct bctbx_ssl_config_t; BCTBX_PUBLIC bctbx_ssl_context_t *bctbx_ssl_context_new(void); BCTBX_PUBLIC void bctbx_ssl_context_free(bctbx_ssl_context_t *ssl_ctx); BCTBX_PUBLIC int32_t bctbx_ssl_context_setup(bctbx_ssl_context_t *ssl_ctx, bctbx_ssl_config_t *ssl_config); BCTBX_PUBLIC int32_t bctbx_ssl_close_notify(bctbx_ssl_context_t *ssl_ctx); BCTBX_PUBLIC int32_t bctbx_ssl_session_reset(bctbx_ssl_context_t *ssl_ctx); BCTBX_PUBLIC int32_t bctbx_ssl_read(bctbx_ssl_context_t *ssl_ctx, unsigned char *buf, size_t buf_length); BCTBX_PUBLIC int32_t bctbx_ssl_write(bctbx_ssl_context_t *ssl_ctx, const unsigned char *buf, size_t buf_length); BCTBX_PUBLIC int32_t bctbx_ssl_set_hostname(bctbx_ssl_context_t *ssl_ctx, const char *hostname); BCTBX_PUBLIC int32_t bctbx_ssl_handshake(bctbx_ssl_context_t *ssl_ctx); BCTBX_PUBLIC int32_t bctbx_ssl_set_hs_own_cert(bctbx_ssl_context_t *ssl_ctx, bctbx_x509_certificate_t *cert, bctbx_signing_key_t *key); BCTBX_PUBLIC void bctbx_ssl_set_io_callbacks(bctbx_ssl_context_t *ssl_ctx, void *callback_data, int(*callback_send_function)(void *, const unsigned char *, size_t), /* callbacks args are: callback data, data buffer to be send, size of data buffer */ int(*callback_recv_function)(void *, unsigned char *, size_t)); /* args: callback data, data buffer to be read, size of data buffer */ BCTBX_PUBLIC const bctbx_x509_certificate_t *bctbx_ssl_get_peer_certificate(bctbx_ssl_context_t *ssl_ctx); BCTBX_PUBLIC const char *bctbx_ssl_get_ciphersuite(bctbx_ssl_context_t *ssl_ctx); BCTBX_PUBLIC const char *bctbx_ssl_get_version(bctbx_ssl_context_t *ssl_ctx); BCTBX_PUBLIC bctbx_ssl_config_t *bctbx_ssl_config_new(void); BCTBX_PUBLIC int32_t bctbx_ssl_config_set_crypto_library_config(bctbx_ssl_config_t *ssl_config, void *internal_config); BCTBX_PUBLIC void bctbx_ssl_config_free(bctbx_ssl_config_t *ssl_config); BCTBX_PUBLIC int32_t bctbx_ssl_config_defaults(bctbx_ssl_config_t *ssl_config, int endpoint, int transport); BCTBX_PUBLIC int32_t bctbx_ssl_config_set_endpoint(bctbx_ssl_config_t *ssl_config, int endpoint); BCTBX_PUBLIC int32_t bctbx_ssl_config_set_transport (bctbx_ssl_config_t *ssl_config, int transport); BCTBX_PUBLIC int32_t bctbx_ssl_config_set_authmode(bctbx_ssl_config_t *ssl_config, int authmode); BCTBX_PUBLIC int32_t bctbx_ssl_config_set_rng(bctbx_ssl_config_t *ssl_config, int(*rng_function)(void *, unsigned char *, size_t), void *rng_context); BCTBX_PUBLIC int32_t bctbx_ssl_config_set_callback_verify(bctbx_ssl_config_t *ssl_config, int(*callback_function)(void *, bctbx_x509_certificate_t *, int, uint32_t *), void *callback_data); BCTBX_PUBLIC int32_t bctbx_ssl_config_set_callback_cli_cert(bctbx_ssl_config_t *ssl_config, int(*callback_function)(void *, bctbx_ssl_context_t *, unsigned char *, size_t), void *callback_data); BCTBX_PUBLIC int32_t bctbx_ssl_config_set_ca_chain(bctbx_ssl_config_t *ssl_config, bctbx_x509_certificate_t *ca_chain); BCTBX_PUBLIC int32_t bctbx_ssl_config_set_own_cert(bctbx_ssl_config_t *ssl_config, bctbx_x509_certificate_t *cert, bctbx_signing_key_t *key); /***** DTLS-SRTP functions *****/ BCTBX_PUBLIC bctbx_dtls_srtp_profile_t bctbx_ssl_get_dtls_srtp_protection_profile(bctbx_ssl_context_t *ssl_ctx); BCTBX_PUBLIC int32_t bctbx_ssl_config_set_dtls_srtp_protection_profiles(bctbx_ssl_config_t *ssl_config, const bctbx_dtls_srtp_profile_t *profiles, size_t profiles_number); BCTBX_PUBLIC int32_t bctbx_ssl_get_dtls_srtp_key_material(bctbx_ssl_context_t *ssl_ctx, char *output, size_t *output_length); BCTBX_PUBLIC uint8_t bctbx_dtls_srtp_supported(void); /*****************************************************************************/ /***** Diffie-Hellman-Merkle key exchange *****/ /*****************************************************************************/ /** * @brief Context for the Diffie-Hellman-Merkle key exchange * Use RFC3526 values for G and P */ typedef struct bctbx_DHMContext_struct { uint8_t algo; /**< Algorithm used for the key exchange mapped to an int: BCTBX_DHM_2048, BCTBX_DHM_3072 */ 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 */ 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 */ }bctbx_DHMContext_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(BCTBX_DHM_2048 or BCTBX_DHM_3072) * @param[in] secretLength The length in byte of the random secret(X). * * @return The initialised context for the DHM calculation(must then be freed calling the destroyDHMContext function), NULL on error * */ BCTBX_PUBLIC bctbx_DHMContext_t *bctbx_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 * */ BCTBX_PUBLIC void bctbx_DHMCreatePublic(bctbx_DHMContext_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 * */ BCTBX_PUBLIC void bctbx_DHMComputeSecret(bctbx_DHMContext_t *context, int (*rngFunction)(void *, uint8_t *, size_t), void *rngContext); /** * * @brief Clean DHM context. Secret and key, if present, are erased from memory(set to 0) * * @param context The context to deallocate * */ BCTBX_PUBLIC void bctbx_DestroyDHMContext(bctbx_DHMContext_t *context); /*****************************************************************************/ /***** Hashing *****/ /*****************************************************************************/ /** * @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. * */ BCTBX_PUBLIC void bctbx_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. * */ BCTBX_PUBLIC void bctbx_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. 20 bytes maximum * @param[out] output Output data buffer * */ BCTBX_PUBLIC void bctbx_hmacSha1(const uint8_t *key, size_t keyLength, const uint8_t *input, size_t inputLength, uint8_t hmacLength, uint8_t *output); /** * @brief MD5 wrapper * output = md5(input) * @param[in] input Input data buffer * @param[in] inputLength Input data length in bytes * @param[out] output Output data buffer. * */ BCTBX_PUBLIC void bctbx_md5(const uint8_t *input, size_t inputLength, uint8_t output[16]); /*****************************************************************************/ /***** Encryption/Decryption *****/ /*****************************************************************************/ typedef struct bctbx_aes_gcm_context_struct bctbx_aes_gcm_context_t; /** * @Brief AES-GCM encrypt and tag buffer * * @param[in] key Encryption key * @param[in] keyLength Key buffer length, in bytes, must be 16,24 or 32 * @param[in] plainText buffer to be encrypted * @param[in] plainTextLength Length in bytes of buffer to be encrypted * @param[in] authenticatedData Buffer holding additional data to be used in tag computation * @param[in] authenticatedDataLength Additional data length in bytes * @param[in] initializationVector Buffer holding the initialisation vector * @param[in] initializationVectorLength Initialisation vector length in bytes * @param[out] tag Buffer holding the generated tag * @param[in] tagLength Requested length for the generated tag * @param[out] output Buffer holding the output, shall be at least the length of plainText buffer * * @return 0 on success, crypto library error code otherwise */ BCTBX_PUBLIC int32_t bctbx_aes_gcm_encrypt_and_tag(const uint8_t *key, size_t keyLength, const uint8_t *plainText, size_t plainTextLength, const uint8_t *authenticatedData, size_t authenticatedDataLength, const uint8_t *initializationVector, size_t initializationVectorLength, uint8_t *tag, size_t tagLength, uint8_t *output); /** * @Brief AES-GCM decrypt, compute authentication tag and compare it to the one provided * * @param[in] key Encryption key * @param[in] keyLength Key buffer length, in bytes, must be 16,24 or 32 * @param[in] cipherText Buffer to be decrypted * @param[in] cipherTextLength Length in bytes of buffer to be decrypted * @param[in] authenticatedData Buffer holding additional data to be used in auth tag computation * @param[in] authenticatedDataLength Additional data length in bytes * @param[in] initializationVector Buffer holding the initialisation vector * @param[in] initializationVectorLength Initialisation vector length in bytes * @param[in] tag Buffer holding the authentication tag * @param[in] tagLength Length in bytes for the authentication tag * @param[out] output Buffer holding the output, shall be at least the length of cipherText buffer * * @return 0 on succes, BCTBX_ERROR_AUTHENTICATION_FAILED if tag doesn't match or crypto library error code */ BCTBX_PUBLIC int32_t bctbx_aes_gcm_decrypt_and_auth(const uint8_t *key, size_t keyLength, const uint8_t *cipherText, size_t cipherTextLength, const uint8_t *authenticatedData, size_t authenticatedDataLength, const uint8_t *initializationVector, size_t initializationVectorLength, const uint8_t *tag, size_t tagLength, uint8_t *output); /** * @Brief create and initialise an AES-GCM encryption context * * @param[in] key encryption key * @param[in] keyLength key buffer length, in bytes, must be 16,24 or 32 * @param[in] authenticatedData Buffer holding additional data to be used in tag computation * @param[in] authenticatedDataLength additional data length in bytes * @param[in] initializationVector Buffer holding the initialisation vector * @param[in] initializationVectorLength Initialisation vector length in bytes * @param[in] mode Operation mode : BCTBX_GCM_ENCRYPT or BCTBX_GCM_DECRYPT * * @return a pointer to the created context, to be freed using bctbx_aes_gcm_finish() */ BCTBX_PUBLIC bctbx_aes_gcm_context_t *bctbx_aes_gcm_context_new(const uint8_t *key, size_t keyLength, const uint8_t *authenticatedData, size_t authenticatedDataLength, const uint8_t *initializationVector, size_t initializationVectorLength, uint8_t mode); /** * @Brief AES-GCM encrypt or decrypt a chunk of data * * @param[in/out] context a context already initialized using bctbx_aes_gcm_context_new * @param[in] input buffer holding the input data * @param[in] inputLength lenght of the input data * @param[out] output buffer to store the output data (same length as input one) * * @return 0 on success, crypto library error code otherwise */ BCTBX_PUBLIC int32_t bctbx_aes_gcm_process_chunk(bctbx_aes_gcm_context_t *context, const uint8_t *input, size_t inputLength, uint8_t *output); /** * @Brief Conclude a AES-GCM encryption stream, generate tag if requested, free resources * * @param[in/out] context a context already initialized using bctbx_aes_gcm_context_new * @param[out] tag a buffer to hold the authentication tag. Can be NULL if tagLength is 0 * @param[in] tagLength length of reqested authentication tag, max 16 * * @return 0 on success, crypto library error code otherwise */ BCTBX_PUBLIC int32_t bctbx_aes_gcm_finish(bctbx_aes_gcm_context_t *context, uint8_t *tag, size_t tagLength); /** * @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 * */ BCTBX_PUBLIC void bctbx_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 * */ BCTBX_PUBLIC void bctbx_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 * */ BCTBX_PUBLIC void bctbx_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 * */ BCTBX_PUBLIC void bctbx_aes256CfbDecrypt(const uint8_t *key, const uint8_t *IV, const uint8_t *input, size_t inputLength, uint8_t *output); #ifdef __cplusplus } #endif #endif /* BCTBX_CRYPTO_H */ bctoolbox-0.6.0/include/bctoolbox/defs.h000066400000000000000000000021271313410701300202130ustar00rootroot00000000000000/* defs.h Copyright (C) 2010-2017 Belledonne Communications SARL This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef BCTBX_DEFS_H_ #define BCTBX_DEFS_H_ /* Macro telling GCC that a 'break' statement has been deliberately omitted * in switch block */ #ifndef BCTBX_NO_BREAK #if defined(__GNUC__) && __GNUC__ >= 7 #define BCTBX_NO_BREAK __attribute__((fallthrough)) #else #define BCTBX_NO_BREAK #endif // __GNUC__ #endif // BCTBX_NO_BREAK #endif /* BCTBX_DEFS_H_ */ bctoolbox-0.6.0/include/bctoolbox/exception.hh000066400000000000000000000041241313410701300214370ustar00rootroot00000000000000/* bctoolbox Copyright (C) 2016 Belledonne Communications SARL. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifndef exception_h #define exception_h #include #include #include #include #include /** * @brief General pupose exception saving backtrace. * * sample of use: * try { * throw BCTBX_EXCEPTION << "Hello, this is my exception"; * } catch (BctbxException e&) { * BCTOOLBOX_SLOGD("mylogdomain") << "Exception cauth"<< e; * } * * */ class BctbxException : public std::exception { public: BctbxException(); BctbxException(const std::string &message); BctbxException(const char *message); virtual ~BctbxException() throw(); BctbxException(const BctbxException &other); /** * print stack strace to stderr * */ void printStackTrace() const; void printStackTrace(std::ostream &os) const; const char *what() const throw(); const std::string &str() const; /* same as osstringstream, but as osstream does not have cp contructor, BctbxException can't inherit from * osstream*/ template BctbxException &operator<<(const T2 &val) { mOs << val; return *this; } protected: int mOffset; /*to hide last stack traces*/ private: void *mArray[20]; size_t mSize; std::ostringstream mOs; mutable std::string mMessage; }; std::ostream &operator<<(std::ostream &__os, const BctbxException &e); #define BCTBX_EXCEPTION BctbxException() << " " << __FILE__ << ":" << __LINE__ << " " #endif /* exception_h */ bctoolbox-0.6.0/include/bctoolbox/list.h000066400000000000000000000106771313410701300202560ustar00rootroot00000000000000/* bctoolbox Copyright (C) 2016 Belledonne Communications SARL 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, see . */ #ifndef BCTBX_LIST_H_ #define BCTBX_LIST_H_ #include "bctoolbox/port.h" #ifdef __cplusplus extern "C"{ #endif typedef struct _bctbx_list { struct _bctbx_list *next; struct _bctbx_list *prev; void *data; } bctbx_list_t; typedef int (*bctbx_compare_func)(const void *, const void*); typedef void (*bctbx_list_iterate_func)(void *); typedef void (*bctbx_list_iterate2_func)(void *, void *); typedef void (*bctbx_list_free_func)(void *); typedef void* (*bctbx_list_copy_func)(void *); BCTBX_PUBLIC bctbx_list_t * bctbx_list_new(void *data); BCTBX_PUBLIC bctbx_list_t * bctbx_list_append(bctbx_list_t * elem, void * data); BCTBX_PUBLIC bctbx_list_t * bctbx_list_append_link(bctbx_list_t * elem, bctbx_list_t *new_elem); BCTBX_PUBLIC bctbx_list_t * bctbx_list_prepend(bctbx_list_t * elem, void * data); BCTBX_PUBLIC bctbx_list_t * bctbx_list_prepend_link(bctbx_list_t* elem, bctbx_list_t *new_elem); BCTBX_PUBLIC bctbx_list_t * bctbx_list_last_elem(const bctbx_list_t *l); BCTBX_PUBLIC bctbx_list_t * bctbx_list_first_elem(const bctbx_list_t *l); BCTBX_PUBLIC bctbx_list_t * bctbx_list_free(bctbx_list_t * elem); BCTBX_PUBLIC bctbx_list_t * bctbx_list_concat(bctbx_list_t * first, bctbx_list_t * second); BCTBX_PUBLIC bctbx_list_t * bctbx_list_remove(bctbx_list_t * first, void *data); BCTBX_PUBLIC bctbx_list_t * bctbx_list_remove_custom(bctbx_list_t *first, bctbx_compare_func compare_func, const void *user_data); BCTBX_PUBLIC bctbx_list_t * bctbx_list_pop_front(bctbx_list_t *list, void **front_data); BCTBX_PUBLIC size_t bctbx_list_size(const bctbx_list_t * first); BCTBX_PUBLIC void bctbx_list_for_each(const bctbx_list_t * list, bctbx_list_iterate_func func); BCTBX_PUBLIC void bctbx_list_for_each2(const bctbx_list_t * list, bctbx_list_iterate2_func func, void *user_data); /** * Removes the element pointed by elem from the list. The element itself is not freed, allowing * to be chained in another list for example. * Use bctbx_list_erase_link() if you simply want to delete an element of a list. **/ BCTBX_PUBLIC bctbx_list_t * bctbx_list_unlink(bctbx_list_t * list, bctbx_list_t * elem); /** * Delete the element pointed by 'elem' from the list. **/ BCTBX_PUBLIC bctbx_list_t * bctbx_list_erase_link(bctbx_list_t * list, bctbx_list_t * elem); BCTBX_PUBLIC bctbx_list_t * bctbx_list_find(bctbx_list_t *list, const void *data); BCTBX_PUBLIC bctbx_list_t * bctbx_list_free(bctbx_list_t *list); /*frees list elements and associated data, using the supplied function pointer*/ BCTBX_PUBLIC bctbx_list_t * bctbx_list_free_with_data(bctbx_list_t *list, bctbx_list_free_func freefunc); BCTBX_PUBLIC bctbx_list_t * bctbx_list_find_custom(const bctbx_list_t * list, bctbx_compare_func cmp, const void *user_data); BCTBX_PUBLIC void * bctbx_list_nth_data(const bctbx_list_t * list, int index); BCTBX_PUBLIC int bctbx_list_position(const bctbx_list_t * list, bctbx_list_t * elem); BCTBX_PUBLIC int bctbx_list_index(const bctbx_list_t * list, void *data); BCTBX_PUBLIC bctbx_list_t * bctbx_list_insert_sorted(bctbx_list_t * list, void *data, bctbx_compare_func cmp); BCTBX_PUBLIC bctbx_list_t * bctbx_list_insert(bctbx_list_t * list, bctbx_list_t * before, void *data); BCTBX_PUBLIC bctbx_list_t * bctbx_list_copy(const bctbx_list_t * list); /*copy list elements and associated data, using the supplied function pointer*/ BCTBX_PUBLIC bctbx_list_t* bctbx_list_copy_with_data(const bctbx_list_t* list, bctbx_list_copy_func copyfunc); /*Same as bctbx_list_copy_with_data but in reverse order*/ BCTBX_PUBLIC bctbx_list_t* bctbx_list_copy_reverse_with_data(const bctbx_list_t* list, bctbx_list_copy_func copyfunc); BCTBX_PUBLIC bctbx_list_t* bctbx_list_next(const bctbx_list_t *elem); BCTBX_PUBLIC void* bctbx_list_get_data(const bctbx_list_t *elem); #ifdef __cplusplus } #endif #endif /* BCTLBX_LIST_H_ */ bctoolbox-0.6.0/include/bctoolbox/logging.h000066400000000000000000000214011313410701300207140ustar00rootroot00000000000000/* bctoolobx Copyright (C) 2016 Belledonne Communications, France, Grenoble This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /** * \file logging.h * \brief Logging API. * **/ #ifndef BCTBX_LOGGING_H #define BCTBX_LOGGING_H #include #include "bctoolbox/list.h" #ifndef BCTBX_LOG_DOMAIN #define BCTBX_LOG_DOMAIN NULL #endif #ifdef __cplusplus extern "C" { #endif typedef enum { BCTBX_LOG_DEBUG=1, BCTBX_LOG_TRACE=1<<1, BCTBX_LOG_MESSAGE=1<<2, BCTBX_LOG_WARNING=1<<3, BCTBX_LOG_ERROR=1<<4, BCTBX_LOG_FATAL=1<<5, BCTBX_LOG_LOGLEV_END=1<<6 } BctbxLogLevel; typedef struct _bctbx_log_handler_t bctbx_log_handler_t; typedef void (*BctbxLogFunc)(const char *domain, BctbxLogLevel lev, const char *fmt, va_list args); typedef void (*BctbxLogHandlerFunc)(void *info,const char *domain, BctbxLogLevel lev, const char *fmt, va_list args); typedef void (*BctbxLogHandlerDestroyFunc)(bctbx_log_handler_t *handler); /* initialise logging functions, add default log handler for stdout output. @param[in] bool_t create : whether or not the initialisation should create a default logger in stdout or not. */ BCTBX_PUBLIC void bctbx_init_logger(bool_t create); /* free logging memory */ BCTBX_PUBLIC void bctbx_uninit_logger(void); /* Default functions to free log handlers @param[in] bctbx_log_handler_t* handler : the handler to free */ BCTBX_PUBLIC void bctbx_logv_out_destroy(bctbx_log_handler_t *handler); BCTBX_PUBLIC void bctbx_logv_file_destroy(bctbx_log_handler_t *handler); /* Function to create a log handler @param[in] BctbxLogHandlerFunc func : the function to call to handle a new line of log @param[in] BctbxLogHandlerDestroyFunc destroy : the function to call to free this handler particuler its user_info field @param[in] void* user_info : complementary information to handle the logs if needed @return a new bctbx_log_handler_t */ BCTBX_PUBLIC bctbx_log_handler_t* bctbx_create_log_handler(BctbxLogHandlerFunc func, BctbxLogHandlerDestroyFunc destroy, void* user_info); /* Function to create a file log handler @param[in] uint64_t max_size : the maximum size of the log file before rotating to a new one (if 0 then no rotation) @param[in] const char* path : the path where to put the log files @param[in] const char* name : the name of the log files @param[in] FILE* f : the file where to write the logs @return a new bctbx_log_handler_t */ BCTBX_PUBLIC bctbx_log_handler_t* bctbx_create_file_log_handler(uint64_t max_size, const char* path, const char* name, FILE* f); BCTBX_PUBLIC void bctbx_add_log_handler(bctbx_log_handler_t* handler); BCTBX_PUBLIC BCTBX_DEPRECATED void bctbx_set_log_handler(BctbxLogFunc func); BCTBX_PUBLIC BCTBX_DEPRECATED void bctbx_set_log_file(FILE* f); BCTBX_PUBLIC bctbx_list_t* bctbx_get_log_handlers(void); BCTBX_PUBLIC void bctbx_logv_out(void* user_info, const char *domain, BctbxLogLevel level, const char *fmt, va_list args); BCTBX_PUBLIC void bctbx_logv_file(void* user_info, const char *domain, BctbxLogLevel level, const char *fmt, va_list args); #define bctbx_log_level_enabled(domain, level) (bctbx_get_log_level_mask(domain) & (level)) BCTBX_PUBLIC void bctbx_logv(const char *domain, BctbxLogLevel level, const char *fmt, va_list args); /** * Flushes the log output queue. * WARNING: Must be called from the thread that has been defined with bctbx_set_log_thread_id(). */ BCTBX_PUBLIC void bctbx_logv_flush(void); /** * Activate all log level greater or equal than specified level argument. **/ BCTBX_PUBLIC void bctbx_set_log_level(const char *domain, BctbxLogLevel level); BCTBX_PUBLIC void bctbx_set_log_level_mask(const char *domain, int levelmask); BCTBX_PUBLIC unsigned int bctbx_get_log_level_mask(const char *domain); /** * Tell oRTP the id of the thread used to output the logs. * This is meant to output all the logs from the same thread to prevent deadlock problems at the application level. * @param[in] thread_id The id of the thread that will output the logs (can be obtained using bctbx_thread_self()). */ BCTBX_PUBLIC void bctbx_set_log_thread_id(unsigned long thread_id); #ifdef __GNUC__ #define CHECK_FORMAT_ARGS(m,n) __attribute__((format(printf,m,n))) #else #define CHECK_FORMAT_ARGS(m,n) #endif #ifdef __clang__ /*in case of compile with -g static inline can produce this type of warning*/ #pragma GCC diagnostic ignored "-Wunused-function" #endif #ifdef BCTBX_DEBUG_MODE static BCTBX_INLINE void CHECK_FORMAT_ARGS(1,2) bctbx_debug(const char *fmt,...) { va_list args; va_start (args, fmt); bctbx_logv(BCTBX_LOG_DOMAIN, BCTBX_LOG_DEBUG, fmt, args); va_end (args); } #else #define bctbx_debug(...) #endif #ifdef BCTBX_NOMESSAGE_MODE #define bctbx_log(...) #define bctbx_message(...) #define bctbx_warning(...) #else static BCTBX_INLINE void bctbx_log(const char* domain, BctbxLogLevel lev, const char *fmt,...) { va_list args; va_start (args, fmt); bctbx_logv(domain, lev, fmt, args); va_end (args); } static BCTBX_INLINE void CHECK_FORMAT_ARGS(1,2) bctbx_message(const char *fmt,...) { va_list args; va_start (args, fmt); bctbx_logv(BCTBX_LOG_DOMAIN, BCTBX_LOG_MESSAGE, fmt, args); va_end (args); } static BCTBX_INLINE void CHECK_FORMAT_ARGS(1,2) bctbx_warning(const char *fmt,...) { va_list args; va_start (args, fmt); bctbx_logv(BCTBX_LOG_DOMAIN, BCTBX_LOG_WARNING, fmt, args); va_end (args); } #endif static BCTBX_INLINE void CHECK_FORMAT_ARGS(1,2) bctbx_error(const char *fmt,...) { va_list args; va_start (args, fmt); bctbx_logv(BCTBX_LOG_DOMAIN, BCTBX_LOG_ERROR, fmt, args); va_end (args); } static BCTBX_INLINE void CHECK_FORMAT_ARGS(1,2) bctbx_fatal(const char *fmt,...) { va_list args; va_start (args, fmt); bctbx_logv(BCTBX_LOG_DOMAIN, BCTBX_LOG_FATAL, fmt, args); va_end (args); } #ifdef __QNX__ void bctbx_qnx_log_handler(const char *domain, BctbxLogLevel lev, const char *fmt, va_list args); #endif #ifdef __cplusplus } #include #include #include #if !defined(_WIN32) && !defined(__QNX__) #include #endif namespace bctoolbox { namespace log { // Here we define our application severity levels. enum level { normal, trace, debug, info, warning, error, fatal }; // The formatting logic for the severity level template inline std::basic_ostream &operator<<(std::basic_ostream &strm, const bctoolbox::log::level &lvl) { static const char *const str[] = {"normal", "trace", "debug", "info", "warning", "error", "fatal"}; if (static_cast(lvl) < (sizeof(str) / sizeof(*str))) strm << str[lvl]; else strm << static_cast(lvl); return strm; } template inline std::basic_istream &operator>>(std::basic_istream &strm, bctoolbox::log::level &lvl) { static const char *const str[] = {"normal", "trace", "debug", "info", "warning", "error", "fatal"}; std::string s; strm >> s; for (unsigned int n = 0; n < (sizeof(str) / sizeof(*str)); ++n) { if (s == str[n]) { lvl = static_cast(n); return strm; } } // Parse error strm.setstate(std::ios_base::failbit); return strm; } } } #include struct pumpstream : public std::ostringstream { const std::string mDomain; const BctbxLogLevel level; pumpstream(const std::string &domain, BctbxLogLevel l) : mDomain(domain), level(l) {} ~pumpstream() { bctbx_log(mDomain.empty()?NULL:mDomain.c_str(), level, "%s", str().c_str()); } }; #if (__GNUC__ == 4 && __GNUC_MINOR__ < 5 && __cplusplus > 199711L) template inline pumpstream &operator<<(pumpstream &&__os, const _Tp &__x) { (static_cast(__os)) << __x; return __os; } #endif #define BCTBX_SLOG(domain, thelevel) \ \ if (bctbx_log_level_enabled((domain), (thelevel))) \ pumpstream((domain != NULL ? domain : ""), (thelevel)) #define BCTBX_SLOGD(DOMAIN) BCTBX_SLOG(DOMAIN, BCTBX_LOG_DEBUG) #define BCTBX_SLOGI(DOMAIN) BCTBX_SLOG((DOMAIN), (BCTBX_LOG_MESSAGE)) #define BCTBX_SLOGW(DOMAIN) BCTBX_SLOG(DOMAIN, BCTBX_LOG_WARNING) #define BCTBX_SLOGE(DOMAIN) BCTBX_SLOG(DOMAIN, BCTBX_LOG_ERROR) #endif #endif bctoolbox-0.6.0/include/bctoolbox/map.h000066400000000000000000000137641313410701300200600ustar00rootroot00000000000000/* bctoolbox mmap Copyright (C) 2016 Belledonne Communications SARL 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, see . */ #ifndef BCTBX_MMAP_H_ #define BCTBX_MMAP_H_ #include "bctoolbox/list.h" #include "bctoolbox/port.h" #ifdef __cplusplus extern "C"{ #endif typedef struct _bctbx_map_t bctbx_map_t; typedef struct _bctbx_pair_t bctbx_pair_t; typedef struct _bctbx_iterator_t bctbx_iterator_t; typedef struct _bctbx_mmap_ullong_t bctbx_mmap_ullong_t; typedef struct _bctbx_mmap_cchar_t bctbx_mmap_cchar_t; typedef void (*bctbx_map_free_func)(void *); /*map*/ BCTBX_PUBLIC bctbx_map_t *bctbx_mmap_ullong_new(void); BCTBX_PUBLIC bctbx_map_t *bctbx_mmap_cchar_new(void); BCTBX_PUBLIC void bctbx_mmap_ullong_delete(bctbx_map_t *mmap); BCTBX_PUBLIC void bctbx_mmap_cchar_delete(bctbx_map_t *mmap); BCTBX_PUBLIC void bctbx_mmap_ullong_delete_with_data(bctbx_map_t *mmap, bctbx_map_free_func freefunc); BCTBX_PUBLIC void bctbx_mmap_cchar_delete_with_data(bctbx_map_t *mmap, bctbx_map_free_func freefunc); #define bctbx_map_insert bctbx_map_ullong_insert BCTBX_PUBLIC void bctbx_map_ullong_insert(bctbx_map_t *map,const bctbx_pair_t *pair); BCTBX_PUBLIC void bctbx_map_cchar_insert(bctbx_map_t *map,const bctbx_pair_t *pair); /*same as insert, but also deleting pair*/ #define bctbx_map_insert_and_delete bctbx_map_ullong_insert_and_delete BCTBX_PUBLIC void bctbx_map_ullong_insert_and_delete(bctbx_map_t *map,bctbx_pair_t *pair); BCTBX_PUBLIC void bctbx_map_cchar_insert_and_delete(bctbx_map_t *map,bctbx_pair_t *pair); /*same as insert and deleting pair with a newly allocated it returned */ #define bctbx_map_insert_and_delete_with_returned_it bctbx_map_ullong_insert_and_delete_with_returned_it BCTBX_PUBLIC bctbx_iterator_t * bctbx_map_ullong_insert_and_delete_with_returned_it(bctbx_map_t *map,bctbx_pair_t *pair); BCTBX_PUBLIC bctbx_iterator_t * bctbx_map_cchar_insert_and_delete_with_returned_it(bctbx_map_t *map,bctbx_pair_t *pair); /*at return, it point to the next element*/ #define bctbx_map_erase bctbx_map_ullong_erase BCTBX_PUBLIC bctbx_iterator_t *bctbx_map_ullong_erase(bctbx_map_t *map,bctbx_iterator_t *it); BCTBX_PUBLIC bctbx_iterator_t *bctbx_map_cchar_erase(bctbx_map_t *map,bctbx_iterator_t *it); /*return a new allocated iterator*/ #define bctbx_map_begin bctbx_map_ullong_begin BCTBX_PUBLIC bctbx_iterator_t *bctbx_map_ullong_begin(const bctbx_map_t *map); BCTBX_PUBLIC bctbx_iterator_t *bctbx_map_cchar_begin(const bctbx_map_t *map); /*return a new allocated iterator*/ #define bctbx_map_end bctbx_map_ullong_end BCTBX_PUBLIC bctbx_iterator_t *bctbx_map_ullong_end(const bctbx_map_t *map); BCTBX_PUBLIC bctbx_iterator_t *bctbx_map_cchar_end(const bctbx_map_t *map); /*return a new allocated iterator or null*/ #define bctbx_map_find_custom bctbx_map_ullong_find_custom BCTBX_PUBLIC bctbx_iterator_t * bctbx_map_ullong_find_custom(bctbx_map_t *map, bctbx_compare_func compare_func, const void *user_data); BCTBX_PUBLIC bctbx_iterator_t * bctbx_map_cchar_find_custom(bctbx_map_t *map, bctbx_compare_func compare_func, const void *user_data); /*return the iterator associated to the key in the map or Null*/ BCTBX_PUBLIC bctbx_iterator_t * bctbx_map_ullong_find_key(bctbx_map_t *map, unsigned long long key); BCTBX_PUBLIC bctbx_iterator_t * bctbx_map_cchar_find_key(bctbx_map_t *map, const char * key); /* return the size of the map*/ #define bctbx_map_size bctbx_map_ullong_size BCTBX_PUBLIC size_t bctbx_map_ullong_size(const bctbx_map_t *map); BCTBX_PUBLIC size_t bctbx_map_cchar_size(const bctbx_map_t *map); /*iterator*/ #define bctbx_iterator_get_pair bctbx_iterator_ullong_get_pair BCTBX_PUBLIC bctbx_pair_t *bctbx_iterator_ullong_get_pair(const bctbx_iterator_t *it); BCTBX_PUBLIC bctbx_pair_t *bctbx_iterator_cchar_get_pair(const bctbx_iterator_t *it); /*return same pointer but pointing to next*/ #define bctbx_iterator_get_next bctbx_iterator_ullong_get_next BCTBX_PUBLIC bctbx_iterator_t *bctbx_iterator_ullong_get_next(bctbx_iterator_t *it); BCTBX_PUBLIC bctbx_iterator_t *bctbx_iterator_cchar_get_next(bctbx_iterator_t *it); #define bctbx_iterator_equals bctbx_iterator_ullong_equals BCTBX_PUBLIC bool_t bctbx_iterator_ullong_equals(const bctbx_iterator_t *a,const bctbx_iterator_t *b); BCTBX_PUBLIC bool_t bctbx_iterator_cchar_equals(const bctbx_iterator_t *a,const bctbx_iterator_t *b); #define bctbx_iterator_delete bctbx_iterator_ullong_delete BCTBX_PUBLIC void bctbx_iterator_ullong_delete(bctbx_iterator_t *it); BCTBX_PUBLIC void bctbx_iterator_cchar_delete(bctbx_iterator_t *it); /*pair*/ typedef struct _bctbx_pair_ullong_t bctbx_pair_ullong_t; /*inherit from bctbx_pair_t*/ BCTBX_PUBLIC bctbx_pair_ullong_t * bctbx_pair_ullong_new(unsigned long long key,void *value); typedef struct _bctbx_pair_cchar_t bctbx_pair_cchar_t; /*inherit from bctbx_pair_t*/ BCTBX_PUBLIC bctbx_pair_cchar_t * bctbx_pair_cchar_new(const char * key,void *value); #define bctbx_pair_get_second bctbx_pair_ullong_get_second BCTBX_PUBLIC void* bctbx_pair_ullong_get_second(const bctbx_pair_t * pair); BCTBX_PUBLIC void* bctbx_pair_cchar_get_second(const bctbx_pair_t * pair); BCTBX_PUBLIC unsigned long long bctbx_pair_ullong_get_first(const bctbx_pair_ullong_t * pair); BCTBX_PUBLIC const char * bctbx_pair_cchar_get_first(const bctbx_pair_cchar_t * pair); #define bctbx_pair_delete bctbx_pair_ullong_delete BCTBX_PUBLIC void bctbx_pair_ullong_delete(bctbx_pair_t * pair); BCTBX_PUBLIC void bctbx_pair_cchar_delete(bctbx_pair_t * pair); #ifdef __cplusplus } #endif #endif /* BCTBX_LIST_H_ */ bctoolbox-0.6.0/include/bctoolbox/parser.h000066400000000000000000000066041313410701300205720ustar00rootroot00000000000000/* bctoolbox Copyright (C) 2017 Belledonne Communications SARL 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, see . */ #ifndef BCTBX_PARSER_H_ #define BCTBX_PARSER_H_ #include "port.h" #ifdef __cplusplus extern "C" { #endif /** * A 256 entries table where each entries defines if character corresponding to its index is allowed or not (value = 0) * for instance noescape_rules[':'] = 1 means that ':' should not be escaped */ typedef unsigned char bctbx_noescape_rules_t[256+1]; /*last entry (BCTBX_NOESCAPE_RULES_USER_INDEX) is reserved for user purpose. Might be usefull to set if array was initialed of not */ #define BCTBX_NOESCAPE_RULES_USER_INDEX (sizeof(bctbx_noescape_rules_t) -1) /** * Allocate a new string with unauthorized characters escaped (I.E replaced by % HEX HEX) if any. * sample: * bctbx_noescape_rules_t my_rules = {0}; nothing allowed * bctbx_noescape_rules_add_alfanums(my_rules); * char * my_escaped_string = bctbx_escape("François",my_rules); * expeted result my_escaped_string == Fran%c3%a7ois * @param buff NULL terminated input buffer. * @param noescape_rules bctbx_noescape_rules_t to apply for this input buff * @return a newly allocated null terminated string */ BCTBX_PUBLIC char* bctbx_escape(const char* buff, const bctbx_noescape_rules_t noescape_rules); /** * Add a list of allowed charaters to a noescape rule. * @param noescape_rules rule to be modified. * @param allowed string representing allowed char. Sample: ";-/" */ BCTBX_PUBLIC void bctbx_noescape_rules_add_list(bctbx_noescape_rules_t noescape_rules, const char *allowed); /** * Add a range of allowed charaters to noescape rule. bctbx_noescape_rules_add_range(noescape_rules, '0','9') is the same as bctbx_noescape_rules_add_list(noescape_rules,"0123456789") * @param noescape_rules rule to be modified. * @param first allowed char. * @param last allowed char. */ BCTBX_PUBLIC void bctbx_noescape_rules_add_range(bctbx_noescape_rules_t noescape_rules, char first, char last); /** * Add ['0'..'9'], ['a'..'z'] ['A'..'z'] to no escape rule. */ BCTBX_PUBLIC void bctbx_noescape_rules_add_alfanums(bctbx_noescape_rules_t noescape_rules); /** * Allocate a new string with escaped character (I.E % HEX HEX) replaced by unicode char. * @param buff NULL terminated input buffer. * @return a newly allocated null terminated string with unescated values. */ BCTBX_PUBLIC char* bctbx_unescaped_string(const char* buff); /** *Convert a single input "a" into unscaped output if need. * a = "%c3%a7" into "ç" with return value = 3 * a = "A" into "A" with return value = 1 * @param a input value * @param out outbut buffer for conversion * @return number of byte wrote into out */ BCTBX_PUBLIC size_t bctbx_get_char (const char *a, char *out); #ifdef __cplusplus } #endif #endif /*BCTBX_PARSER_H_*/ bctoolbox-0.6.0/include/bctoolbox/port.h000066400000000000000000000573171313410701300202710ustar00rootroot00000000000000/* The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* this file is responsible of the portability of the stack */ #ifndef BCTBX_PORT_H #define BCTBX_PORT_H #if !defined(_WIN32) && !defined(_WIN32_WCE) /********************************/ /* definitions for UNIX flavour */ /********************************/ #include #include #include #include #include #include #include #include #include #ifdef __linux #include #endif #include #include #include #if defined(_XOPEN_SOURCE_EXTENDED) || !defined(__hpux) #include #endif #include #include typedef int bctbx_socket_t; typedef pthread_t bctbx_thread_t; typedef pthread_mutex_t bctbx_mutex_t; typedef pthread_cond_t bctbx_cond_t; #ifdef __INTEL_COMPILER #pragma warning(disable : 111) // statement is unreachable #pragma warning(disable : 181) // argument is incompatible with corresponding format string conversion #pragma warning(disable : 188) // enumerated type mixed with another type #pragma warning(disable : 593) // variable "xxx" was set but never used #pragma warning(disable : 810) // conversion from "int" to "unsigned short" may lose significant bits #pragma warning(disable : 869) // parameter "xxx" was never referenced #pragma warning(disable : 981) // operands are evaluated in unspecified order #pragma warning(disable : 1418) // external function definition with no prior declaration #pragma warning(disable : 1419) // external declaration in primary source file #pragma warning(disable : 1469) // "cc" clobber ignored #endif #ifndef BCTBX_DEPRECATED #define BCTBX_DEPRECATED __attribute__ ((deprecated)) #endif #define BCTBX_PUBLIC #define BCTBX_INLINE inline #define BCTBX_EWOULDBLOCK EWOULDBLOCK #define BCTBX_EINPROGRESS EINPROGRESS #define BCTBX_ENETUNREACH ENETUNREACH #define BCTBX_EHOSTUNREACH EHOSTUNREACH #define BCTBX_ENOTCONN ENOTCONN #define BCTBX_EPROTOTYPE EPROTOTYPE /* Protocol wrong type for socket */ #ifdef __cplusplus extern "C" { #endif int __bctbx_thread_join(bctbx_thread_t thread, void **ptr); int __bctbx_thread_create(bctbx_thread_t *thread, pthread_attr_t *attr, void * (*routine)(void*), void *arg); unsigned long __bctbx_thread_self(void); #ifdef __cplusplus } #endif #define bctbx_thread_create __bctbx_thread_create #define bctbx_thread_join __bctbx_thread_join #define bctbx_thread_self __bctbx_thread_self #define bctbx_thread_exit pthread_exit #define bctbx_mutex_init pthread_mutex_init #define bctbx_mutex_lock pthread_mutex_lock #define bctbx_mutex_unlock pthread_mutex_unlock #define bctbx_mutex_destroy pthread_mutex_destroy #define bctbx_cond_init pthread_cond_init #define bctbx_cond_signal pthread_cond_signal #define bctbx_cond_broadcast pthread_cond_broadcast #define bctbx_cond_wait pthread_cond_wait #define bctbx_cond_destroy pthread_cond_destroy #define bctbx_inet_aton inet_aton #define SOCKET_OPTION_VALUE void * #define SOCKET_BUFFER void * #define getSocketError() strerror(errno) #define getSocketErrorCode() (errno) #define bctbx_gettimeofday(tv,tz) gettimeofday(tv,tz) #define bctbx_log10f(x) log10f(x) #else /*********************************/ /* definitions for WIN32 flavour */ /*********************************/ #include #define _CRT_RAND_S #include #include #include #include #ifdef _MSC_VER #include #endif #if defined(__MINGW32__) || !defined(WINAPI_FAMILY_PARTITION) || !defined(WINAPI_PARTITION_DESKTOP) #define BCTBX_WINDOWS_DESKTOP 1 #elif defined(WINAPI_FAMILY_PARTITION) #if defined(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define BCTBX_WINDOWS_DESKTOP 1 #elif defined(WINAPI_PARTITION_PHONE_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) #define BCTBX_WINDOWS_PHONE 1 #elif defined(WINAPI_PARTITION_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) #define BCTBX_WINDOWS_UNIVERSAL 1 #endif #endif #ifndef BCTBX_DEPRECATED #define BCTBX_DEPRECATED __declspec(deprecated) #endif #if defined(_WIN32) || defined(_WIN32_WCE) #ifdef BCTBX_STATIC #define BCTBX_PUBLIC #define BCTBX_VAR_PUBLIC extern #else #ifdef BCTBX_EXPORTS #define BCTBX_PUBLIC __declspec(dllexport) #define BCTBX_VAR_PUBLIC extern __declspec(dllexport) #else #define BCTBX_PUBLIC __declspec(dllimport) #define BCTBX_VAR_PUBLIC __declspec(dllimport) #endif #endif #pragma push_macro("_WINSOCKAPI_") #ifndef _WINSOCKAPI_ #define _WINSOCKAPI_ #endif #define strtok_r strtok_s typedef unsigned __int64 uint64_t; typedef __int64 int64_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef int int32_t; typedef unsigned char uint8_t; typedef __int16 int16_t; typedef long ssize_t; #else #include /*provided by mingw32*/ #include #define BCTBX_PUBLIC #define BCTBX_VAR_PUBLIC extern BCTBX_PUBLIC char* strtok_r(char *str, const char *delim, char **nextp); #endif #define vsnprintf _vsnprintf typedef SOCKET bctbx_socket_t; #ifdef BCTBX_WINDOWS_DESKTOP typedef HANDLE bctbx_cond_t; typedef HANDLE bctbx_mutex_t; #else typedef CONDITION_VARIABLE bctbx_cond_t; typedef SRWLOCK bctbx_mutex_t; #endif typedef HANDLE bctbx_thread_t; #define bctbx_thread_create __bctbx_WIN_thread_create #define bctbx_thread_join __bctbx_WIN_thread_join #define bctbx_thread_self __bctbx_WIN_thread_self #define bctbx_thread_exit(arg) #define bctbx_mutex_init __bctbx_WIN_mutex_init #define bctbx_mutex_lock __bctbx_WIN_mutex_lock #define bctbx_mutex_unlock __bctbx_WIN_mutex_unlock #define bctbx_mutex_destroy __bctbx_WIN_mutex_destroy #define bctbx_cond_init __bctbx_WIN_cond_init #define bctbx_cond_signal __bctbx_WIN_cond_signal #define bctbx_cond_broadcast __bctbx_WIN_cond_broadcast #define bctbx_cond_wait __bctbx_WIN_cond_wait #define bctbx_cond_destroy __bctbx_WIN_cond_destroy #define bctbx_inet_aton __bctbx_WIN_inet_aton #ifdef __cplusplus extern "C" { #endif BCTBX_PUBLIC int __bctbx_WIN_mutex_init(bctbx_mutex_t *m, void *attr_unused); BCTBX_PUBLIC int __bctbx_WIN_mutex_lock(bctbx_mutex_t *mutex); BCTBX_PUBLIC int __bctbx_WIN_mutex_unlock(bctbx_mutex_t *mutex); BCTBX_PUBLIC int __bctbx_WIN_mutex_destroy(bctbx_mutex_t *mutex); BCTBX_PUBLIC int __bctbx_WIN_thread_create(bctbx_thread_t *t, void *attr_unused, void *(*func)(void*), void *arg); BCTBX_PUBLIC int __bctbx_WIN_thread_join(bctbx_thread_t thread, void **unused); BCTBX_PUBLIC unsigned long __bctbx_WIN_thread_self(void); BCTBX_PUBLIC int __bctbx_WIN_cond_init(bctbx_cond_t *cond, void *attr_unused); BCTBX_PUBLIC int __bctbx_WIN_cond_wait(bctbx_cond_t * cond, bctbx_mutex_t * mutex); BCTBX_PUBLIC int __bctbx_WIN_cond_signal(bctbx_cond_t * cond); BCTBX_PUBLIC int __bctbx_WIN_cond_broadcast(bctbx_cond_t * cond); BCTBX_PUBLIC int __bctbx_WIN_cond_destroy(bctbx_cond_t * cond); BCTBX_PUBLIC int __bctbx_WIN_inet_aton (const char * cp, struct in_addr * addr); #ifdef __cplusplus } #endif #define SOCKET_OPTION_VALUE char * #define BCTBX_INLINE __inline #define BCTBX_EWOULDBLOCK WSAEWOULDBLOCK #define BCTBX_EINPROGRESS WSAEINPROGRESS #define BCTBX_ENETUNREACH WSAENETUNREACH #define BCTBX_EHOSTUNREACH WSAEHOSTUNREACH #define BCTBX_ENOTCONN WSAENOTCONN #define BCTBX_EPROTOTYPE WSAEPROTOTYPE /* Protocol wrong type for socket */ #if defined(_WIN32_WCE) #define bctbx_log10f(x) (float)log10 ((double)x) #ifdef assert #undef assert #endif /*assert*/ #define assert(exp) ((void)0) #ifdef errno #undef errno #endif /*errno*/ #define errno GetLastError() #ifdef strerror #undef strerror #endif /*strerror*/ const char * bctbx_strerror(DWORD value); #define strerror bctbx_strerror #else /*_WIN32_WCE*/ #define bctbx_log10f(x) log10f(x) #endif BCTBX_PUBLIC const char *__bctbx_getWinSocketError(int error); #ifndef getSocketErrorCode #define getSocketErrorCode() WSAGetLastError() #endif #ifndef getSocketError #define getSocketError() __bctbx_getWinSocketError(WSAGetLastError()) #endif #ifndef snprintf #define snprintf _snprintf #endif #ifndef strcasecmp #define strcasecmp _stricmp #endif #ifndef strncasecmp #define strncasecmp _strnicmp #endif #ifndef strdup #define strdup _strdup #endif #ifndef unlink #define unlink _unlink #endif #ifndef F_OK #define F_OK 00 /* Visual Studio does not define F_OK */ #endif #ifdef __cplusplus extern "C"{ #endif BCTBX_PUBLIC int bctbx_gettimeofday (struct timeval *tv, void* tz); #ifdef _WORKAROUND_MINGW32_BUGS char * WSAAPI gai_strerror(int errnum); #endif #ifdef __cplusplus } #endif #endif #ifndef _BOOL_T_ #define _BOOL_T_ typedef unsigned char bool_t; #endif /* _BOOL_T_ */ #undef TRUE #undef FALSE #define TRUE 1 #define FALSE 0 #ifndef MIN #define MIN(a,b) (((a)>(b)) ? (b) : (a)) #endif #ifndef MAX #define MAX(a,b) (((a)>(b)) ? (a) : (b)) #endif typedef struct bctoolboxTimeSpec{ int64_t tv_sec; int64_t tv_nsec; }bctoolboxTimeSpec; #ifdef __cplusplus extern "C"{ #endif BCTBX_PUBLIC void* bctbx_malloc(size_t sz); BCTBX_PUBLIC void bctbx_free(void *ptr); BCTBX_PUBLIC void* bctbx_realloc(void *ptr, size_t sz); BCTBX_PUBLIC void* bctbx_malloc0(size_t sz); BCTBX_PUBLIC char * bctbx_strdup(const char *tmp); /*override the allocator with this method, to be called BEFORE bctbx_init()*/ typedef struct _BctoolboxMemoryFunctions{ void *(*malloc_fun)(size_t sz); void *(*realloc_fun)(void *ptr, size_t sz); void (*free_fun)(void *ptr); }BctoolboxMemoryFunctions; void bctbx_set_memory_functions(BctoolboxMemoryFunctions *functions); #define bctbx_new(type,count) (type*)bctbx_malloc(sizeof(type)*(count)) #define bctbx_new0(type,count) (type*)bctbx_malloc0(sizeof(type)*(count)) BCTBX_PUBLIC int bctbx_socket_set_non_blocking(bctbx_socket_t sock); BCTBX_PUBLIC char *bctbx_strndup(const char *str,int n); BCTBX_PUBLIC char *bctbx_strdup_printf(const char *fmt,...); BCTBX_PUBLIC char *bctbx_strdup_vprintf(const char *fmt, va_list ap); BCTBX_PUBLIC char *bctbx_strcat_printf(char *dst, const char *fmt,...); BCTBX_PUBLIC char *bctbx_strcat_vprintf(char *dst, const char *fmt, va_list ap); BCTBX_PUBLIC char *bctbx_concat (const char *str, ...) ; /** * Portable version of the dirname function from libgen.h * @param[in] path The full path for which we want to find the dirname * @return NULL if no dirname is found, otherwise a copy of the dirname of path that needs to be freed with bctbx_free(). */ BCTBX_PUBLIC char *bctbx_dirname(const char *path); /** * Portable version of the basename function from libgen.h * @param[in] path The full path for which we want to find the basename * @return NULL if no basename is found, otherwise a copy of the basename of path that needs to be freed with bctbx_free(). */ BCTBX_PUBLIC char *bctbx_basename(const char *path); BCTBX_PUBLIC int bctbx_file_exist(const char *pathname); /** * @brief return a timeSpec structure(sec and nsec) containing current time(WARNING: there is no guarantees it is UTC ). * The time returned may refers to UTC or last boot. * Use this function only to compute a time span between two calls * @param[in/out] ret The current time (seconds and nano seconds). */ BCTBX_PUBLIC void bctbx_get_cur_time(bctoolboxTimeSpec *ret); /** * @brief return a timeSpec structure(sec and nsec) containing current UTC time. * * @param[in/out] ret The current UTC time, (seconds and nano seconds) */ BCTBX_PUBLIC void bctbx_get_utc_cur_time(bctoolboxTimeSpec *ret); BCTBX_PUBLIC uint64_t bctbx_get_cur_time_ms(void); BCTBX_PUBLIC void bctbx_sleep_ms(int ms); BCTBX_PUBLIC void bctbx_sleep_until(const bctoolboxTimeSpec *ts); /** * @brief Compares two TimeSpec s1 and s2. * * @param[in] s1 First time spec * @param[in] s2 Second time spec * * @return a negative value if s1 is earlier than s2, 0 if they are equal, a positive value if s1 is later than s2 */ BCTBX_PUBLIC int bctbx_timespec_compare(const bctoolboxTimeSpec *s1, const bctoolboxTimeSpec *s2); /** * @brief Add given amount of seconds to a timeSpec structure * * @param[in/out] ts The timeSpec structure used as input, modified in output by increnting it according to second argument * @param[in] lap In seconds, number of seconds to modify the given timeSpec, can be negative(which may set the original timeSpec to 0) */ BCTBX_PUBLIC void bctbx_timespec_add(bctoolboxTimeSpec *ts, const int64_t lap); /** * @brief Parse a string into a number of seconds * Accepted suffixes are Y,M,W,d,h,m,s number is expected to be a base 10 integer, no suffix means seconds * notes: * - M suffix(month) is consired a 30 days period without any consideration of the current date, Y is always 365 days. * - You can combine suffixes in any order: 3Y6M is valid, 15d1M6h is valid too. * - Any unknown suffix is silently ignored and the value preceding it is discarded * - NULL or empty string('\0') in timeString are valid and return 0. * * @param[in] timeString a string formated like {[0-9]+[Y,M,W,d,h,m,s]?}*'\0' (must be null terminated) * @return described time period in seconds */ BCTBX_PUBLIC uint32_t bctbx_time_string_to_sec(const char *timeString); BCTBX_PUBLIC unsigned int bctbx_random(void); BCTBX_PUBLIC ssize_t bctbx_send(bctbx_socket_t socket, const void *buffer, size_t length, int flags); BCTBX_PUBLIC ssize_t bctbx_sendto(bctbx_socket_t socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len); BCTBX_PUBLIC ssize_t bctbx_recv(bctbx_socket_t socket, void *buffer, size_t length, int flags); BCTBX_PUBLIC ssize_t bctbx_recvfrom(bctbx_socket_t socket, void *buffer, size_t length, int flags, struct sockaddr *address, socklen_t *address_len); BCTBX_PUBLIC ssize_t bctbx_read(int fd, void *buf, size_t nbytes); BCTBX_PUBLIC ssize_t bctbx_write(int fd, const void *buf, size_t nbytes); /* Portable and bug-less getaddrinfo */ BCTBX_PUBLIC int bctbx_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res); BCTBX_PUBLIC void bctbx_freeaddrinfo(struct addrinfo *res); BCTBX_PUBLIC int bctbx_getnameinfo(const struct sockaddr *address, socklen_t address_len, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags); BCTBX_PUBLIC int bctbx_addrinfo_to_ip_address(const struct addrinfo *ai, char *ip, size_t ip_size, int *port); BCTBX_PUBLIC int bctbx_addrinfo_to_printable_ip_address(const struct addrinfo *ai, char *printable_ip, size_t printable_ip_size); BCTBX_PUBLIC int bctbx_sockaddr_to_ip_address(const struct sockaddr *sa, socklen_t salen, char *ip, size_t ip_size, int *port); BCTBX_PUBLIC int bctbx_sockaddr_to_printable_ip_address(struct sockaddr *sa, socklen_t salen, char *printable_ip, size_t printable_ip_size); /** * Convert a numeric ip address and port into an addrinfo, whose family will be as specified in the first argument. * If AF_INET6 is requested, the returned addrinfo will always be an IPv6 address, possibly V4MAPPED if the * ip address was a v4 address. * Passing AF_UNSPEC to this function leads to unspecified results. **/ BCTBX_PUBLIC struct addrinfo * bctbx_ip_address_to_addrinfo(int family, int socktype, const char *ipaddress, int port); /** * Convert a name or ip address and port into an addrinfo, whose family will be as specified in the first argument. * If AF_INET6 is requested, the returned addrinfo will always be an IPv6 address, possibly a V4MAPPED if the * ip address was a v4 address. * Passing AF_UNSPEC to this function leads to unspecified results. **/ BCTBX_PUBLIC struct addrinfo * bctbx_name_to_addrinfo(int family, int socktype, const char *name, int port); /** * This function will transform a V4 to V6 mapped address to a pure V4 and write it into result, or will just copy it otherwise. * The memory for v6 and result may be the same, in which case processing is done in place or no copy is done. * The pointer to result must have sufficient storage, typically a struct sockaddr_storage. **/ BCTBX_PUBLIC void bctbx_sockaddr_remove_v4_mapping(const struct sockaddr *v6, struct sockaddr *result, socklen_t *result_len); /** * This function will transform a V6 NAT64 mapped address to a pure V4 and write it into result, or will just copy it otherwise. * The memory for v6 and result may be the same, in which case processing is done in place or no copy is done. * The pointer to result must have sufficient storage, typically a struct sockaddr_storage. **/ BCTBX_PUBLIC void bctbx_sockaddr_remove_nat64_mapping(const struct sockaddr *v6, struct sockaddr *result, socklen_t *result_len); /** * This function will transform a V4 to V6 mapped address to a pure V4 and write it into result, or will just copy it otherwise. * The memory for v6 and result may be the same, in which case processing is done in place or no copy is done. * The pointer to result must have sufficient storage, typically a struct sockaddr_storage. **/ BCTBX_PUBLIC void bctbx_sockaddr_ipv6_to_ipv4(const struct sockaddr *v6, struct sockaddr *result, socklen_t *result_len); /** * This function will transform any V4 address to a V4 mapped address and write it into result. * The pointer to result must have sufficient storage, typically a struct sockaddr_storage. **/ BCTBX_PUBLIC void bctbx_sockaddr_ipv4_to_ipv6(const struct sockaddr *v4, struct sockaddr *result, socklen_t *result_len); /** * Return TRUE if both families, ports and addresses are equals */ BCTBX_PUBLIC bool_t bctbx_sockaddr_equals(const struct sockaddr * sa, const struct sockaddr * sb) ; /** * Get the local IP address that is used to send data to a specific destination. * @param[in] type The address family of the socket to use. * @param[in] dest The destination address. * @param[in] port The destination port. * @param[out] result The local IP address that is used to send data to the destination. * @param[in] result_len The size of the result buffer. * @return 0 on success, a negative value on error. **/ BCTBX_PUBLIC int bctbx_get_local_ip_for(int type, const char *dest, int port, char *result, size_t result_len); /* portable named pipes and shared memory*/ #if !defined(_WIN32_WCE) #ifdef _WIN32 typedef HANDLE bctbx_pipe_t; #define BCTBX_PIPE_INVALID INVALID_HANDLE_VALUE #else typedef int bctbx_pipe_t; #define BCTBX_PIPE_INVALID (-1) #endif BCTBX_PUBLIC bctbx_pipe_t bctbx_server_pipe_create(const char *name); /* * warning: on win32 bctbx_server_pipe_accept_client() might return INVALID_HANDLE_VALUE without * any specific error, this happens when bctbx_server_pipe_close() is called on another pipe. * This pipe api is not thread-safe. */ BCTBX_PUBLIC bctbx_pipe_t bctbx_server_pipe_accept_client(bctbx_pipe_t server); BCTBX_PUBLIC int bctbx_server_pipe_close(bctbx_pipe_t spipe); BCTBX_PUBLIC int bctbx_server_pipe_close_client(bctbx_pipe_t client); BCTBX_PUBLIC bctbx_pipe_t bctbx_client_pipe_connect(const char *name); BCTBX_PUBLIC int bctbx_client_pipe_close(bctbx_pipe_t sock); BCTBX_PUBLIC int bctbx_pipe_read(bctbx_pipe_t p, uint8_t *buf, int len); BCTBX_PUBLIC int bctbx_pipe_write(bctbx_pipe_t p, const uint8_t *buf, int len); BCTBX_PUBLIC void *bctbx_shm_open(unsigned int keyid, int size, int create); BCTBX_PUBLIC void bctbx_shm_close(void *memory); BCTBX_PUBLIC bool_t bctbx_is_multicast_addr(const struct sockaddr *addr); #endif /** * @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] input_char a char which shall be in range [0-9a-fA-F] * * @return the unsigned integer value in range [0-15] */ BCTBX_PUBLIC uint8_t bctbx_char_to_byte(uint8_t input_char); /** * @brief convert a byte which value is in range [0-15] into an hexa char [0-9a-fA-F] * * @param[in] input_byte an integer which shall be in range [0-15] * @return the hexa char [0-9a-f] corresponding to the input */ BCTBX_PUBLIC uint8_t bctbx_byte_to_char(uint8_t input_byte); /** * @brief Convert an hexadecimal string into the corresponding byte buffer * * @param[out] output_bytes The output bytes buffer, must have a length of half the input string buffer * @param[in] input_string The input string buffer, must be hexadecimal(it is not checked by function, any non hexa char is converted to 0) * @param[in] input_string_length The lenght in chars of the string buffer, output is half this length */ BCTBX_PUBLIC void bctbx_str_to_uint8(uint8_t *output_bytes, const uint8_t *input_string, size_t input_string_length); /** * @brief Convert a byte buffer into the corresponding hexadecimal string * * @param[out] output_string The output string buffer, must have a length of twice the input bytes buffer * @param[in] input_bytes The input bytes buffer * @param[in] input_bytes_length The lenght in bytes buffer, output is twice this length */ BCTBX_PUBLIC void bctbx_int8_to_str(uint8_t *output_string, const uint8_t *input_bytes, size_t input_bytes_length); /** * @brief Convert an unsigned 32 bits integer into the corresponding hexadecimal string(including null termination character) * * @param[out] output_string The output string buffer, must have a length of at least 9 bytes(8 nibbles and the '\0') * @param[in] input_uint32 The input unsigned int */ BCTBX_PUBLIC void bctbx_uint32_to_str(uint8_t output_string[9], uint32_t input_uint32); /** * @brief Convert an hexadecimal string of 8 char length into the corresponding 32 bits unsigned integer * * @param[in] input_string The input string buffer, must be hexadecimal and at least 8 char long * * Note : there is no check on the length or validity as an hexa string on the input, incorrect byte is silently mapped to 0 */ BCTBX_PUBLIC uint32_t bctbx_str_to_uint32(const uint8_t input_string[9]); /** * @brief Convert an unsigned 64 bits integer into the corresponding hexadecimal string(including null termination character) * * @param[out] output_string The output string buffer, must have a length of at least 17 bytes(16 nibbles and the '\0') * @param[in] input_uint64 The input unsigned int */ BCTBX_PUBLIC void bctbx_uint64_to_str(uint8_t output_string[17], uint64_t input_uint64); /** * @brief Convert an hexadecimal string of 8 char length into the corresponding 64 bits unsigned integer * * @param[in] input_string The input string buffer, must be hexadecimal and at leat 16 char long * * Note : there is no check on the length or validity as an hexa string on the input, incorrect byte is silently mapped to 0 */ BCTBX_PUBLIC uint64_t bctbx_str_to_uint64(const uint8_t input_string[17]); #ifdef __cplusplus } #endif #ifndef IN6_IS_ADDR_MULTICAST #define IN6_IS_ADDR_MULTICAST(i) (((uint8_t *) (i))[0] == 0xff) #endif #if defined(_WIN32) || defined(__QNX__) /* Mingw32 does not define AI_V4MAPPED, however it is supported starting from Windows Vista. QNX also does not define AI_V4MAPPED. */ # ifndef AI_V4MAPPED # define AI_V4MAPPED 0x00000800 # endif # ifndef AI_ALL # define AI_ALL 0x00000100 # endif # ifndef IPV6_V6ONLY # define IPV6_V6ONLY 27 # endif #endif #endif #if defined(_WIN32) || defined(__QNX__) #define FORMAT_SIZE_T "%Iu" #elif __APPLE__ #define FORMAT_SIZE_T "%lu" #else #define FORMAT_SIZE_T "%zu" #endif bctoolbox-0.6.0/include/bctoolbox/tester.h000066400000000000000000000227561313410701300206120ustar00rootroot00000000000000/* tester - liblinphone test suite Copyright (C) 2013 Belledonne Communications SARL 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, see . */ #ifndef BCTOOLBOX_TESTER_H #define BCTOOLBOX_TESTER_H #include #include #include #include #include typedef void (*test_function_t)(void); /** Function used in all suites - it is invoked before all and each tests and also after each and all tests * @return 0 means success, otherwise it's an error **/ typedef int (*pre_post_function_t)(void); // typedef int (*test_suite_function_t)(const char *name); typedef struct { const char *name; test_function_t func; const char *tags[2]; } test_t; #define TEST_NO_TAG(name, func) \ { name, func, { NULL, NULL } } #define TEST_ONE_TAG(name, func, tag) \ { name, func, { tag, NULL } } #define TEST_TWO_TAGS(name, func, tag1, tag2) \ { name, func, { tag1, tag2 } } typedef struct { const char *name; /*suite name*/ pre_post_function_t before_all; /*function invoked before running the suite. If not returning 0, suite is not launched. */ pre_post_function_t after_all; /*function invoked at the end of the suite, even if some tests failed. */ test_function_t before_each; /*function invoked before each test within this suite. */ test_function_t after_each; /*function invoked after each test within this suite, even if it failed. */ int nb_tests; /* number of tests */ test_t *tests; /* tests within this suite */ } test_suite_t; #ifdef __cplusplus extern "C" { #endif #define CHECK_ARG(argument, index, argc) \ if(index >= argc) { \ fprintf(stderr, "Missing argument for \"%s\"\n", argument); \ return -1; \ } \ BCTBX_PUBLIC void bc_tester_init(void (*ftester_printf)(int level, const char *fmt, va_list args) , int verbosity_info, int verbosity_error, const char* expected_res); BCTBX_PUBLIC void bc_tester_helper(const char *name, const char* additionnal_helper); BCTBX_PUBLIC int bc_tester_parse_args(int argc, char** argv, int argid); BCTBX_PUBLIC int bc_tester_start(const char* prog_name); BCTBX_PUBLIC void bc_tester_add_suite(test_suite_t *suite); BCTBX_PUBLIC void bc_tester_uninit(void); BCTBX_PUBLIC void bc_tester_printf(int level, const char *fmt, ...); BCTBX_PUBLIC const char * bc_tester_get_resource_dir_prefix(void); BCTBX_PUBLIC void bc_tester_set_resource_dir_prefix(const char *name); BCTBX_PUBLIC const char * bc_tester_get_writable_dir_prefix(void); BCTBX_PUBLIC void bc_tester_set_writable_dir_prefix(const char *name); BCTBX_PUBLIC int bc_tester_nb_suites(void); BCTBX_PUBLIC int bc_tester_nb_tests(const char* name); BCTBX_PUBLIC void bc_tester_list_suites(void); BCTBX_PUBLIC void bc_tester_list_tests(const char *suite_name); BCTBX_PUBLIC const char * bc_tester_suite_name(int suite_index); BCTBX_PUBLIC const char * bc_tester_test_name(const char *suite_name, int test_index); BCTBX_PUBLIC int bc_tester_run_suite(test_suite_t *suite, const char *tag_name); BCTBX_PUBLIC int bc_tester_run_tests(const char *suite_name, const char *test_name, const char *tag_name); BCTBX_PUBLIC int bc_tester_suite_index(const char *suite_name); BCTBX_PUBLIC const char * bc_tester_current_suite_name(void); BCTBX_PUBLIC const char * bc_tester_current_test_name(void); BCTBX_PUBLIC const char ** bc_tester_current_test_tags(void); BCTBX_PUBLIC char* bc_sprintfva(const char* format, va_list args); BCTBX_PUBLIC char* bc_sprintf(const char* format, ...); BCTBX_PUBLIC void bc_free(void *ptr); BCTBX_PUBLIC unsigned int bc_get_number_of_failures(void); BCTBX_PUBLIC void bc_set_trace_handler(void(*handler)(int, const char*, va_list)); /** * Get full path to the given resource * * @param name relative resource path * @return path to the resource. Must be freed by caller. */ BCTBX_PUBLIC char * bc_tester_res(const char *name); /** * Get full path to the given writable_file * * @param name relative writable file path * @return path to the writable file. Must be freed by caller. */ BCTBX_PUBLIC char * bc_tester_file(const char *name); /*Redefine the CU_... macros WITHOUT final ';' semicolon, to allow IF conditions and smarter error message */ extern int CU_assertImplementation(int bValue, unsigned int uiLine, const char *strCondition, const char *strFile, const char *strFunction, int bFatal); /** * Test unit assertion * * @return 1 if assert was true, 0 otherwise */ BCTBX_PUBLIC int bc_assert(const char* file, int line, int predicate, const char* format); #define _BC_ASSERT_PRED(name, pred, actual, expected, type, ...) \ do { \ char format[4096] = {0}; \ type cactual = (actual); \ type cexpected = (expected); \ snprintf(format, 4096, name "(" #actual ", " #expected ") - " __VA_ARGS__); \ bc_assert(__FILE__, __LINE__, pred, format); \ } while (0) #define BC_PASS(msg) bc_assert(__FILE__, __LINE__, TRUE, "BC_PASS(" #msg ").") #define BC_FAIL(msg) bc_assert(__FILE__, __LINE__, FALSE, "BC_FAIL(" #msg ").") #define BC_ASSERT(value) bc_assert(__FILE__, __LINE__, (value), #value) #define BC_TEST(value) bc_assert(__FILE__, __LINE__, (value), #value) #define BC_ASSERT_TRUE(value) bc_assert(__FILE__, __LINE__, (value), "BC_ASSERT_TRUE(" #value ")") #define BC_ASSERT_FALSE(value) bc_assert(__FILE__, __LINE__, !(value), "BC_ASSERT_FALSE(" #value ")") #define BC_ASSERT_PTR_EQUAL(actual, expected) bc_assert(__FILE__, __LINE__, ((actual) == (expected)), "BC_ASSERT_PTR_EQUAL(" #actual "!=" #expected ")") #define BC_ASSERT_PTR_NOT_EQUAL(actual, expected) bc_assert(__FILE__, __LINE__, ((actual) != (expected)), "BC_ASSERT_PTR_NOT_EQUAL(" #actual "==" #expected ")") #define BC_ASSERT_PTR_NULL(value) bc_assert(__FILE__, __LINE__, ((value) == NULL), "BC_ASSERT_PTR_NULL(" #value ")") #define BC_ASSERT_PTR_NOT_NULL(value) bc_assert(__FILE__, __LINE__, ((value) != NULL), "BC_ASSERT_PTR_NOT_NULL(" #value ")") #define BC_ASSERT_STRING_NOT_EQUAL(actual, expected) _BC_ASSERT_PRED("BC_ASSERT_STRING_NOT_EQUAL", (strcmp((const char*)(cactual), (const char*)(cexpected))), actual, expected, const char*, "Expected NOT %s but it was.", cexpected) #define BC_ASSERT_NSTRING_EQUAL(actual, expected, count) _BC_ASSERT_PRED("BC_ASSERT_NSTRING_EQUAL", !(strncmp((const char*)(cactual), (const char*)(cexpected), (size_t)(count))), actual, expected, const char*, "Expected %*s but was %*s.", (int)(count), cexpected, (int)(count), cactual) #define BC_ASSERT_NSTRING_NOT_EQUAL(actual, expected, count) _BC_ASSERT_PRED("BC_ASSERT_NSTRING_NOT_EQUAL", (strncmp((const char*)(cactual), (const char*)(cexpected), (size_t)(count))), actual, expected, const char*, "Expected %*s but it was.", (int)count, cexpected) #define BC_ASSERT_DOUBLE_EQUAL(actual, expected, granularity) _BC_ASSERT_PRED("BC_ASSERT_DOUBLE_EQUAL", ((fabs((double)(cactual) - (cexpected)) <= fabs((double)(granularity)))), actual, expected, double, "Expected %f but was %f.", cexpected, cactual) #define BC_ASSERT_DOUBLE_NOT_EQUAL(actual, expected, granularity) _BC_ASSERT_PRED("BC_ASSERT_DOUBLE_NOT_EQUAL", ((fabs((double)(cactual) - (cexpected)) > fabs((double)(granularity)))), actual, expected, double, "Expected %f but was %f.", cexpected, cactual) #define BC_ASSERT_EQUAL(actual, expected, type, type_format) _BC_ASSERT_PRED("BC_ASSERT_EQUAL", ((cactual) == (cexpected)), actual, expected, type, "Expected " type_format " but was " type_format ".", cexpected, cactual) #define BC_ASSERT_NOT_EQUAL(actual, expected, type, type_format) _BC_ASSERT_PRED("BC_ASSERT_NOT_EQUAL", ((cactual) != (cexpected)), actual, expected, type, "Expected NOT " type_format " but it was.", cexpected) #define BC_ASSERT_STRING_EQUAL(actual, expected) _BC_ASSERT_PRED("BC_ASSERT_STRING_EQUAL", cactual && cexpected && !(strcmp((const char*)(cactual), (const char*)(cexpected))), actual, expected, const char*, "Expected %s but was %s.", cexpected, cactual) #define BC_ASSERT_GREATER(actual, min, type, type_format) _BC_ASSERT_PRED("BC_ASSERT_GREATER", ((cactual) >= (cexpected)), actual, min, type, "Expected at least " type_format " but was " type_format ".", cexpected, cactual) #define BC_ASSERT_LOWER(actual, max, type, type_format) _BC_ASSERT_PRED("BC_ASSERT_LOWER", ((cactual) <= (cexpected)), actual, max, type, "Expected at most " type_format " but was " type_format ".", cexpected, cactual) #define BC_ASSERT_GREATER_STRICT(actual, min, type, type_format) _BC_ASSERT_PRED("BC_ASSERT_GREATER", ((cactual) > (cexpected)), actual, min, type, "Expected more than " type_format " but was " type_format ".", cexpected, cactual) #define BC_ASSERT_LOWER_STRICT(actual, max, type, type_format) _BC_ASSERT_PRED("BC_ASSERT_LOWER", ((cactual) < (cexpected)), actual, max, type, "Expected less than " type_format " but was " type_format ".", cexpected, cactual) #ifdef __cplusplus } #endif #endif bctoolbox-0.6.0/include/bctoolbox/vconnect.h000066400000000000000000000165121313410701300211140ustar00rootroot00000000000000/* vconnect.h Copyright (C) 2017 Belledonne Communications SARL This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef BCTBX_VCONNECT #define BCTBX_VCONNECT #include #include #if !defined(_WIN32_WCE) #include #include #if _MSC_VER #include #endif #endif /*_WIN32_WCE*/ #ifndef _WIN32 #include #endif #define BCTBX_VCONNECT_OK 0 /* Successful result */ #define BCTBX_VCONNECT_ERROR -255 /* Some kind of socket error occurred */ #ifdef __cplusplus extern "C"{ #endif /** * Methods associated with the bctbx_vsocket_api_t. */ typedef struct bctbx_vsocket_methods_t bctbx_vsocket_methods_t; /** * Methods pointer prototypes for the socket functions. */ struct bctbx_vsocket_methods_t { bctbx_socket_t (*pFuncSocket)(int socket_family, int socket_type, int protocol); int (*pFuncConnect)(bctbx_socket_t sock, const struct sockaddr *address, socklen_t address_len); int (*pFuncBind)(bctbx_socket_t sock, const struct sockaddr *address, socklen_t address_len); int (*pFuncGetSockName)(bctbx_socket_t sockfd, struct sockaddr *addr, socklen_t *addrlen); int (*pFuncGetSockOpt)(bctbx_socket_t sockfd, int level, int optname, void *optval, socklen_t *optlen); int (*pFuncSetSockOpt)(bctbx_socket_t sockfd, int level, int optname, const void *optval, socklen_t optlen); int (*pFuncClose)(bctbx_socket_t sock); char* (*pFuncGetError)(int err); int (*pFuncShutdown)(bctbx_socket_t sock, int how); }; /** * Socket API structure definition */ typedef struct bctbx_vsocket_api_t bctbx_vsocket_api_t; struct bctbx_vsocket_api_t { const char *vSockName; /* Socket API name */ const bctbx_vsocket_methods_t *pSocketMethods; /* Pointer to the socket methods structure */ }; /**=================================================== * Socket API methods prototypes. * The default implementation relies on libc methods. *====================================================*/ /** * Creates a socket. * @param socket_family type of address structure * @param socket_type socket type i.e SOCK_STREAM * @param protocol protocol family i.e AF_INET * @return Returns a socket file descriptor. */ BCTBX_PUBLIC bctbx_socket_t bctbx_socket(int socket_family, int socket_type, int protocol); /** * Get the local socket address. * Calls the function pointer pFuncGetSockName. The default method associated with this pointer * is getsockname. * @param sockfd socket descriptor * @param addr buffer holding the current address to which the socket sockfd is bound * @param addrlen amount of space (in bytes) pointed to by addr * @return On success, zero is returned. On error, -1 is returned, and errno is * set appropriately. */ BCTBX_PUBLIC int bctbx_getsockname(bctbx_socket_t sockfd, struct sockaddr *addr, socklen_t *addrlen); /** * Get socket options. * @param sockfd socket file descriptor * @param level level of the socket option * @param optname name of the option * @param optval buffer in which the value for the requested option(s) are to be returned * @param optlen contains the size of the buffer pointed to by optval, and on return * contains the actual size of the value returned. * @return On success, zero is returned. On error, -1 is returned, and errno is * set appropriately. */ BCTBX_PUBLIC int bctbx_getsockopt(bctbx_socket_t sockfd, int level, int optname, void *optval, socklen_t *optlen); /** * Set socket options. * @param sockfd socket file descriptor * @param level level of the socket option * @param optname name of the option * @param optval buffer holding the value for the requested option * @param optlen contains the size of the buffer pointed to by optval * @return On success, zero is returned. On error, -1 is returned, and errno is * set appropriately. */ BCTBX_PUBLIC int bctbx_setsockopt(bctbx_socket_t sockfd, int level, int optname, const void *optval, socklen_t optlen); /** * Shut down part of a full duplex connection. * @param sockfd socket file descriptor * @param how specifies what is shut down in the connection. * @return On success, zero is returned. On error, -1 is returned, and errno is * set appropriately. */ BCTBX_PUBLIC int bctbx_shutdown(bctbx_socket_t sockfd, int how); /** * Close a socket file descriptor. * @param sockfd socket file descriptor * @return 0 on success , -1 on error and errno is set. */ BCTBX_PUBLIC int bctbx_socket_close(bctbx_socket_t sockfd); /** * Assign a name to a socket. * @param sockfd socket file descriptor to assign the name to. * @param address address of the socket * @param address_len size of the address structure pointed to by address (bytes) * @return On success, zero is returned. On error, -1 is returned, and errno is * set appropriately. */ BCTBX_PUBLIC int bctbx_bind(bctbx_socket_t sockfd, const struct sockaddr *address, socklen_t address_len); /** * Initialize a connection to a socket. * @param sockfd socket file descriptor * @param address address of the socket * @param address_len size of the address structure pointed to by address (bytes) * @return On success, zero is returned. On error, -1 is returned, and errno is * set appropriately. */ BCTBX_PUBLIC int bctbx_connect(bctbx_socket_t sockfd, const struct sockaddr *address, socklen_t address_len); /** * strerror equivalent. * When an error is returned on a socket operations, returns * the error description based on err (errno) value. * @param err should be set to errno * @return Error description */ BCTBX_PUBLIC char* bctbx_socket_error(int err); /** * Set default bctbx_vsocket_api_t pointer pDefaultvSocket to my_vsocket_api * if it is not NULL, sets it to the standard API implementation otherwise. * By default, the global pointer is set to use bcvSocket implemented in vconnect.c * @param my_vsocket_api Pointer to a bctbx_vsocket_api_t structure. */ BCTBX_PUBLIC void bctbx_vsocket_api_set_default(bctbx_vsocket_api_t *my_vsocket_api); /** * Returns the value of the global variable pDefaultvSocket, * pointing to the default bctbx_vsocket_api_t used. * @return Pointer to bctbx_vsocket_api_t set to operate as default. */ BCTBX_PUBLIC bctbx_vsocket_api_t* bctbx_vsocket_api_get_default(void); /** * Return pointer to standard bctbx_vsocket_api_t implementation based on libc * functions. * @return pointer to bcSocketAPI */ BCTBX_PUBLIC bctbx_vsocket_api_t* bctbx_vsocket_api_get_standard(void); #ifdef __cplusplus } #endif #endif /* BCTBX_VCONNECT */ bctoolbox-0.6.0/include/bctoolbox/vfs.h000066400000000000000000000172671313410701300201030ustar00rootroot00000000000000/* vfs.h Copyright (C) 2016 Belledonne Communications SARL This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef BCTBX_VFS_H #define BCTBX_VFS_H #include #include #if !defined(_WIN32_WCE) #include #include #if _MSC_VER #include #endif #endif /*_WIN32_WCE*/ #ifndef _WIN32 #include #endif #ifdef _WIN32 #ifndef S_IRUSR #define S_IRUSR S_IREAD #endif #ifndef S_IWUSR #define S_IWUSR S_IWRITE #endif #define open _open #define read _read #define write _write #define close _close #define lseek _lseek #endif /*!_WIN32*/ #define BCTBX_VFS_OK 0 /* Successful result */ #define BCTBX_VFS_ERROR -255 /* Some kind of disk I/O error occurred */ #ifdef __cplusplus extern "C"{ #endif /** * Methods associated with the bctbx_vfs_t. */ typedef struct bctbx_io_methods_t bctbx_io_methods_t; /** * VFS file handle. */ typedef struct bctbx_vfs_file_t bctbx_vfs_file_t; struct bctbx_vfs_file_t { const struct bctbx_io_methods_t *pMethods; /* Methods for an open file: all Developpers must supply this field at open step*/ /*the fields below are used by the default implementation. Developpers are not required to supply them, but may use them if they find * them useful*/ void* pUserData; /*Developpers can store private data under this pointer */ int fd; /* File descriptor */ off_t offset; /*File offset used by lseek*/ }; /** */ struct bctbx_io_methods_t { int (*pFuncClose)(bctbx_vfs_file_t *pFile); ssize_t (*pFuncRead)(bctbx_vfs_file_t *pFile, void* buf, size_t count, off_t offset); ssize_t (*pFuncWrite)(bctbx_vfs_file_t *pFile, const void* buf, size_t count, off_t offset); int (*pFuncTruncate)(bctbx_vfs_file_t *pFile, int64_t size); int64_t (*pFuncFileSize)(bctbx_vfs_file_t *pFile); int (*pFuncGetLineFromFd)(bctbx_vfs_file_t *pFile, char* s, int count); off_t (*pFuncSeek)(bctbx_vfs_file_t *pFile, off_t offset, int whence); }; /** * VFS definition */ typedef struct bctbx_vfs_t bctbx_vfs_t; struct bctbx_vfs_t { const char *vfsName; /* Virtual file system name */ int (*pFuncOpen)(bctbx_vfs_t *pVfs, bctbx_vfs_file_t *pFile, const char *fName, int openFlags); }; /* API to use the VFS */ /* * This function returns a pointer to the VFS implemented in this file. */ BCTBX_PUBLIC bctbx_vfs_t *bc_create_vfs(void); /** * Attempts to read count bytes from the open file given by pFile, at the position starting at offset * in the file and and puts them in the buffer pointed by buf. * @param pFile bctbx_vfs_file_t File handle pointer. * @param buf Buffer holding the read bytes. * @param count Number of bytes to read. * @param offset Where to start reading in the file (in bytes). * @return Number of bytes read on success, BCTBX_VFS_ERROR otherwise. */ BCTBX_PUBLIC ssize_t bctbx_file_read(bctbx_vfs_file_t *pFile, void *buf, size_t count, off_t offset); /** * Close the file from its descriptor pointed by thw bctbx_vfs_file_t handle. * @param pFile File handle pointer. * @return return value from the pFuncClose VFS Close function on success, * BCTBX_VFS_ERROR otherwise. */ BCTBX_PUBLIC int bctbx_file_close(bctbx_vfs_file_t *pFile); /** * Allocates a bctbx_vfs_file_t file handle pointer. Opens the file fName * with the mode specified by the mode argument. Calls bctbx_file_open. * @param pVfs Pointer to the vfs instance in use. * @param fName Absolute file path. * @param mode File access mode (char*). * @return pointer to bctbx_vfs_file_t on success, NULL otherwise. */ BCTBX_PUBLIC bctbx_vfs_file_t* bctbx_file_open(bctbx_vfs_t *pVfs, const char *fName, const char *mode); /** * Allocates a bctbx_vfs_file_t file handle pointer. Opens the file fName * with the mode specified by the mode argument. Calls bctbx_file_open. * @param pVfs Pointer to the vfs instance in use. * @param fName Absolute file path. * @param openFlags File access flags(integer). * @return pointer to bctbx_vfs_file_t on success, NULL otherwise. */ BCTBX_PUBLIC bctbx_vfs_file_t* bctbx_file_open2(bctbx_vfs_t *pVfs, const char *fName, const int openFlags); /** * Returns the file size. * @param pFile bctbx_vfs_file_t File handle pointer. * @return BCTBX_VFS_ERROR if an error occured, file size otherwise. */ BCTBX_PUBLIC int64_t bctbx_file_size(bctbx_vfs_file_t *pFile); /** * Truncates/ Extends a file. * @param pFile bctbx_vfs_file_t File handle pointer. * @param size New size of the file. * @return BCTBX_VFS_ERROR if an error occured, 0 otherwise. */ BCTBX_PUBLIC int bctbx_file_truncate(bctbx_vfs_file_t *pFile, int64_t size); /** * Write count bytes contained in buf to a file associated with pFile at the position * offset. Calls pFuncWrite (set to bc_Write by default). * @param pFile File handle pointer. * @param buf Buffer hodling the values to write. * @param count Number of bytes to write to the file. * @param offset Position in the file where to start writing. * @return Number of bytes written on success, BCTBX_VFS_ERROR if an error occurred. */ BCTBX_PUBLIC ssize_t bctbx_file_write(bctbx_vfs_file_t *pFile, const void *buf, size_t count, off_t offset); /** * Writes to file. * @param pFile File handle pointer. * @param offset where to write in the file * @param fmt format argument, similar to that of printf * @return Number of bytes written if success, BCTBX_VFS_ERROR otherwise. */ BCTBX_PUBLIC ssize_t bctbx_file_fprintf(bctbx_vfs_file_t *pFile, off_t offset, const char *fmt, ...); /** * Wrapper to pFuncGetNxtLine. Returns a line with at most maxlen characters * from the file associated to pFile and writes it into s. * @param pFile File handle pointer. * @param s Buffer where to store the read line. * @param maxlen Number of characters to read to find a line in the file. * @return BCTBX_VFS_ERROR if an error occurred, size of line read otherwise. */ BCTBX_PUBLIC int bctbx_file_get_nxtline(bctbx_vfs_file_t *pFile, char *s, int maxlen); /** * Wrapper to pFuncSeek VFS method call. Set the position to offset in the file. * @param pFile File handle pointer. * @param offset File offset where to set the position to. * @param whence Either SEEK_SET, SEEK_CUR,SEEK_END * @return BCTBX_VFS_ERROR on error, offset otherwise. */ BCTBX_PUBLIC off_t bctbx_file_seek(bctbx_vfs_file_t *pFile, off_t offset, int whence); /** * Set default VFS pointer pDefault to my_vfs. * By default, the global pointer is set to use VFS implemnted in vfs.c * @param my_vfs Pointer to a bctbx_vfs_t structure. */ BCTBX_PUBLIC void bctbx_vfs_set_default(bctbx_vfs_t *my_vfs); /** * Returns the value of the global variable pDefault, * pointing to the default vfs used. * @return Pointer to bctbx_vfs_t set to operate as default VFS. */ BCTBX_PUBLIC bctbx_vfs_t* bctbx_vfs_get_default(void); /** * Return pointer to standard VFS impletentation. * @return pointer to bcVfs */ BCTBX_PUBLIC bctbx_vfs_t* bctbx_vfs_get_standard(void); #ifdef __cplusplus } #endif #endif /* BCTBX_VFS_H */ bctoolbox-0.6.0/src/000077500000000000000000000000001313410701300142705ustar00rootroot00000000000000bctoolbox-0.6.0/src/CMakeLists.txt000066400000000000000000000210221313410701300170250ustar00rootroot00000000000000############################################################################ # CMakeLists.txt # Copyright (C) 2016 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################################################ set(BCTOOLBOX_C_SOURCE_FILES containers/list.c logging/logging.c utils/port.c vfs.c vconnect.c parser.c ) set(BCTOOLBOX_CXX_SOURCE_FILES containers/map.cc) if(HAVE_EXECINFO) list(APPEND BCTOOLBOX_CXX_SOURCE_FILES utils/exception.cc) endif() if(MBEDTLS_FOUND) list(APPEND BCTOOLBOX_C_SOURCE_FILES crypto/mbedtls.c) endif() if(POLARSSL_FOUND) if(POLARSSL_VERSION13_OK) list(APPEND BCTOOLBOX_C_SOURCE_FILES crypto/polarssl.c) else() list(APPEND BCTOOLBOX_C_SOURCE_FILES crypto/polarssl1.2.c) endif() endif() if(BCUNIT_FOUND) set(BCTOOLBOX_C_TESTER_SOURCE_FILES tester.c) endif() set(BCTOOLBOX_SOURCE_FILES ${BCTOOLBOX_C_SOURCE_FILES} ${BCTOOLBOX_CXX_SOURCE_FILES}) set(BCTOOLBOX_TESTER_SOURCE_FILES ${BCTOOLBOX_C_TESTER_SOURCE_FILES}) bc_apply_compile_flags(BCTOOLBOX_C_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_C) bc_apply_compile_flags(BCTOOLBOX_C_TESTER_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_C) bc_apply_compile_flags(BCTOOLBOX_CXX_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_CXX) if(ENABLE_STATIC) add_library(bctoolbox-static STATIC ${BCTOOLBOX_SOURCE_FILES} ${BCTOOLBOX_HEADER_FILES}) target_link_libraries(bctoolbox-static INTERFACE ${CMAKE_THREAD_LIBS_INIT}) if(WIN32) target_link_libraries(bctoolbox-static INTERFACE "Winmm" "Ws2_32") endif() set_target_properties(bctoolbox-static PROPERTIES LINKER_LANGUAGE "CXX") if(NOT CMAKE_VERSION VERSION_LESS 3.1) set_target_properties(bctoolbox-static PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED ON) endif() set_target_properties(bctoolbox-static PROPERTIES OUTPUT_NAME bctoolbox) if(HAVE_LIBRT) target_link_libraries(bctoolbox-static INTERFACE rt) endif() if(HAVE_LIBDL) target_link_libraries(bctoolbox-static INTERFACE dl) endif() if(BCUNIT_FOUND) add_library(bctoolbox-tester-static STATIC ${BCTOOLBOX_TESTER_SOURCE_FILES}) set_target_properties(bctoolbox-tester-static PROPERTIES OUTPUT_NAME bctoolbox-tester) target_link_libraries(bctoolbox-tester-static INTERFACE bctoolbox-static) endif() endif() if(ENABLE_SHARED) add_library(bctoolbox SHARED ${BCTOOLBOX_SOURCE_FILES} ${BCTOOLBOX_HEADER_FILES}) target_link_libraries(bctoolbox PRIVATE ${CMAKE_THREAD_LIBS_INIT}) if(IOS) if(IOS) set(MIN_OS ${LINPHONE_IOS_DEPLOYMENT_TARGET}) else() set(MIN_OS ${CMAKE_OSX_DEPLOYMENT_TARGET}) endif() set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/build/osx/") set_target_properties(bctoolbox PROPERTIES FRAMEWORK TRUE MACOSX_FRAMEWORK_IDENTIFIER org.linphone.bctoolbox MACOSX_FRAMEWORK_INFO_PLIST Info.plist.in PUBLIC_HEADER "${BCTOOLBOX_HEADER_FILES}" ) endif() if(WIN32) if(NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") target_link_libraries(bctoolbox PRIVATE "Winmm" "Ws2_32") endif() target_compile_definitions(bctoolbox PRIVATE "-DBCTBX_EXPORTS") endif() set_target_properties(bctoolbox PROPERTIES LINKER_LANGUAGE "CXX") if(NOT CMAKE_VERSION VERSION_LESS 3.1) set_target_properties(bctoolbox PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED ON) endif() if(NOT ANDROID) # Do not version shared library on Android set_target_properties(bctoolbox PROPERTIES SOVERSION ${BCTOOLBOX_SO_VERSION}) endif() if(MSVC) if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/bctoolbox.pdb DESTINATION ${CMAKE_INSTALL_BINDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) endif() endif() if(HAVE_LIBRT) target_link_libraries(bctoolbox PRIVATE rt) endif() if(HAVE_LIBDL) target_link_libraries(bctoolbox PRIVATE dl) endif() if(BCUNIT_FOUND) add_library(bctoolbox-tester SHARED ${BCTOOLBOX_TESTER_SOURCE_FILES}) set_target_properties(bctoolbox-tester PROPERTIES LINKER_LANGUAGE "CXX") target_link_libraries(bctoolbox-tester PRIVATE bctoolbox) if(WIN32) target_compile_definitions(bctoolbox-tester PRIVATE "-DBCTBX_EXPORTS") endif() if(NOT ANDROID) # Do not version shared library on Android set_target_properties(bctoolbox-tester PROPERTIES SOVERSION ${BCTOOLBOXTESTER_SO_VERSION}) endif() if(MSVC) if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/bctoolbox-tester.pdb DESTINATION ${CMAKE_INSTALL_BINDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) endif() endif() endif() endif() if(MBEDTLS_FOUND) if(ENABLE_STATIC) target_include_directories(bctoolbox-static PUBLIC ${MBEDTLS_INCLUDE_DIRS}) target_include_directories(bctoolbox-static PRIVATE ${BCTOOLBOX_PRIVATE_INCLUDE_DIRS}) target_link_libraries(bctoolbox-static INTERFACE ${MBEDTLS_LIBRARIES}) endif() if(ENABLE_SHARED) target_include_directories(bctoolbox PUBLIC ${MBEDTLS_INCLUDE_DIRS}) target_include_directories(bctoolbox PRIVATE ${BCTOOLBOX_PRIVATE_INCLUDE_DIRS}) target_link_libraries(bctoolbox PRIVATE ${MBEDTLS_LIBRARIES}) endif() endif() if(POLARSSL_FOUND) if(ENABLE_STATIC) target_include_directories(bctoolbox-static PUBLIC ${POLARSSL_INCLUDE_DIRS}) target_link_libraries(bctoolbox-static INTERFACE ${POLARSSL_LIBRARIES}) endif() if(ENABLE_SHARED) target_include_directories(bctoolbox PUBLIC ${POLARSSL_INCLUDE_DIRS}) target_link_libraries(bctoolbox PRIVATE ${POLARSSL_LIBRARIES}) endif() endif() if(BCUNIT_FOUND) if(ENABLE_STATIC) target_include_directories(bctoolbox-tester-static PUBLIC ${BCUNIT_INCLUDE_DIRS}) target_link_libraries(bctoolbox-tester-static INTERFACE bctoolbox-static ${BCUNIT_LIBRARIES}) endif() if(ENABLE_SHARED) target_include_directories(bctoolbox-tester PUBLIC ${BCUNIT_INCLUDE_DIRS}) target_link_libraries(bctoolbox-tester PRIVATE bctoolbox ${BCUNIT_LIBRARIES}) if(IOS) set_target_properties(bctoolbox-tester PROPERTIES FRAMEWORK TRUE MACOSX_FRAMEWORK_IDENTIFIER com.belledonne-communications.bctoolbox-tester PUBLIC_HEADER "${BCTOOLBOX_HEADER_FILES}" ) endif() endif() endif() if(ENABLE_STATIC) install(TARGETS bctoolbox-static EXPORT ${EXPORT_TARGETS_NAME}Targets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE COMPONENT core ) if(BCUNIT_FOUND) install(TARGETS bctoolbox-tester-static EXPORT ${EXPORT_TARGETS_NAME}Targets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE COMPONENT tester ) endif() endif() if(ENABLE_SHARED) install(TARGETS bctoolbox EXPORT ${EXPORT_TARGETS_NAME}Targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} FRAMEWORK DESTINATION Frameworks PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE COMPONENT core ) if(BCUNIT_FOUND) install(TARGETS bctoolbox-tester EXPORT ${EXPORT_TARGETS_NAME}Targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} FRAMEWORK DESTINATION Frameworks PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE COMPONENT tester ) endif() endif() if(MSVC) #disable "was deprecated" warnings of windows compiler (typically using strcpy_s instead of strcpy and stupid things like this) target_compile_options(bctoolbox PRIVATE "/wd4996") target_compile_options(bctoolbox-tester PRIVATE "/wd4996") endif() bctoolbox-0.6.0/src/Makefile.am000066400000000000000000000017231313410701300163270ustar00rootroot00000000000000 lib_LTLIBRARIES=libbctoolbox.la libbctoolbox-tester.la libbctoolbox_la_SOURCES= vconnect.c \ vfs.c \ utils/port.c \ utils/exception.cc \ logging/logging.c \ containers/list.c \ containers/map.cc \ parser.c if ENABLE_POLARSSL libbctoolbox_la_SOURCES += crypto/polarssl.c endif if ENABLE_POLARSSL12 libbctoolbox_la_SOURCES += crypto/polarssl1.2.c endif if ENABLE_MBEDTLS libbctoolbox_la_SOURCES += crypto/mbedtls.c endif AM_CFLAGS = $(STRICT_OPTIONS) $(POLARSSL_CFLAGS) $(MBEDTLS_CFLAGS) AM_CXXFLAGS = $(STRICT_OPTIONS) libbctoolbox_la_LIBADD = $(POLARSSL_LIBS) $(MBEDTLS_LIBS) libbctoolbox_la_LDFLAGS = -version-info $(BCTOOLBOX_SO_VERSION) -no-undefined libbctoolbox_tester_la_SOURCES = tester.c utils.h libbctoolbox_tester_la_LIBADD = libbctoolbox.la $(BCUNIT_LIBS) libbctoolbox_tester_la_LDFLAGS= -version-info $(BCTOOLBOX_SO_VERSION) -no-undefined AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(BCUNIT_CFLAGS) bctoolbox-0.6.0/src/containers/000077500000000000000000000000001313410701300164355ustar00rootroot00000000000000bctoolbox-0.6.0/src/containers/list.c000066400000000000000000000206401313410701300175560ustar00rootroot00000000000000/* bctoolbox Copyright (C) 2016 Belledonne Communications SARL 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, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #define _CRT_RAND_S #include #include #include #ifndef _WIN32 #include #include /*for gettimeofday*/ #include /* available on POSIX system only */ #else #include #endif #include "bctoolbox/port.h" #include "bctoolbox/logging.h" #include "bctoolbox/list.h" bctbx_list_t* bctbx_list_new(void *data){ bctbx_list_t* new_elem=bctbx_new0(bctbx_list_t,1); new_elem->data=data; return new_elem; } bctbx_list_t* bctbx_list_next(const bctbx_list_t *elem) { return elem->next; } void* bctbx_list_get_data(const bctbx_list_t *elem) { return elem->data; } bctbx_list_t* bctbx_list_append_link(bctbx_list_t* elem,bctbx_list_t *new_elem){ bctbx_list_t* it=elem; if (elem==NULL) return new_elem; if (new_elem==NULL) return elem; while (it->next!=NULL) it=bctbx_list_next(it); it->next=new_elem; new_elem->prev=it; return elem; } bctbx_list_t* bctbx_list_append(bctbx_list_t* elem, void * data){ bctbx_list_t* new_elem=bctbx_list_new(data); return bctbx_list_append_link(elem,new_elem); } bctbx_list_t* bctbx_list_prepend_link(bctbx_list_t* elem, bctbx_list_t *new_elem){ if (elem!=NULL) { new_elem->next=elem; elem->prev=new_elem; } return new_elem; } bctbx_list_t* bctbx_list_prepend(bctbx_list_t* elem, void *data){ return bctbx_list_prepend_link(elem,bctbx_list_new(data)); } bctbx_list_t * bctbx_list_last_elem(const bctbx_list_t *l){ if (l==NULL) return NULL; while(l->next){ l=l->next; } return (bctbx_list_t*)l; } bctbx_list_t * bctbx_list_first_elem(const bctbx_list_t *l){ if (l==NULL) return NULL; while(l->prev){ l=l->prev; } return (bctbx_list_t*)l; } bctbx_list_t* bctbx_list_concat(bctbx_list_t* first, bctbx_list_t* second){ bctbx_list_t* it=first; if (it==NULL) return second; if (second==NULL) return first; while(it->next!=NULL) it=bctbx_list_next(it); it->next=second; second->prev=it; return first; } bctbx_list_t* bctbx_list_free(bctbx_list_t* list){ bctbx_list_t* elem = list; bctbx_list_t* tmp; if (list==NULL) return NULL; while(elem->next!=NULL) { tmp = elem; elem = elem->next; bctbx_free(tmp); } bctbx_free(elem); return NULL; } bctbx_list_t * bctbx_list_free_with_data(bctbx_list_t *list, bctbx_list_free_func freefunc){ bctbx_list_t* elem = list; bctbx_list_t* tmp; if (list==NULL) return NULL; while(elem->next!=NULL) { tmp = elem; elem = elem->next; freefunc(tmp->data); bctbx_free(tmp); } freefunc(elem->data); bctbx_free(elem); return NULL; } bctbx_list_t* _bctbx_list_remove(bctbx_list_t* first, void *data, int warn_if_not_found){ bctbx_list_t* it; it=bctbx_list_find(first,data); if (it) return bctbx_list_erase_link(first,it); else if (warn_if_not_found){ bctbx_warning("bctbx_list_remove: no element with %p data was in the list", data); } return first; } bctbx_list_t* bctbx_list_remove(bctbx_list_t* first, void *data){ return _bctbx_list_remove(first, data, TRUE); } bctbx_list_t * bctbx_list_remove_custom(bctbx_list_t *first, bctbx_compare_func compare_func, const void *user_data) { bctbx_list_t *cur; bctbx_list_t *elem = first; while (elem != NULL) { cur = elem; elem = elem->next; if (compare_func(cur->data, user_data) == 0) { first = bctbx_list_remove(first, cur->data); } } return first; } size_t bctbx_list_size(const bctbx_list_t* first){ size_t n=0; while(first!=NULL){ ++n; first=first->next; } return n; } void bctbx_list_for_each(const bctbx_list_t* list, bctbx_list_iterate_func func){ for(;list!=NULL;list=list->next){ func(list->data); } } void bctbx_list_for_each2(const bctbx_list_t* list, bctbx_list_iterate2_func func, void *user_data){ for(;list!=NULL;list=list->next){ func(list->data,user_data); } } bctbx_list_t * bctbx_list_pop_front(bctbx_list_t *list, void **front_data){ bctbx_list_t *front_elem=list; if (front_elem==NULL){ *front_data=NULL; return NULL; } *front_data=front_elem->data; list=bctbx_list_unlink(list,front_elem); bctbx_free(front_elem); return list; } bctbx_list_t* bctbx_list_unlink(bctbx_list_t* list, bctbx_list_t* elem){ bctbx_list_t* ret; if (elem==list){ ret=elem->next; elem->prev=NULL; elem->next=NULL; if (ret!=NULL) ret->prev=NULL; return ret; } elem->prev->next=elem->next; if (elem->next!=NULL) elem->next->prev=elem->prev; elem->next=NULL; elem->prev=NULL; return list; } bctbx_list_t * bctbx_list_erase_link(bctbx_list_t* list, bctbx_list_t* elem){ bctbx_list_t *ret=bctbx_list_unlink(list,elem); bctbx_free(elem); return ret; } bctbx_list_t* bctbx_list_find(bctbx_list_t* list, const void *data){ for(;list!=NULL;list=list->next){ if (list->data==data) return list; } return NULL; } bctbx_list_t* bctbx_list_find_custom(const bctbx_list_t* list, bctbx_compare_func compare_func, const void *user_data){ for(;list!=NULL;list=list->next){ if (compare_func(list->data,user_data)==0) return (bctbx_list_t *)list; } return NULL; } bctbx_list_t *bctbx_list_delete_custom(bctbx_list_t *list, bctbx_compare_func compare_func, const void *user_data){ bctbx_list_t *elem=bctbx_list_find_custom(list,compare_func,user_data); if (elem!=NULL){ list=bctbx_list_erase_link(list,elem); } return list; } void * bctbx_list_nth_data(const bctbx_list_t* list, int index){ int i; for(i=0;list!=NULL;list=list->next,++i){ if (i==index) return list->data; } bctbx_error("bctbx_list_nth_data: no such index in list."); return NULL; } int bctbx_list_position(const bctbx_list_t* list, bctbx_list_t* elem){ int i; for(i=0;list!=NULL;list=list->next,++i){ if (elem==list) return i; } bctbx_error("bctbx_list_position: no such element in list."); return -1; } int bctbx_list_index(const bctbx_list_t* list, void *data){ int i; for(i=0;list!=NULL;list=list->next,++i){ if (data==list->data) return i; } bctbx_error("bctbx_list_index: no such element in list."); return -1; } bctbx_list_t* bctbx_list_insert_sorted(bctbx_list_t* list, void *data, bctbx_compare_func compare_func){ bctbx_list_t* it,*previt=NULL; bctbx_list_t* nelem; bctbx_list_t* ret=list; if (list==NULL) return bctbx_list_append(list,data); else{ nelem=bctbx_list_new(data); for(it=list;it!=NULL;it=it->next){ previt=it; if (compare_func(data,it->data)<=0){ nelem->prev=it->prev; nelem->next=it; if (it->prev!=NULL) it->prev->next=nelem; else{ ret=nelem; } it->prev=nelem; return ret; } } previt->next=nelem; nelem->prev=previt; } return ret; } bctbx_list_t* bctbx_list_insert(bctbx_list_t* list, bctbx_list_t* before, void *data){ bctbx_list_t* elem; if (list==NULL || before==NULL) return bctbx_list_append(list,data); for(elem=list;elem!=NULL;elem=bctbx_list_next(elem)){ if (elem==before){ if (elem->prev==NULL) return bctbx_list_prepend(list,data); else{ bctbx_list_t* nelem=bctbx_list_new(data); nelem->prev=elem->prev; nelem->next=elem; elem->prev->next=nelem; elem->prev=nelem; } } } return list; } bctbx_list_t* bctbx_list_copy(const bctbx_list_t* list){ bctbx_list_t* copy=NULL; const bctbx_list_t* iter; for(iter=list;iter!=NULL;iter=bctbx_list_next(iter)){ copy=bctbx_list_append(copy,iter->data); } return copy; } bctbx_list_t* bctbx_list_copy_with_data(const bctbx_list_t* list, bctbx_list_copy_func copyfunc){ bctbx_list_t* copy=NULL; const bctbx_list_t* iter; for(iter=list;iter!=NULL;iter=bctbx_list_next(iter)){ copy=bctbx_list_append(copy,copyfunc(iter->data)); } return copy; } bctbx_list_t* bctbx_list_copy_reverse_with_data(const bctbx_list_t* list, bctbx_list_copy_func copyfunc){ bctbx_list_t* copy=NULL; const bctbx_list_t* iter; for(iter=list;iter!=NULL;iter=bctbx_list_next(iter)){ copy=bctbx_list_prepend(copy,copyfunc(iter->data)); } return copy; } bctoolbox-0.6.0/src/containers/map.cc000066400000000000000000000271261313410701300175310ustar00rootroot00000000000000/* bctoolbox Copyright (C) 2016 Belledonne Communications SARL 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, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "bctoolbox/logging.h" #include "bctoolbox/map.h" #include #include #define LOG_DOMAIN "bctoolbox" typedef std::multimap mmap_ullong_t; typedef mmap_ullong_t::value_type pair_ullong_t; typedef std::multimap mmap_cchar_t; typedef mmap_cchar_t::value_type pair_cchar_t; template bctbx_map_t * bctbx_mmap_new(void) { return (bctbx_map_t *) new T; } extern "C" bctbx_map_t *bctbx_mmap_ullong_new(void) { return bctbx_mmap_new(); } extern "C" bctbx_map_t *bctbx_mmap_cchar_new(void) { return bctbx_mmap_new(); } template void bctbx_mmap_delete(bctbx_map_t *mmap) { delete (T *)mmap; } extern "C" void bctbx_mmap_ullong_delete(bctbx_map_t *mmap) { bctbx_mmap_delete(mmap); } extern "C" void bctbx_mmap_cchar_delete(bctbx_map_t *mmap) { bctbx_mmap_delete(mmap); } extern "C" void bctbx_mmap_ullong_delete_with_data(bctbx_map_t *mmap, bctbx_map_free_func freefunc) { bctbx_iterator_t *it = bctbx_map_ullong_begin(mmap); bctbx_iterator_t *end = bctbx_map_ullong_end(mmap); while(!bctbx_iterator_ullong_equals(it, end)) { bctbx_pair_t *pair = bctbx_iterator_ullong_get_pair(it); freefunc(bctbx_pair_ullong_get_second(pair)); it = bctbx_iterator_ullong_get_next(it); } bctbx_iterator_ullong_delete(it); bctbx_iterator_ullong_delete(end); bctbx_mmap_ullong_delete(mmap); } extern "C" void bctbx_mmap_cchar_delete_with_data(bctbx_map_t *mmap, bctbx_map_free_func freefunc) { bctbx_iterator_t *it = bctbx_map_cchar_begin(mmap); bctbx_iterator_t *end = bctbx_map_cchar_end(mmap); while(!bctbx_iterator_cchar_equals(it, end)) { bctbx_pair_t *pair = bctbx_iterator_cchar_get_pair(it); freefunc(bctbx_pair_cchar_get_second(pair)); it = bctbx_iterator_cchar_get_next(it); } bctbx_iterator_cchar_delete(it); bctbx_iterator_cchar_delete(end); bctbx_mmap_cchar_delete(mmap); } template bctbx_iterator_t *bctbx_map_insert_base(bctbx_map_t *map,const bctbx_pair_t *pair,bool_t returns_it) { typename T::iterator it; it = ((T *)map)->insert(*((typename T::value_type *)pair)); if (returns_it) { return (bctbx_iterator_t *) new typename T::iterator(it); } else return NULL; } static bctbx_iterator_t * bctbx_map_ullong_insert_base(bctbx_map_t *map,const bctbx_pair_t *pair,bool_t returns_it) { return bctbx_map_insert_base(map, pair, returns_it); } extern "C" void bctbx_map_ullong_insert(bctbx_map_t *map,const bctbx_pair_t *pair) { bctbx_map_ullong_insert_base(map,pair,FALSE); } static bctbx_iterator_t * bctbx_map_cchar_insert_base(bctbx_map_t *map,const bctbx_pair_t *pair,bool_t returns_it) { return bctbx_map_insert_base(map, pair, returns_it); } extern "C" void bctbx_map_cchar_insert(bctbx_map_t *map,const bctbx_pair_t *pair) { bctbx_map_cchar_insert_base(map,pair,FALSE); } extern "C" void bctbx_map_ullong_insert_and_delete(bctbx_map_t *map, bctbx_pair_t *pair) { bctbx_map_ullong_insert(map,pair); bctbx_pair_ullong_delete(pair); } extern "C" bctbx_iterator_t * bctbx_map_ullong_insert_and_delete_with_returned_it(bctbx_map_t *map, bctbx_pair_t *pair) { bctbx_iterator_t * it = bctbx_map_ullong_insert_base(map,pair,TRUE); bctbx_pair_ullong_delete(pair); return it; } extern "C" void bctbx_map_cchar_insert_and_delete(bctbx_map_t *map, bctbx_pair_t *pair) { bctbx_map_cchar_insert(map,pair); bctbx_pair_cchar_delete(pair); } extern "C" bctbx_iterator_t * bctbx_map_cchar_insert_and_delete_with_returned_it(bctbx_map_t *map, bctbx_pair_t *pair) { bctbx_iterator_t * it = bctbx_map_cchar_insert_base(map,pair,TRUE); bctbx_pair_cchar_delete(pair); return it; } template bctbx_iterator_t *bctbx_map_erase_type(bctbx_map_t *map,bctbx_iterator_t *it) { //bctbx_iterator_t * next = (bctbx_iterator_t *) new mmap_ullong_t::iterator((*(mmap_ullong_t::iterator*)it)); //next = bctbx_iterator_get_next(next); ((T *)map)->erase((*(typename T::iterator*)it)++); //bctbx_iterator_delete(it); return it; } extern "C" bctbx_iterator_t *bctbx_map_ullong_erase(bctbx_map_t *map,bctbx_iterator_t *it) { return bctbx_map_erase_type(map, it); } extern "C" bctbx_iterator_t *bctbx_map_cchar_erase(bctbx_map_t *map,bctbx_iterator_t *it) { return bctbx_map_erase_type(map, it); } template bctbx_iterator_t *bctbx_map_begin_type(const bctbx_map_t *map) { return (bctbx_iterator_t *) new typename T::iterator(((T *)map)->begin()); } extern "C" bctbx_iterator_t *bctbx_map_ullong_begin(const bctbx_map_t *map) { return bctbx_map_begin_type(map); } extern "C" bctbx_iterator_t *bctbx_map_cchar_begin(const bctbx_map_t *map) { return bctbx_map_begin_type(map); } template bctbx_iterator_t *bctbx_map_end_type(const bctbx_map_t *map) { return (bctbx_iterator_t *) new typename T::iterator(((T *)map)->end()); } extern "C" bctbx_iterator_t *bctbx_map_ullong_end(const bctbx_map_t *map) { return bctbx_map_end_type(map); } extern "C" bctbx_iterator_t *bctbx_map_cchar_end(const bctbx_map_t *map) { return bctbx_map_end_type(map); } template bctbx_iterator_t * bctbx_map_find_key_type(bctbx_map_t *map, typename T::key_type key) { bctbx_iterator_t * it = (bctbx_iterator_t*) new typename T::iterator(((T *)map)->find(key)); return it; } extern "C" bctbx_iterator_t * bctbx_map_ullong_find_key(bctbx_map_t *map, unsigned long long key) { return bctbx_map_find_key_type(map, (mmap_ullong_t::key_type)key); } extern "C" bctbx_iterator_t * bctbx_map_cchar_find_key(bctbx_map_t *map, const char * key) { return bctbx_map_find_key_type(map, (mmap_cchar_t::key_type)key); } template size_t bctbx_map_size_type(const bctbx_map_t *map) { return ((T *)map)->size(); } extern "C" size_t bctbx_map_ullong_size(const bctbx_map_t *map) { return bctbx_map_size_type(map); } extern "C" size_t bctbx_map_cchar_size(const bctbx_map_t *map) { return bctbx_map_size_type(map); } extern "C" bctbx_iterator_t * bctbx_map_ullong_find_custom(bctbx_map_t *map, bctbx_compare_func compare_func, const void *user_data) { bctbx_iterator_t * end = bctbx_map_ullong_end(map); for(bctbx_iterator_t * it = bctbx_map_ullong_begin(map);!bctbx_iterator_ullong_equals(it,end);) { if (compare_func(bctbx_pair_ullong_get_second(bctbx_iterator_ullong_get_pair(it)),user_data)==0) { bctbx_iterator_ullong_delete(end); return it; } else { it = bctbx_iterator_ullong_get_next(it); } } bctbx_iterator_ullong_delete(end); return NULL; } extern "C" bctbx_iterator_t * bctbx_map_cchar_find_custom(bctbx_map_t *map, bctbx_compare_func compare_func, const void *user_data) { bctbx_iterator_t * end = bctbx_map_cchar_end(map); for(bctbx_iterator_t * it = bctbx_map_cchar_begin(map);!bctbx_iterator_cchar_equals(it,end);) { if (compare_func(bctbx_pair_cchar_get_second(bctbx_iterator_cchar_get_pair(it)),user_data)==0) { bctbx_iterator_cchar_delete(end); return it; } else { it = bctbx_iterator_cchar_get_next(it); } } bctbx_iterator_cchar_delete(end); return NULL; } /*iterator*/ template bctbx_pair_t *bctbx_iterator_get_pair_type(const bctbx_iterator_t *it) { return (bctbx_pair_t *)&(**((typename T::iterator*)it)); } extern "C" bctbx_pair_t *bctbx_iterator_ullong_get_pair(const bctbx_iterator_t *it) { return bctbx_iterator_get_pair_type(it); } extern "C" bctbx_pair_t *bctbx_iterator_cchar_get_pair(const bctbx_iterator_t *it) { return bctbx_iterator_get_pair_type(it); } template bctbx_iterator_t *bctbx_iterator_get_next_type(bctbx_iterator_t *it) { ((typename T::iterator*)it)->operator++(); return it; } extern "C" bctbx_iterator_t *bctbx_iterator_ullong_get_next(bctbx_iterator_t *it) { return bctbx_iterator_get_next_type(it); } extern "C" bctbx_iterator_t *bctbx_iterator_cchar_get_next(bctbx_iterator_t *it) { return bctbx_iterator_get_next_type(it); } extern "C" bctbx_iterator_t *bctbx_iterator_ullong_get_next_and_delete(bctbx_iterator_t *it) { bctbx_iterator_t * next = bctbx_iterator_ullong_get_next(it); bctbx_iterator_ullong_delete(it); return next; } extern "C" bctbx_iterator_t *bctbx_iterator_cchar_get_next_and_delete(bctbx_iterator_t *it) { bctbx_iterator_t * next = bctbx_iterator_cchar_get_next(it); bctbx_iterator_cchar_delete(it); return next; } template bool_t bctbx_iterator_equals_type(const bctbx_iterator_t *a,const bctbx_iterator_t *b) { return *(typename T::iterator*)a == *(typename T::iterator*)b; } extern "C" bool_t bctbx_iterator_ullong_equals(const bctbx_iterator_t *a,const bctbx_iterator_t *b) { return bctbx_iterator_equals_type(a, b); } extern "C" bool_t bctbx_iterator_cchar_equals(const bctbx_iterator_t *a,const bctbx_iterator_t *b) { return bctbx_iterator_equals_type(a, b); } template void bctbx_iterator_delete_type(bctbx_iterator_t *it) { delete ((typename T::iterator*)it); } extern "C" void bctbx_iterator_ullong_delete(bctbx_iterator_t *it) { bctbx_iterator_delete_type(it); } extern "C" void bctbx_iterator_cchar_delete(bctbx_iterator_t *it) { bctbx_iterator_delete_type(it); } /*pair*/ template typename T::value_type * bctbx_pair_new(typename T::key_type key,void *value) { return (typename T::value_type *) new typename T::value_type(key,value); } extern "C" bctbx_pair_ullong_t * bctbx_pair_ullong_new(unsigned long long key,void *value) { return (bctbx_pair_ullong_t *)bctbx_pair_new((mmap_ullong_t::key_type)key, value); } extern "C" bctbx_pair_cchar_t * bctbx_pair_cchar_new(const char * key,void *value) { return (bctbx_pair_cchar_t *)bctbx_pair_new((mmap_cchar_t::key_type)key, value); } template typename T::key_type bctbx_pair_get_first(const typename T::value_type * pair) { return ((typename T::value_type*)pair)->first; } extern "C" unsigned long long bctbx_pair_ullong_get_first(const bctbx_pair_ullong_t * pair) { return bctbx_pair_get_first((pair_ullong_t *)pair); } extern "C" const char * bctbx_pair_cchar_get_first(const bctbx_pair_cchar_t * pair) { return bctbx_pair_get_first((pair_cchar_t *)pair).c_str(); } template void* bctbx_pair_get_second_type(const bctbx_pair_t * pair) { return ((T*)pair)->second; } extern "C" void* bctbx_pair_ullong_get_second(const bctbx_pair_t * pair) { return bctbx_pair_get_second_type(pair); } extern "C" void* bctbx_pair_cchar_get_second(const bctbx_pair_t * pair) { return bctbx_pair_get_second_type(pair); } template void bctbx_pair_delete_type(bctbx_pair_t * pair) { delete ((T*)pair); } extern "C" void bctbx_pair_ullong_delete(bctbx_pair_t * pair) { bctbx_pair_delete_type(pair); } extern "C" void bctbx_pair_cchar_delete(bctbx_pair_t * pair) { bctbx_pair_delete_type(pair); } bctoolbox-0.6.0/src/crypto/000077500000000000000000000000001313410701300156105ustar00rootroot00000000000000bctoolbox-0.6.0/src/crypto/mbedtls.c000066400000000000000000001724301313410701300174150ustar00rootroot00000000000000/* crypto_mbedtls.c Copyright (C) 2016 Belledonne Communications SARL This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "utils.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bctoolbox/logging.h" static int bctbx_ssl_sendrecv_callback_return_remap(int32_t ret_code) { switch (ret_code) { case BCTBX_ERROR_NET_WANT_READ: return MBEDTLS_ERR_SSL_WANT_READ; case BCTBX_ERROR_NET_WANT_WRITE: return MBEDTLS_ERR_SSL_WANT_WRITE; case BCTBX_ERROR_NET_CONN_RESET: return MBEDTLS_ERR_NET_CONN_RESET; default: return (int)ret_code; } } void bctbx_strerror(int32_t error_code, char *buffer, size_t buffer_length) { if (error_code>0) { snprintf(buffer, buffer_length, "%s", "Invalid Error code"); return ; } /* mbedtls error code are all negatived and bas smaller than 0x0000F000 */ /* bctoolbox defined error codes are all in format -0x7XXXXXXX */ if (-error_code<0x00010000) { /* it's a mbedtls error code */ mbedtls_strerror(error_code, buffer, buffer_length); return; } snprintf(buffer, buffer_length, "%s [-0x%x]", "bctoolbox defined error code", -error_code); return; } int32_t bctbx_base64_encode(unsigned char *output, size_t *output_length, const unsigned char *input, size_t input_length) { size_t byte_written = 0; int ret = mbedtls_base64_encode(output, *output_length, &byte_written, input, input_length); *output_length = byte_written; if (ret == MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) { return BCTBX_ERROR_OUTPUT_BUFFER_TOO_SMALL; } return ret; } int32_t bctbx_base64_decode(unsigned char *output, size_t *output_length, const unsigned char *input, size_t input_length) { size_t byte_written = 0; int ret = mbedtls_base64_decode(output, *output_length, &byte_written, input, input_length); *output_length = byte_written; if (ret == MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) { return BCTBX_ERROR_OUTPUT_BUFFER_TOO_SMALL; } if (ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER) { return BCTBX_ERROR_INVALID_BASE64_INPUT; } return ret; } /*** Random Number Generation ***/ struct bctbx_rng_context_struct { mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; }; bctbx_rng_context_t *bctbx_rng_context_new(void) { bctbx_rng_context_t *ctx = bctbx_malloc0(sizeof(bctbx_rng_context_t)); mbedtls_entropy_init(&(ctx->entropy)); mbedtls_ctr_drbg_init(&(ctx->ctr_drbg)); mbedtls_ctr_drbg_seed(&(ctx->ctr_drbg), mbedtls_entropy_func, &(ctx->entropy), NULL, 0); return ctx; } int32_t bctbx_rng_get(bctbx_rng_context_t *context, unsigned char*output, size_t output_length) { return mbedtls_ctr_drbg_random(&(context->ctr_drbg), output, output_length); } void bctbx_rng_context_free(bctbx_rng_context_t *context) { mbedtls_ctr_drbg_free(&(context->ctr_drbg)); mbedtls_entropy_free(&(context->entropy)); bctbx_free(context); } /*** signing key ***/ bctbx_signing_key_t *bctbx_signing_key_new(void) { mbedtls_pk_context *key = bctbx_malloc0(sizeof(mbedtls_pk_context)); mbedtls_pk_init(key); return (bctbx_signing_key_t *)key; } void bctbx_signing_key_free(bctbx_signing_key_t *key) { mbedtls_pk_free((mbedtls_pk_context *)key); bctbx_free(key); } char *bctbx_signing_key_get_pem(bctbx_signing_key_t *key) { char *pem_key; if (key == NULL) return NULL; pem_key = (char *)bctbx_malloc0(4096); mbedtls_pk_write_key_pem( (mbedtls_pk_context *)key, (unsigned char *)pem_key, 4096); return pem_key; } int32_t bctbx_signing_key_parse(bctbx_signing_key_t *key, const char *buffer, size_t buffer_length, const unsigned char *password, size_t password_length) { int err; err=mbedtls_pk_parse_key((mbedtls_pk_context *)key, (const unsigned char *)buffer, buffer_length, password, password_length); if(err==0 && !mbedtls_pk_can_do((mbedtls_pk_context *)key, MBEDTLS_PK_RSA)) { err=MBEDTLS_ERR_PK_TYPE_MISMATCH; } if (err<0) { char tmp[128]; mbedtls_strerror(err,tmp,sizeof(tmp)); bctbx_error("cannot parse public key because [%s]",tmp); return BCTBX_ERROR_UNABLE_TO_PARSE_KEY; } return 0; } int32_t bctbx_signing_key_parse_file(bctbx_signing_key_t *key, const char *path, const char *password) { int err; err=mbedtls_pk_parse_keyfile((mbedtls_pk_context *)key, path, password); if(err==0 && !mbedtls_pk_can_do((mbedtls_pk_context *)key,MBEDTLS_PK_RSA)) { err=MBEDTLS_ERR_PK_TYPE_MISMATCH; } if (err<0) { char tmp[128]; mbedtls_strerror(err,tmp,sizeof(tmp)); bctbx_error("cannot parse public key because [%s]",tmp); return BCTBX_ERROR_UNABLE_TO_PARSE_KEY; } return 0; } /*** Certificate ***/ char *bctbx_x509_certificates_chain_get_pem(bctbx_x509_certificate_t *cert) { char *pem_certificate = NULL; size_t olen=0; pem_certificate = (char *)bctbx_malloc0(4096); mbedtls_pem_write_buffer("-----BEGIN CERTIFICATE-----\n", "-----END CERTIFICATE-----\n", ((mbedtls_x509_crt *)cert)->raw.p, ((mbedtls_x509_crt *)cert)->raw.len, (unsigned char*)pem_certificate, 4096, &olen ); return pem_certificate; } bctbx_x509_certificate_t *bctbx_x509_certificate_new(void) { mbedtls_x509_crt *cert = bctbx_malloc0(sizeof(mbedtls_x509_crt)); mbedtls_x509_crt_init(cert); return (bctbx_x509_certificate_t *)cert; } void bctbx_x509_certificate_free(bctbx_x509_certificate_t *cert) { mbedtls_x509_crt_free((mbedtls_x509_crt *)cert); bctbx_free(cert); } int32_t bctbx_x509_certificate_get_info_string(char *buf, size_t size, const char *prefix, const bctbx_x509_certificate_t *cert) { return mbedtls_x509_crt_info(buf, size, prefix, (mbedtls_x509_crt *)cert); } int32_t bctbx_x509_certificate_parse_file(bctbx_x509_certificate_t *cert, const char *path) { return mbedtls_x509_crt_parse_file((mbedtls_x509_crt *)cert, path); } int32_t bctbx_x509_certificate_parse_path(bctbx_x509_certificate_t *cert, const char *path) { return mbedtls_x509_crt_parse_path((mbedtls_x509_crt *)cert, path); } int32_t bctbx_x509_certificate_parse(bctbx_x509_certificate_t *cert, const char *buffer, size_t buffer_length) { return mbedtls_x509_crt_parse((mbedtls_x509_crt *)cert, (const unsigned char *)buffer, buffer_length); } int32_t bctbx_x509_certificate_get_der_length(bctbx_x509_certificate_t *cert) { if (cert!=NULL) { return (int32_t)((mbedtls_x509_crt *)cert)->raw.len; } return 0; } int32_t bctbx_x509_certificate_get_der(bctbx_x509_certificate_t *cert, unsigned char *buffer, size_t buffer_length) { if (cert==NULL) { return BCTBX_ERROR_INVALID_CERTIFICATE; } if (((mbedtls_x509_crt *)cert)->raw.len>buffer_length-1) { /* check buffer size is ok, +1 for the NULL termination added at the end */ return BCTBX_ERROR_OUTPUT_BUFFER_TOO_SMALL; } memcpy(buffer, ((mbedtls_x509_crt *)cert)->raw.p, ((mbedtls_x509_crt *)cert)->raw.len); buffer[((mbedtls_x509_crt *)cert)->raw.len] = '\0'; /* add a null termination char */ return 0; } int32_t bctbx_x509_certificate_get_subject_dn(bctbx_x509_certificate_t *cert, char *dn, size_t dn_length) { if (cert==NULL) { return BCTBX_ERROR_INVALID_CERTIFICATE; } return mbedtls_x509_dn_gets(dn, dn_length, &(((mbedtls_x509_crt *)cert)->subject)); } int32_t bctbx_x509_certificate_generate_selfsigned(const char *subject, bctbx_x509_certificate_t *certificate, bctbx_signing_key_t *pkey, char * pem, size_t pem_length) { mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; int ret; mbedtls_mpi serial; mbedtls_x509write_cert crt; char file_buffer[8192]; size_t file_buffer_len = 0; char formatted_subject[512]; /* subject may be a sip URL or linphone-dtls-default-identity, add CN= before it to make a valid name */ memcpy(formatted_subject, "CN=", 3); memcpy(formatted_subject+3, subject, strlen(subject)+1); /* +1 to get the \0 termination */ mbedtls_entropy_init( &entropy ); mbedtls_ctr_drbg_init(&ctr_drbg); if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0 ) ) != 0 ) { bctbx_error("Certificate generation can't init ctr_drbg: [-0x%x]", -ret); return BCTBX_ERROR_CERTIFICATE_GENERATION_FAIL; } /* generate 3072 bits RSA public/private key */ if ( (ret = mbedtls_pk_setup( (mbedtls_pk_context *)pkey, mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) )) != 0) { bctbx_error("Certificate generation can't init pk_ctx: [-0x%x]", -ret); return BCTBX_ERROR_CERTIFICATE_GENERATION_FAIL; } if ( ( ret = mbedtls_rsa_gen_key( mbedtls_pk_rsa( *(mbedtls_pk_context *)pkey ), mbedtls_ctr_drbg_random, &ctr_drbg, 3072, 65537 ) ) != 0) { bctbx_error("Certificate generation can't generate rsa key: [-0x%x]", -ret); return BCTBX_ERROR_CERTIFICATE_GENERATION_FAIL; } /* if there is no pem pointer, don't save the key in pem format */ if (pem!=NULL) { mbedtls_pk_write_key_pem((mbedtls_pk_context *)pkey, (unsigned char *)file_buffer, 4096); file_buffer_len = strlen(file_buffer); } /* generate the certificate */ mbedtls_x509write_crt_init( &crt ); mbedtls_x509write_crt_set_md_alg( &crt, MBEDTLS_MD_SHA256 ); mbedtls_mpi_init( &serial ); if ( (ret = mbedtls_mpi_read_string( &serial, 10, "1" ) ) != 0 ) { bctbx_error("Certificate generation can't read serial mpi: [-0x%x]", -ret); return BCTBX_ERROR_CERTIFICATE_GENERATION_FAIL; } mbedtls_x509write_crt_set_subject_key( &crt, (mbedtls_pk_context *)pkey); mbedtls_x509write_crt_set_issuer_key( &crt, (mbedtls_pk_context *)pkey); if ( (ret = mbedtls_x509write_crt_set_subject_name( &crt, formatted_subject) ) != 0) { bctbx_error("Certificate generation can't set subject name: [-0x%x]", -ret); return BCTBX_ERROR_CERTIFICATE_GENERATION_FAIL; } if ( (ret = mbedtls_x509write_crt_set_issuer_name( &crt, formatted_subject) ) != 0) { bctbx_error("Certificate generation can't set issuer name: -%x", -ret); return BCTBX_ERROR_CERTIFICATE_GENERATION_FAIL; } if ( (ret = mbedtls_x509write_crt_set_serial( &crt, &serial ) ) != 0) { bctbx_error("Certificate generation can't set serial: -%x", -ret); return BCTBX_ERROR_CERTIFICATE_GENERATION_FAIL; } mbedtls_mpi_free(&serial); if ( (ret = mbedtls_x509write_crt_set_validity( &crt, "20010101000000", "20300101000000" ) ) != 0) { bctbx_error("Certificate generation can't set validity: -%x", -ret); return BCTBX_ERROR_CERTIFICATE_GENERATION_FAIL; } /* store anyway certificate in pem format in a string even if we do not have file to write as we need it to get it in a x509_crt structure */ if ( (ret = mbedtls_x509write_crt_pem( &crt, (unsigned char *)file_buffer+file_buffer_len, 4096, mbedtls_ctr_drbg_random, &ctr_drbg ) ) != 0) { bctbx_error("Certificate generation can't write crt pem: -%x", -ret); return BCTBX_ERROR_CERTIFICATE_WRITE_PEM; } mbedtls_x509write_crt_free(&crt); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); /* copy the key+cert in pem format into the given buffer */ if (pem != NULL) { if (strlen(file_buffer)+1>pem_length) { bctbx_error("Certificate generation can't copy the certificate to pem buffer: too short [%ld] but need [%ld] bytes", (long)pem_length, (long)strlen(file_buffer)); return BCTBX_ERROR_OUTPUT_BUFFER_TOO_SMALL; } strncpy(pem, file_buffer, pem_length); } /* +1 on strlen as crt_parse in PEM format, length must include the final \0 */ if ( (ret = mbedtls_x509_crt_parse((mbedtls_x509_crt *)certificate, (unsigned char *)file_buffer, strlen(file_buffer)+1) ) != 0) { bctbx_error("Certificate generation can't parse crt pem: -%x", -ret); return BCTBX_ERROR_CERTIFICATE_PARSE_PEM; } return 0; } int32_t bctbx_x509_certificate_get_signature_hash_function(const bctbx_x509_certificate_t *certificate, bctbx_md_type_t *hash_algorithm) { mbedtls_x509_crt *crt; if (certificate == NULL) return BCTBX_ERROR_INVALID_CERTIFICATE; crt = (mbedtls_x509_crt *)certificate; switch (crt->sig_md) { case MBEDTLS_MD_SHA1: *hash_algorithm = BCTBX_MD_SHA1; break; case MBEDTLS_MD_SHA224: *hash_algorithm = BCTBX_MD_SHA224; break; case MBEDTLS_MD_SHA256: *hash_algorithm = BCTBX_MD_SHA256; break; case MBEDTLS_MD_SHA384: *hash_algorithm = BCTBX_MD_SHA384; break; case MBEDTLS_MD_SHA512: *hash_algorithm = BCTBX_MD_SHA512; break; default: *hash_algorithm = BCTBX_MD_UNDEFINED; return BCTBX_ERROR_UNSUPPORTED_HASH_FUNCTION; break; } return 0; } /* maximum length of returned buffer will be 7(SHA-512 string)+3*hash_length(64)+null char = 200 bytes */ int32_t bctbx_x509_certificate_get_fingerprint(const bctbx_x509_certificate_t *certificate, char *fingerprint, size_t fingerprint_length, bctbx_md_type_t hash_algorithm) { unsigned char buffer[64]={0}; /* buffer is max length of returned hash, which is 64 in case we use sha-512 */ size_t hash_length = 0; const char *hash_alg_string=NULL; size_t fingerprint_size = 0; mbedtls_x509_crt *crt; mbedtls_md_type_t hash_id; if (certificate == NULL) return BCTBX_ERROR_INVALID_CERTIFICATE; crt = (mbedtls_x509_crt *)certificate; /* if there is a specified hash algorithm, use it*/ switch (hash_algorithm) { case BCTBX_MD_SHA1: hash_id = MBEDTLS_MD_SHA1; break; case BCTBX_MD_SHA224: hash_id = MBEDTLS_MD_SHA224; break; case BCTBX_MD_SHA256: hash_id = MBEDTLS_MD_SHA256; break; case BCTBX_MD_SHA384: hash_id = MBEDTLS_MD_SHA384; break; case BCTBX_MD_SHA512: hash_id = MBEDTLS_MD_SHA512; break; default: /* nothing specified, use the hash algo used in the certificate signature */ hash_id = crt->sig_md; break; } /* fingerprint is a hash of the DER formated certificate (found in crt->raw.p) using the same hash function used by certificate signature */ switch (hash_id) { case MBEDTLS_MD_SHA1: mbedtls_sha1(crt->raw.p, crt->raw.len, buffer); hash_length = 20; hash_alg_string="SHA-1"; break; case MBEDTLS_MD_SHA224: mbedtls_sha256(crt->raw.p, crt->raw.len, buffer, 1); /* last argument is a boolean, indicate to output sha-224 and not sha-256 */ hash_length = 28; hash_alg_string="SHA-224"; break; case MBEDTLS_MD_SHA256: mbedtls_sha256(crt->raw.p, crt->raw.len, buffer, 0); hash_length = 32; hash_alg_string="SHA-256"; break; case MBEDTLS_MD_SHA384: mbedtls_sha512(crt->raw.p, crt->raw.len, buffer, 1); /* last argument is a boolean, indicate to output sha-384 and not sha-512 */ hash_length = 48; hash_alg_string="SHA-384"; break; case MBEDTLS_MD_SHA512: mbedtls_sha512(crt->raw.p, crt->raw.len, buffer, 1); /* last argument is a boolean, indicate to output sha-384 and not sha-512 */ hash_length = 64; hash_alg_string="SHA-512"; break; default: return BCTBX_ERROR_UNSUPPORTED_HASH_FUNCTION; break; } if (hash_length>0) { size_t i; size_t fingerprint_index = strlen(hash_alg_string); char prefix=' '; fingerprint_size=fingerprint_index+3*hash_length+1; /* fingerprint will be : hash_alg_string+' '+HEX : separated values: length is strlen(hash_alg_string)+3*hash_lenght + 1 for null termination */ if (fingerprint_lengthbuffer_size) { return BCTBX_ERROR_OUTPUT_BUFFER_TOO_SMALL; } strncpy(buffer, outputString, buffer_size); return 0; } int32_t bctbx_x509_certificate_set_flag(uint32_t *flags, uint32_t flags_to_set) { if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_EXPIRED) *flags |= MBEDTLS_X509_BADCERT_EXPIRED; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_REVOKED) *flags |= MBEDTLS_X509_BADCERT_REVOKED; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_CN_MISMATCH) *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_NOT_TRUSTED) *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_MISSING) *flags |= MBEDTLS_X509_BADCERT_MISSING; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_SKIP_VERIFY) *flags |= MBEDTLS_X509_BADCERT_SKIP_VERIFY; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_OTHER) *flags |= MBEDTLS_X509_BADCERT_OTHER; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_FUTURE) *flags |= MBEDTLS_X509_BADCERT_FUTURE; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_KEY_USAGE) *flags |= MBEDTLS_X509_BADCERT_KEY_USAGE; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_EXT_KEY_USAGE) *flags |= MBEDTLS_X509_BADCERT_EXT_KEY_USAGE; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_NS_CERT_TYPE) *flags |= MBEDTLS_X509_BADCERT_NS_CERT_TYPE; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_BAD_MD) *flags |= MBEDTLS_X509_BADCERT_BAD_MD; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_BAD_PK) *flags |= MBEDTLS_X509_BADCERT_BAD_PK; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_BAD_KEY) *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCRL_NOT_TRUSTED) *flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCRL_EXPIRED) *flags |= MBEDTLS_X509_BADCRL_EXPIRED; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCRL_FUTURE) *flags |= MBEDTLS_X509_BADCRL_FUTURE; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCRL_BAD_MD) *flags |= MBEDTLS_X509_BADCRL_BAD_MD; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCRL_BAD_PK) *flags |= MBEDTLS_X509_BADCRL_BAD_PK; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCRL_BAD_KEY) *flags |= MBEDTLS_X509_BADCRL_BAD_KEY; return 0; } uint32_t bctbx_x509_certificate_remap_flag(uint32_t flags) { uint32_t ret = 0; if (flags & MBEDTLS_X509_BADCERT_EXPIRED) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_EXPIRED; if (flags & MBEDTLS_X509_BADCERT_REVOKED) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_REVOKED; if (flags & MBEDTLS_X509_BADCERT_CN_MISMATCH) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_CN_MISMATCH; if (flags & MBEDTLS_X509_BADCERT_NOT_TRUSTED) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_NOT_TRUSTED; if (flags & MBEDTLS_X509_BADCERT_MISSING) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_MISSING; if (flags & MBEDTLS_X509_BADCERT_SKIP_VERIFY) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_SKIP_VERIFY; if (flags & MBEDTLS_X509_BADCERT_FUTURE) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_FUTURE; if (flags & MBEDTLS_X509_BADCERT_OTHER) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_OTHER; if (flags & MBEDTLS_X509_BADCERT_KEY_USAGE) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_KEY_USAGE; if (flags & MBEDTLS_X509_BADCERT_EXT_KEY_USAGE) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_EXT_KEY_USAGE; if (flags & MBEDTLS_X509_BADCERT_NS_CERT_TYPE) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_NS_CERT_TYPE; if (flags & MBEDTLS_X509_BADCERT_BAD_MD) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_BAD_MD; if (flags & MBEDTLS_X509_BADCERT_BAD_PK) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_BAD_PK; if (flags & MBEDTLS_X509_BADCERT_BAD_KEY) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_BAD_KEY; if (flags & MBEDTLS_X509_BADCRL_NOT_TRUSTED) ret |= BCTBX_CERTIFICATE_VERIFY_BADCRL_NOT_TRUSTED; if (flags & MBEDTLS_X509_BADCRL_EXPIRED) ret |= BCTBX_CERTIFICATE_VERIFY_BADCRL_EXPIRED; if (flags & MBEDTLS_X509_BADCRL_FUTURE) ret |= BCTBX_CERTIFICATE_VERIFY_BADCRL_FUTURE; if (flags & MBEDTLS_X509_BADCRL_BAD_MD) ret |= BCTBX_CERTIFICATE_VERIFY_BADCRL_BAD_MD; if (flags & MBEDTLS_X509_BADCRL_BAD_PK) ret |= BCTBX_CERTIFICATE_VERIFY_BADCRL_BAD_PK; if (flags & MBEDTLS_X509_BADCRL_BAD_KEY) ret |= BCTBX_CERTIFICATE_VERIFY_BADCRL_BAD_KEY; return ret; } int32_t bctbx_x509_certificate_unset_flag(uint32_t *flags, uint32_t flags_to_unset) { if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_EXPIRED) *flags &= ~MBEDTLS_X509_BADCERT_EXPIRED; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_REVOKED) *flags &= ~MBEDTLS_X509_BADCERT_REVOKED; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_CN_MISMATCH) *flags &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_NOT_TRUSTED) *flags &= ~MBEDTLS_X509_BADCERT_NOT_TRUSTED; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_MISSING) *flags &= ~MBEDTLS_X509_BADCERT_MISSING; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_SKIP_VERIFY) *flags &= ~MBEDTLS_X509_BADCERT_SKIP_VERIFY; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_OTHER) *flags &= ~MBEDTLS_X509_BADCERT_OTHER; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_FUTURE) *flags &= ~MBEDTLS_X509_BADCERT_FUTURE; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_KEY_USAGE) *flags &= ~MBEDTLS_X509_BADCERT_KEY_USAGE; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_EXT_KEY_USAGE) *flags &= ~MBEDTLS_X509_BADCERT_EXT_KEY_USAGE; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_NS_CERT_TYPE) *flags &= ~MBEDTLS_X509_BADCERT_NS_CERT_TYPE; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_BAD_MD) *flags &= ~MBEDTLS_X509_BADCERT_BAD_MD; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_BAD_PK) *flags &= ~MBEDTLS_X509_BADCERT_BAD_PK; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_BAD_KEY) *flags &= ~MBEDTLS_X509_BADCERT_BAD_KEY; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCRL_NOT_TRUSTED) *flags &= ~MBEDTLS_X509_BADCRL_NOT_TRUSTED; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCRL_EXPIRED) *flags &= ~MBEDTLS_X509_BADCRL_EXPIRED; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCRL_FUTURE) *flags &= ~MBEDTLS_X509_BADCRL_FUTURE; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCRL_BAD_MD) *flags &= ~MBEDTLS_X509_BADCRL_BAD_MD; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCRL_BAD_PK) *flags &= ~MBEDTLS_X509_BADCRL_BAD_PK; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCRL_BAD_KEY) *flags &= ~MBEDTLS_X509_BADCRL_BAD_KEY; return 0; } /*** Diffie-Hellman-Merkle ***/ /* initialise de DHM context according to requested algorithm */ bctbx_DHMContext_t *bctbx_CreateDHMContext(uint8_t DHMAlgo, uint8_t secretLength) { mbedtls_dhm_context *mbedtlsDhmContext; /* create the context */ bctbx_DHMContext_t *context = (bctbx_DHMContext_t *)malloc(sizeof(bctbx_DHMContext_t)); memset (context, 0, sizeof(bctbx_DHMContext_t)); /* create the mbedtls context for DHM */ mbedtlsDhmContext=(mbedtls_dhm_context *)malloc(sizeof(mbedtls_dhm_context)); memset(mbedtlsDhmContext, 0, sizeof(mbedtls_dhm_context)); context->cryptoModuleData=(void *)mbedtlsDhmContext; /* 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 BCTBX_DHM_2048: /* set P and G in the mbedtls context */ if ((mbedtls_mpi_read_string(&(mbedtlsDhmContext->P), 16, MBEDTLS_DHM_RFC3526_MODP_2048_P) != 0) || (mbedtls_mpi_read_string(&(mbedtlsDhmContext->G), 16, MBEDTLS_DHM_RFC3526_MODP_2048_G) != 0)) { return NULL; } context->primeLength=256; mbedtlsDhmContext->len=256; break; case BCTBX_DHM_3072: /* set P and G in the mbedtls context */ if ((mbedtls_mpi_read_string(&(mbedtlsDhmContext->P), 16, MBEDTLS_DHM_RFC3526_MODP_3072_P) != 0) || (mbedtls_mpi_read_string(&(mbedtlsDhmContext->G), 16, MBEDTLS_DHM_RFC3526_MODP_3072_G) != 0)) { return NULL; } context->primeLength=384; mbedtlsDhmContext->len=384; break; default: free(context); return NULL; break; } return context; } /* generate the random secret and compute the public value */ void bctbx_DHMCreatePublic(bctbx_DHMContext_t *context, int (*rngFunction)(void *, uint8_t *, size_t), void *rngContext) { /* get the mbedtls context */ mbedtls_dhm_context *mbedtlsContext = (mbedtls_dhm_context *)context->cryptoModuleData; /* allocate output buffer */ context->self = (uint8_t *)malloc(context->primeLength*sizeof(uint8_t)); mbedtls_dhm_make_public(mbedtlsContext, context->secretLength, context->self, context->primeLength, (int (*)(void *, unsigned char *, size_t))rngFunction, rngContext); } /* compute secret - the ->peer field of context must have been set before calling this function */ void bctbx_DHMComputeSecret(bctbx_DHMContext_t *context, int (*rngFunction)(void *, uint8_t *, size_t), void *rngContext) { size_t keyLength; uint8_t sharedSecretBuffer[384]; /* longest shared secret available in these mode */ /* import the peer public value G^Y mod P in the mbedtls dhm context */ mbedtls_dhm_read_public((mbedtls_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 and reset the key buffer */ memset(context->key,0, keyLength); mbedtls_dhm_calc_secret((mbedtls_dhm_context *)(context->cryptoModuleData), sharedSecretBuffer, 384, &keyLength, (int (*)(void *, unsigned char *, size_t))rngFunction, rngContext); /* now copy the resulting secret in the correct place in buffer(result may actually miss some front zero bytes, real length of output is now in keyLength but we want primeLength bytes) */ memcpy(context->key+(context->primeLength-keyLength), sharedSecretBuffer, keyLength); memset(sharedSecretBuffer, 0, 384); /* purge secret from temporary buffer */ } /* clean DHM context */ void bctbx_DestroyDHMContext(bctbx_DHMContext_t *context) { if (context!= NULL) { /* key and secret must be erased from memory and not just freed */ if (context->secret != NULL) { memset(context->secret, 0, context->secretLength); free(context->secret); } free(context->self); if (context->key != NULL) { memset(context->key, 0, context->primeLength); free(context->key); } free(context->peer); mbedtls_dhm_free((mbedtls_dhm_context *)context->cryptoModuleData); free(context->cryptoModuleData); free(context); } } /*** SSL Client ***/ /* * Default profile used to configure ssl_context, allow 1024 bits keys(while mbedtls default is 2048) */ const mbedtls_x509_crt_profile bctbx_x509_crt_profile_default = { /* Hashes from SHA-1 and above */ MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) | MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_RIPEMD160 ) | MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) | MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), 0xFFFFFFF, /* Any PK alg */ 0xFFFFFFF, /* Any curve */ 1024, }; /** context **/ struct bctbx_ssl_context_struct { mbedtls_ssl_context ssl_ctx; int(*callback_cli_cert_function)(void *, bctbx_ssl_context_t *, unsigned char *, size_t); /**< pointer to the callback called to update client certificate during handshake callback params are user_data, ssl_context, certificate distinguished name, name length */ void *callback_cli_cert_data; /**< data passed to the client cert callback */ int(*callback_send_function)(void *, const unsigned char *, size_t); /* callbacks args are: callback data, data buffer to be send, size of data buffer */ int(*callback_recv_function)(void *, unsigned char *, size_t); /* args: callback data, data buffer to be read, size of data buffer */ void *callback_sendrecv_data; /**< data passed to send/recv callbacks */ mbedtls_timing_delay_context timer; /**< a timer is requested for DTLS */ }; bctbx_ssl_context_t *bctbx_ssl_context_new(void) { bctbx_ssl_context_t *ssl_ctx = bctbx_malloc0(sizeof(bctbx_ssl_context_t)); mbedtls_ssl_init(&(ssl_ctx->ssl_ctx)); ssl_ctx->callback_cli_cert_function = NULL; ssl_ctx->callback_cli_cert_data = NULL; ssl_ctx->callback_send_function = NULL; ssl_ctx->callback_recv_function = NULL; ssl_ctx->callback_sendrecv_data = NULL; return ssl_ctx; } void bctbx_ssl_context_free(bctbx_ssl_context_t *ssl_ctx) { mbedtls_ssl_free(&(ssl_ctx->ssl_ctx)); bctbx_free(ssl_ctx); } int32_t bctbx_ssl_close_notify(bctbx_ssl_context_t *ssl_ctx) { return mbedtls_ssl_close_notify(&(ssl_ctx->ssl_ctx)); } int32_t bctbx_ssl_session_reset(bctbx_ssl_context_t *ssl_ctx) { return mbedtls_ssl_session_reset(&(ssl_ctx->ssl_ctx)); } int32_t bctbx_ssl_write(bctbx_ssl_context_t *ssl_ctx, const unsigned char *buf, size_t buf_length) { int ret = mbedtls_ssl_write(&(ssl_ctx->ssl_ctx), buf, buf_length); /* remap some output code */ if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) { ret = BCTBX_ERROR_NET_WANT_WRITE; } return ret; } int32_t bctbx_ssl_read(bctbx_ssl_context_t *ssl_ctx, unsigned char *buf, size_t buf_length) { int ret = mbedtls_ssl_read(&(ssl_ctx->ssl_ctx), buf, buf_length); /* remap some output code */ if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { ret = BCTBX_ERROR_SSL_PEER_CLOSE_NOTIFY; } if (ret == MBEDTLS_ERR_SSL_WANT_READ) { ret = BCTBX_ERROR_NET_WANT_READ; } return ret; } int32_t bctbx_ssl_handshake(bctbx_ssl_context_t *ssl_ctx) { int ret = 0; while( ssl_ctx->ssl_ctx.state != MBEDTLS_SSL_HANDSHAKE_OVER ) { ret = mbedtls_ssl_handshake_step(&(ssl_ctx->ssl_ctx)); if( ret != 0 ) { break; } /* insert the callback function for client certificate request */ if (ssl_ctx->callback_cli_cert_function != NULL) { /* check we have a callback function */ /* when in state SSL_CLIENT_CERTIFICATE - which means, next call to ssl_handshake_step will send the client certificate to server - * and the client_auth flag is set - which means the server requested a client certificate - */ if (ssl_ctx->ssl_ctx.state == MBEDTLS_SSL_CLIENT_CERTIFICATE && ssl_ctx->ssl_ctx.client_auth > 0) { /* TODO: retrieve certificate dn during handshake from server certificate request * for now the dn params in the callback are set to NULL and 0(dn string length) */ if (ssl_ctx->callback_cli_cert_function(ssl_ctx->callback_cli_cert_data, ssl_ctx, NULL, 0)!=0) { if((ret=mbedtls_ssl_send_alert_message(&(ssl_ctx->ssl_ctx), MBEDTLS_SSL_ALERT_LEVEL_FATAL, MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE)) != 0 ) return( ret ); } } } } /* remap some output codes */ if (ret == MBEDTLS_ERR_SSL_WANT_READ) { ret = BCTBX_ERROR_NET_WANT_READ; } else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) { ret = BCTBX_ERROR_NET_WANT_WRITE; } return(ret); } int32_t bctbx_ssl_set_hs_own_cert(bctbx_ssl_context_t *ssl_ctx, bctbx_x509_certificate_t *cert, bctbx_signing_key_t *key) { /* WARNING Dirty-Dirty trick : in mbedtls ssl_set_hs_own_cert shall be caller on server side only for SNI, there is no real equivalent on client side yet */ /* If we are server call the regular function */ if (ssl_ctx->ssl_ctx.conf->endpoint == MBEDTLS_SSL_IS_SERVER ) { return mbedtls_ssl_set_hs_own_cert(&(ssl_ctx->ssl_ctx) , (mbedtls_x509_crt *)cert , (mbedtls_pk_context *)key); } else { /* if we are client, call the conf function on the function in use inside the ssl_context, dirty but it works for now */ return mbedtls_ssl_conf_own_cert((mbedtls_ssl_config *)ssl_ctx->ssl_ctx.conf , (mbedtls_x509_crt *)cert , (mbedtls_pk_context *)key); } } int bctbx_ssl_send_callback(void *data, const unsigned char *buffer, size_t buffer_length) { int ret = 0; /* data is the ssl_context which contains the actual callback and data */ bctbx_ssl_context_t *ssl_ctx = (bctbx_ssl_context_t *)data; ret = ssl_ctx->callback_send_function(ssl_ctx->callback_sendrecv_data, buffer, buffer_length); return bctbx_ssl_sendrecv_callback_return_remap(ret); } int bctbx_ssl_recv_callback(void *data, unsigned char *buffer, size_t buffer_length) { int ret = 0; /* data is the ssl_context which contains the actual callback and data */ bctbx_ssl_context_t *ssl_ctx = (bctbx_ssl_context_t *)data; ret = ssl_ctx->callback_recv_function(ssl_ctx->callback_sendrecv_data, buffer, buffer_length); return bctbx_ssl_sendrecv_callback_return_remap(ret); } void bctbx_ssl_set_io_callbacks(bctbx_ssl_context_t *ssl_ctx, void *callback_data, int(*callback_send_function)(void *, const unsigned char *, size_t), /* callbacks args are: callback data, data buffer to be send, size of data buffer */ int(*callback_recv_function)(void *, unsigned char *, size_t)){ /* args: callback data, data buffer to be read, size of data buffer */ if (ssl_ctx==NULL) { return; } ssl_ctx->callback_send_function = callback_send_function; ssl_ctx->callback_recv_function = callback_recv_function; ssl_ctx->callback_sendrecv_data = callback_data; mbedtls_ssl_set_bio(&(ssl_ctx->ssl_ctx), ssl_ctx, bctbx_ssl_send_callback, bctbx_ssl_recv_callback, NULL); } const bctbx_x509_certificate_t *bctbx_ssl_get_peer_certificate(bctbx_ssl_context_t *ssl_ctx) { return (const bctbx_x509_certificate_t *)mbedtls_ssl_get_peer_cert(&(ssl_ctx->ssl_ctx)); } const char *bctbx_ssl_get_ciphersuite(bctbx_ssl_context_t *ssl_ctx){ return mbedtls_ssl_get_ciphersuite(&(ssl_ctx->ssl_ctx)); } const char *bctbx_ssl_get_version(bctbx_ssl_context_t *ssl_ctx){ return mbedtls_ssl_get_version(&(ssl_ctx->ssl_ctx)); } int32_t bctbx_ssl_set_hostname(bctbx_ssl_context_t *ssl_ctx, const char *hostname){ return mbedtls_ssl_set_hostname(&(ssl_ctx->ssl_ctx), hostname); } /** DTLS SRTP functions **/ #ifdef HAVE_DTLS_SRTP uint8_t bctbx_dtls_srtp_supported(void) { return 1; } static bctbx_dtls_srtp_profile_t bctbx_srtp_profile_mbedtls2bctoolbox(enum mbedtls_DTLS_SRTP_protection_profiles mbedtls_profile) { switch (mbedtls_profile) { case MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_80: return BCTBX_SRTP_AES128_CM_HMAC_SHA1_80; case MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_32: return BCTBX_SRTP_AES128_CM_HMAC_SHA1_32; case MBEDTLS_SRTP_NULL_HMAC_SHA1_80: return BCTBX_SRTP_NULL_HMAC_SHA1_80; case MBEDTLS_SRTP_NULL_HMAC_SHA1_32: return BCTBX_SRTP_NULL_HMAC_SHA1_32; default: return BCTBX_SRTP_UNDEFINED; } } static enum mbedtls_DTLS_SRTP_protection_profiles bctbx_srtp_profile_bctoolbox2mbedtls(bctbx_dtls_srtp_profile_t bctbx_profile) { switch (bctbx_profile) { case BCTBX_SRTP_AES128_CM_HMAC_SHA1_80: return MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_80; case BCTBX_SRTP_AES128_CM_HMAC_SHA1_32: return MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_32; case BCTBX_SRTP_NULL_HMAC_SHA1_80: return MBEDTLS_SRTP_NULL_HMAC_SHA1_80; case BCTBX_SRTP_NULL_HMAC_SHA1_32: return MBEDTLS_SRTP_NULL_HMAC_SHA1_32; default: return MBEDTLS_SRTP_UNSET_PROFILE; } } bctbx_dtls_srtp_profile_t bctbx_ssl_get_dtls_srtp_protection_profile(bctbx_ssl_context_t *ssl_ctx) { if (ssl_ctx==NULL) { return BCTBX_ERROR_INVALID_SSL_CONTEXT; } return bctbx_srtp_profile_mbedtls2bctoolbox(mbedtls_ssl_get_dtls_srtp_protection_profile(&(ssl_ctx->ssl_ctx))); }; int32_t bctbx_ssl_get_dtls_srtp_key_material(bctbx_ssl_context_t *ssl_ctx, char *output, size_t *output_length) { int ret = 0; if (ssl_ctx==NULL) { return BCTBX_ERROR_INVALID_SSL_CONTEXT; } ret = mbedtls_ssl_get_dtls_srtp_key_material(&(ssl_ctx->ssl_ctx), (unsigned char *)output, *output_length, output_length); /* remap the output error code */ if (ret == MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL) { return BCTBX_ERROR_OUTPUT_BUFFER_TOO_SMALL; } return 0; } #else /* HAVE_DTLS_SRTP */ /* dummy DTLS api when not available */ uint8_t bctbx_dtls_srtp_supported(void) { return 0; } bctbx_dtls_srtp_profile_t bctbx_ssl_get_dtls_srtp_protection_profile(bctbx_ssl_context_t *ssl_ctx) { return BCTBX_SRTP_UNDEFINED; } int32_t bctbx_ssl_get_dtls_srtp_key_material(bctbx_ssl_context_t *ssl_ctx, char *output, size_t *output_length) { *output_length = 0; return BCTBX_ERROR_UNAVAILABLE_FUNCTION; } #endif /* HAVE_DTLS_SRTP */ /** DTLS SRTP functions **/ /** config **/ struct bctbx_ssl_config_struct { mbedtls_ssl_config *ssl_config; /**< actual config structure */ uint8_t ssl_config_externally_provided; /**< a flag, on when the ssl_config was provided by callers and not created threw the new function */ int(*callback_cli_cert_function)(void *, bctbx_ssl_context_t *, unsigned char *, size_t); /**< pointer to the callback called to update client certificate during handshake callback params are user_data, ssl_context, certificate distinguished name, name length */ void *callback_cli_cert_data; /**< data passed to the client cert callback */ }; bctbx_ssl_config_t *bctbx_ssl_config_new(void) { bctbx_ssl_config_t *ssl_config = bctbx_malloc0(sizeof(bctbx_ssl_config_t)); /* allocate and init anyway a ssl_config, it may be then crashed by an externally provided one */ ssl_config->ssl_config = bctbx_malloc0(sizeof(mbedtls_ssl_config)); ssl_config->ssl_config_externally_provided = 0; mbedtls_ssl_config_init(ssl_config->ssl_config); ssl_config->callback_cli_cert_function = NULL; ssl_config->callback_cli_cert_data = NULL; return ssl_config; } int32_t bctbx_ssl_config_set_crypto_library_config(bctbx_ssl_config_t *ssl_config, void *internal_config) { if (ssl_config == NULL) { return BCTBX_ERROR_INVALID_SSL_CONFIG; } /* free already existing structure */ if (ssl_config->ssl_config != NULL && ssl_config->ssl_config_externally_provided==0) { mbedtls_ssl_config_free(ssl_config->ssl_config); bctbx_free(ssl_config->ssl_config); } /* set the given pointer as the ssl_config context */ ssl_config->ssl_config = (mbedtls_ssl_config *)internal_config; /* set the flag in order to not free the mbedtls config when freing bctbx_ssl_config */ ssl_config->ssl_config_externally_provided = 1; return 0; } void bctbx_ssl_config_free(bctbx_ssl_config_t *ssl_config) { if (ssl_config == NULL) { return; } /* free mbedtls_ssl_config only when created internally */ if (ssl_config->ssl_config_externally_provided==0) { mbedtls_ssl_config_free(ssl_config->ssl_config); bctbx_free(ssl_config->ssl_config); } bctbx_free(ssl_config); } int32_t bctbx_ssl_config_defaults(bctbx_ssl_config_t *ssl_config, int endpoint, int transport) { int mbedtls_endpoint, mbedtls_transport, ret; if (ssl_config == NULL) { return BCTBX_ERROR_INVALID_SSL_CONFIG; } /* remap input arguments */ switch (endpoint) { case BCTBX_SSL_IS_CLIENT: mbedtls_endpoint = MBEDTLS_SSL_IS_CLIENT; break; case BCTBX_SSL_IS_SERVER: mbedtls_endpoint = MBEDTLS_SSL_IS_SERVER; break; default: return BCTBX_ERROR_INVALID_INPUT_DATA; } switch (transport) { case BCTBX_SSL_TRANSPORT_STREAM: mbedtls_transport = MBEDTLS_SSL_TRANSPORT_STREAM; break; case BCTBX_SSL_TRANSPORT_DATAGRAM: mbedtls_transport = MBEDTLS_SSL_TRANSPORT_DATAGRAM; break; default: return BCTBX_ERROR_INVALID_INPUT_DATA; } ret = mbedtls_ssl_config_defaults(ssl_config->ssl_config, mbedtls_endpoint, mbedtls_transport, MBEDTLS_SSL_PRESET_DEFAULT); if (ret <0) { return ret; } /* Set the default x509 security profile used for verification of all certificate in chain */ mbedtls_ssl_conf_cert_profile(ssl_config->ssl_config, &bctbx_x509_crt_profile_default); return ret; } int32_t bctbx_ssl_config_set_endpoint(bctbx_ssl_config_t *ssl_config, int endpoint) { int mbedtls_endpoint; if (ssl_config == NULL) { return BCTBX_ERROR_INVALID_SSL_CONFIG; } /* remap input arguments */ switch (endpoint) { case BCTBX_SSL_IS_CLIENT: mbedtls_endpoint = MBEDTLS_SSL_IS_CLIENT; break; case BCTBX_SSL_IS_SERVER: mbedtls_endpoint = MBEDTLS_SSL_IS_SERVER; break; default: return BCTBX_ERROR_INVALID_INPUT_DATA; } mbedtls_ssl_conf_endpoint(ssl_config->ssl_config, mbedtls_endpoint); return 0; } int32_t bctbx_ssl_config_set_transport (bctbx_ssl_config_t *ssl_config, int transport) { int mbedtls_transport; if (ssl_config == NULL) { return BCTBX_ERROR_INVALID_SSL_CONFIG; } /* remap input arguments */ switch (transport) { case BCTBX_SSL_TRANSPORT_STREAM: mbedtls_transport = MBEDTLS_SSL_TRANSPORT_STREAM; break; case BCTBX_SSL_TRANSPORT_DATAGRAM: mbedtls_transport = MBEDTLS_SSL_TRANSPORT_DATAGRAM; break; default: return BCTBX_ERROR_INVALID_INPUT_DATA; } mbedtls_ssl_conf_transport(ssl_config->ssl_config, mbedtls_transport); return 0; } int32_t bctbx_ssl_config_set_authmode(bctbx_ssl_config_t *ssl_config, int authmode) { int mbedtls_authmode; if (ssl_config == NULL) { return BCTBX_ERROR_INVALID_SSL_CONFIG; } /* remap input arguments */ switch (authmode) { case BCTBX_SSL_VERIFY_NONE: mbedtls_authmode = MBEDTLS_SSL_VERIFY_NONE; break; case BCTBX_SSL_VERIFY_OPTIONAL: mbedtls_authmode = MBEDTLS_SSL_VERIFY_OPTIONAL; break; case BCTBX_SSL_VERIFY_REQUIRED: mbedtls_authmode = MBEDTLS_SSL_VERIFY_REQUIRED; break; default: return BCTBX_ERROR_INVALID_SSL_AUTHMODE; break; } mbedtls_ssl_conf_authmode(ssl_config->ssl_config, mbedtls_authmode); return 0; } int32_t bctbx_ssl_config_set_rng(bctbx_ssl_config_t *ssl_config, int(*rng_function)(void *, unsigned char *, size_t), void *rng_context) { if (ssl_config == NULL) { return BCTBX_ERROR_INVALID_SSL_CONFIG; } mbedtls_ssl_conf_rng(ssl_config->ssl_config, rng_function, rng_context); return 0; } int32_t bctbx_ssl_config_set_callback_verify(bctbx_ssl_config_t *ssl_config, int(*callback_function)(void *, bctbx_x509_certificate_t *, int, uint32_t *), void *callback_data) { if (ssl_config == NULL) { return BCTBX_ERROR_INVALID_SSL_CONFIG; } mbedtls_ssl_conf_verify(ssl_config->ssl_config, (int(*)(void *, mbedtls_x509_crt*, int, uint32_t *))callback_function, callback_data); return 0; } int32_t bctbx_ssl_config_set_callback_cli_cert(bctbx_ssl_config_t *ssl_config, int(*callback_function)(void *, bctbx_ssl_context_t *, unsigned char *, size_t), void *callback_data) { if (ssl_config == NULL) { return BCTBX_ERROR_INVALID_SSL_CONFIG; } ssl_config->callback_cli_cert_function = callback_function; ssl_config->callback_cli_cert_data = callback_data; return 0; } int32_t bctbx_ssl_config_set_ca_chain(bctbx_ssl_config_t *ssl_config, bctbx_x509_certificate_t *ca_chain) { if (ssl_config == NULL) { return BCTBX_ERROR_INVALID_SSL_CONFIG; } /* ca_crl (arg 3) is always set to null, add the functionnality if needed */ mbedtls_ssl_conf_ca_chain(ssl_config->ssl_config, (mbedtls_x509_crt *)ca_chain, NULL); return 0; } int32_t bctbx_ssl_config_set_own_cert(bctbx_ssl_config_t *ssl_config, bctbx_x509_certificate_t *cert, bctbx_signing_key_t *key) { if (ssl_config == NULL) { return BCTBX_ERROR_INVALID_SSL_CONFIG; } return mbedtls_ssl_conf_own_cert(ssl_config->ssl_config, (mbedtls_x509_crt *)cert, (mbedtls_pk_context *)key); } /** DTLS SRTP functions **/ #ifdef HAVE_DTLS_SRTP int32_t bctbx_ssl_config_set_dtls_srtp_protection_profiles(bctbx_ssl_config_t *ssl_config, const bctbx_dtls_srtp_profile_t *profiles, size_t profiles_number) { size_t i; enum mbedtls_DTLS_SRTP_protection_profiles dtls_srtp_mbedtls_profiles[4]; if (ssl_config == NULL) { return BCTBX_ERROR_INVALID_SSL_CONFIG; } /* convert the profiles array into a mbedtls profiles array */ for (i=0; issl_config, dtls_srtp_mbedtls_profiles, profiles_number); } #else /* HAVE_DTLS_SRTP */ int32_t bctbx_ssl_config_set_dtls_srtp_protection_profiles(bctbx_ssl_config_t *ssl_config, const bctbx_dtls_srtp_profile_t *profiles, size_t profiles_number) { return BCTBX_ERROR_UNAVAILABLE_FUNCTION; } #endif /* HAVE_DTLS_SRTP */ /** DTLS SRTP functions **/ int32_t bctbx_ssl_context_setup(bctbx_ssl_context_t *ssl_ctx, bctbx_ssl_config_t *ssl_config) { int ret; /* Check validity of context and config */ if (ssl_config == NULL) { return BCTBX_ERROR_INVALID_SSL_CONFIG; } if (ssl_ctx == NULL) { return BCTBX_ERROR_INVALID_SSL_CONTEXT; } /* apply all valids settings to the ssl_context */ if (ssl_config->callback_cli_cert_function != NULL) { ssl_ctx->callback_cli_cert_function = ssl_config->callback_cli_cert_function; ssl_ctx->callback_cli_cert_data = ssl_config->callback_cli_cert_data; } #ifdef HAVE_DTLS_SRTP /* We do not use DTLS SRTP cookie, so we must set to NULL the callbacks. Cookies are used to prevent DoS attack but our server is on only when during a brief period so we do not need this */ mbedtls_ssl_conf_dtls_cookies(ssl_config->ssl_config, NULL, NULL, NULL); #endif /* HAVE_DTLS_SRTP */ ret = mbedtls_ssl_setup(&(ssl_ctx->ssl_ctx), ssl_config->ssl_config); if (ret != 0) return ret; /* for DTLS handshake, we must set a timer callback */ mbedtls_ssl_set_timer_cb(&(ssl_ctx->ssl_ctx), &(ssl_ctx->timer), mbedtls_timing_set_delay, mbedtls_timing_get_delay); return ret; } /*****************************************************************************/ /***** Hashing *****/ /*****************************************************************************/ /* * 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 bctbx_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]; mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), key, keyLength, input, inputLength, hmacOutput); /* check output length, can't be>32 */ if (hmacLength>32) { memcpy(output, hmacOutput, 32); } else { memcpy(output, hmacOutput, hmacLength); } } /* * @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 bctbx_sha256(const uint8_t *input, size_t inputLength, uint8_t hashLength, uint8_t *output) { uint8_t hashOutput[32]; mbedtls_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); } } /* * @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 bctbx_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]; mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), key, keyLength, input, inputLength, hmacOutput); /* check output length, can't be>20 */ if (hmacLength>20) { memcpy(output, hmacOutput, 20); } else { memcpy(output, hmacOutput, hmacLength); } } /** * @brief MD5 wrapper * output = md5(input) * @param[in] input Input data buffer * @param[in] inputLength Input data length in bytes * @param[out] output Output data buffer. * */ void bctbx_md5(const uint8_t *input, size_t inputLength, uint8_t output[16]) { mbedtls_md5(input, inputLength, output); } /*****************************************************************************/ /***** Encryption/Decryption *****/ /*****************************************************************************/ /***** GCM *****/ /** * @Brief AES-GCM encrypt and tag buffer * * @param[in] key Encryption key * @param[in] keyLength Key buffer length, in bytes, must be 16,24 or 32 * @param[in] plainText Buffer to be encrypted * @param[in] plainTextLength Length in bytes of buffer to be encrypted * @param[in] authenticatedData Buffer holding additional data to be used in tag computation * @param[in] authenticatedDataLength Additional data length in bytes * @param[in] initializationVector Buffer holding the initialisation vector * @param[in] initializationVectorLength Initialisation vector length in bytes * @param[out] tag Buffer holding the generated tag * @param[in] tagLength Requested length for the generated tag * @param[out] output Buffer holding the output, shall be at least the length of plainText buffer */ int32_t bctbx_aes_gcm_encrypt_and_tag(const uint8_t *key, size_t keyLength, const uint8_t *plainText, size_t plainTextLength, const uint8_t *authenticatedData, size_t authenticatedDataLength, const uint8_t *initializationVector, size_t initializationVectorLength, uint8_t *tag, size_t tagLength, uint8_t *output) { mbedtls_gcm_context gcmContext; int ret; mbedtls_gcm_init(&gcmContext); ret = mbedtls_gcm_setkey(&gcmContext, MBEDTLS_CIPHER_ID_AES, key, (unsigned int)keyLength*8); if (ret != 0) return ret; ret = mbedtls_gcm_crypt_and_tag(&gcmContext, MBEDTLS_GCM_ENCRYPT, plainTextLength, initializationVector, initializationVectorLength, authenticatedData, authenticatedDataLength, plainText, output, tagLength, tag); mbedtls_gcm_free(&gcmContext); return ret; } /** * @Brief AES-GCM decrypt, compute authentication tag and compare it to the one provided * * @param[in] key Encryption key * @param[in] keyLength Key buffer length, in bytes, must be 16,24 or 32 * @param[in] cipherText Buffer to be decrypted * @param[in] cipherTextLength Length in bytes of buffer to be decrypted * @param[in] authenticatedData Buffer holding additional data to be used in auth tag computation * @param[in] authenticatedDataLength Additional data length in bytes * @param[in] initializationVector Buffer holding the initialisation vector * @param[in] initializationVectorLength Initialisation vector length in bytes * @param[in] tag Buffer holding the authentication tag * @param[in] tagLength Length in bytes for the authentication tag * @param[out] output Buffer holding the output, shall be at least the length of cipherText buffer * * @return 0 on succes, BCTBX_ERROR_AUTHENTICATION_FAILED if tag doesn't match or mbedtls error code */ int32_t bctbx_aes_gcm_decrypt_and_auth(const uint8_t *key, size_t keyLength, const uint8_t *cipherText, size_t cipherTextLength, const uint8_t *authenticatedData, size_t authenticatedDataLength, const uint8_t *initializationVector, size_t initializationVectorLength, const uint8_t *tag, size_t tagLength, uint8_t *output) { mbedtls_gcm_context gcmContext; int ret; mbedtls_gcm_init(&gcmContext); ret = mbedtls_gcm_setkey(&gcmContext, MBEDTLS_CIPHER_ID_AES, key, (unsigned int)keyLength*8); if (ret != 0) return ret; ret = mbedtls_gcm_auth_decrypt(&gcmContext, cipherTextLength, initializationVector, initializationVectorLength, authenticatedData, authenticatedDataLength, tag, tagLength, cipherText, output); mbedtls_gcm_free(&gcmContext); if (ret == MBEDTLS_ERR_GCM_AUTH_FAILED) { return BCTBX_ERROR_AUTHENTICATION_FAILED; } return ret; } /** * @Brief create and initialise an AES-GCM encryption context * * @param[in] key encryption key * @param[in] keyLength key buffer length, in bytes, must be 16,24 or 32 * @param[in] authenticatedData Buffer holding additional data to be used in tag computation (can be NULL) * @param[in] authenticatedDataLength additional data length in bytes (can be 0) * @param[in] initializationVector Buffer holding the initialisation vector * @param[in] initializationVectorLength Initialisation vector length in bytes * @param[in] mode Operation mode : BCTBX_GCM_ENCRYPT or BCTBX_GCM_DECRYPT * * @return 0 on success, crypto library error code otherwise */ bctbx_aes_gcm_context_t *bctbx_aes_gcm_context_new(const uint8_t *key, size_t keyLength, const uint8_t *authenticatedData, size_t authenticatedDataLength, const uint8_t *initializationVector, size_t initializationVectorLength, uint8_t mode) { int ret = 0; int mbedtls_mode; mbedtls_gcm_context *ctx = NULL; if (mode == BCTBX_GCM_ENCRYPT) { mbedtls_mode = MBEDTLS_GCM_ENCRYPT; } else if ( mode == BCTBX_GCM_DECRYPT) { mbedtls_mode = MBEDTLS_GCM_DECRYPT; } else { return NULL; } ctx = bctbx_malloc0(sizeof(mbedtls_gcm_context)); mbedtls_gcm_init(ctx); ret = mbedtls_gcm_setkey(ctx, MBEDTLS_CIPHER_ID_AES, key, (unsigned int)keyLength*8); if (ret != 0) { bctbx_free(ctx); return NULL; } ret = mbedtls_gcm_starts(ctx, mbedtls_mode, initializationVector, initializationVectorLength, authenticatedData, authenticatedDataLength); if (ret != 0) { bctbx_free(ctx); return NULL; } return (bctbx_aes_gcm_context_t *)ctx; } /** * @Brief AES-GCM encrypt or decrypt a chunk of data * * @param[in/out] context a context already initialized using bctbx_aes_gcm_context_new * @param[in] input buffer holding the input data * @param[in] inputLength lenght of the input data * @param[out] output buffer to store the output data (same length as input one) * * @return 0 on success, crypto library error code otherwise */ int32_t bctbx_aes_gcm_process_chunk(bctbx_aes_gcm_context_t *context, const uint8_t *input, size_t inputLength, uint8_t *output) { return mbedtls_gcm_update((mbedtls_gcm_context *)context, inputLength, input, output); } /** * @Brief Conclude a AES-GCM encryption stream, generate tag if requested, free resources * * @param[in/out] context a context already initialized using bctbx_aes_gcm_context_new * @param[out] tag a buffer to hold the authentication tag. Can be NULL if tagLength is 0 * @param[in] tagLength length of reqested authentication tag, max 16 * * @return 0 on success, crypto library error code otherwise */ int32_t bctbx_aes_gcm_finish(bctbx_aes_gcm_context_t *context, uint8_t *tag, size_t tagLength) { int ret; ret = mbedtls_gcm_finish((mbedtls_gcm_context *)context, tag, tagLength); mbedtls_gcm_free((mbedtls_gcm_context *)context); bctbx_free(context); return ret; } /* * @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 bctbx_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 mbedtls */ mbedtls_aes_context context; memset (&context, 0, sizeof(mbedtls_aes_context)); /* make a local copy of IV which is modified by the mbedtls AES-CFB function */ memcpy(IVbuffer, IV, 16*sizeof(uint8_t)); /* initialise the aes context and key */ mbedtls_aes_setkey_enc(&context, key, 128); /* encrypt */ mbedtls_aes_crypt_cfb128 (&context, MBEDTLS_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 bctbx_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 mbedtls */ mbedtls_aes_context context; memset (&context, 0, sizeof(mbedtls_aes_context)); /* make a local copy of IV which is modified by the mbedtls 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 */ mbedtls_aes_setkey_enc(&context, key, 128); /* encrypt */ mbedtls_aes_crypt_cfb128 (&context, MBEDTLS_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 bctbx_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; mbedtls_aes_context context; memcpy(IVbuffer, IV, 16*sizeof(uint8_t)); memset (&context, 0, sizeof(mbedtls_aes_context)); mbedtls_aes_setkey_enc(&context, key, 256); /* encrypt */ mbedtls_aes_crypt_cfb128 (&context, MBEDTLS_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 bctbx_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; mbedtls_aes_context context; memcpy(IVbuffer, IV, 16*sizeof(uint8_t)); memset (&context, 0, sizeof(mbedtls_aes_context)); mbedtls_aes_setkey_enc(&context, key, 256); /* decrypt */ mbedtls_aes_crypt_cfb128 (&context, MBEDTLS_AES_DECRYPT, inputLength, &iv_offset, IVbuffer, input, output); } bctoolbox-0.6.0/src/crypto/polarssl.c000066400000000000000000001515101313410701300176160ustar00rootroot00000000000000/* crypto_polarssl.c Copyright (C) 2016 Belledonne Communications SARL This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "utils.h" #include #include #include #include #include "polarssl/base64.h" #include #include #include #include #include #include #include #include #include "bctoolbox/logging.h" #ifdef _WIN32 #define snprintf _snprintf #endif static int bctbx_ssl_sendrecv_callback_return_remap(int32_t ret_code) { switch (ret_code) { case BCTBX_ERROR_NET_WANT_READ: return POLARSSL_ERR_NET_WANT_READ; case BCTBX_ERROR_NET_WANT_WRITE: return POLARSSL_ERR_NET_WANT_WRITE; case BCTBX_ERROR_NET_CONN_RESET: return POLARSSL_ERR_NET_CONN_RESET; default: return (int)ret_code; } } void bctbx_strerror(int32_t error_code, char *buffer, size_t buffer_length) { if (error_code>0) { snprintf(buffer, buffer_length, "%s", "Invalid Error code"); return ; } /* polarssl error code are all negatived and bas smaller than 0x0000F000 */ /* bctoolbox defined error codes are all in format -0x7XXXXXXX */ if (-error_code<0x00010000) { /* it's a polarssl error code */ error_strerror(error_code, buffer, buffer_length); return; } snprintf(buffer, buffer_length, "%s [-0x%x]", "bctoolbox defined error code", -error_code); return; } int32_t bctbx_base64_encode(unsigned char *output, size_t *output_length, const unsigned char *input, size_t input_length) { int ret = base64_encode(output, output_length, input, input_length); if (ret == POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL) { return BCTBX_ERROR_OUTPUT_BUFFER_TOO_SMALL; } return ret; } int32_t bctbx_base64_decode(unsigned char *output, size_t *output_length, const unsigned char *input, size_t input_length) { int ret = base64_decode(output, output_length, input, input_length); if (ret == POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL) { return BCTBX_ERROR_OUTPUT_BUFFER_TOO_SMALL; } if (ret == POLARSSL_ERR_BASE64_INVALID_CHARACTER) { return BCTBX_ERROR_INVALID_BASE64_INPUT; } return ret; } /*** Random Number Generation ***/ struct bctbx_rng_context_struct { entropy_context entropy; ctr_drbg_context ctr_drbg; }; bctbx_rng_context_t *bctbx_rng_context_new(void) { bctbx_rng_context_t *ctx = bctbx_malloc0(sizeof(bctbx_rng_context_t)); entropy_init(&(ctx->entropy)); ctr_drbg_init(&(ctx->ctr_drbg), entropy_func, &(ctx->entropy), NULL, 0); return ctx; } int32_t bctbx_rng_get(bctbx_rng_context_t *context, unsigned char*output, size_t output_length) { return ctr_drbg_random(&(context->ctr_drbg), output, output_length); } void bctbx_rng_context_free(bctbx_rng_context_t *context) { /* ctr_drg_free function is available from polarssl1.3.8 but we want to support previous versions */ #ifdef HAVE_CTR_DRGB_FREE ctr_drbg_free(&(context->ctr_drbg)); #endif entropy_free(&(context->entropy)); bctbx_free(context); } /*** signing key ***/ bctbx_signing_key_t *bctbx_signing_key_new(void) { pk_context *key = bctbx_malloc0(sizeof(pk_context)); pk_init(key); return (bctbx_signing_key_t *)key; } void bctbx_signing_key_free(bctbx_signing_key_t *key) { pk_free((pk_context *)key); bctbx_free(key); } char *bctbx_signing_key_get_pem(bctbx_signing_key_t *key) { char *pem_key; if (key == NULL) return NULL; pem_key = (char *)bctbx_malloc0(4096); pk_write_key_pem( (pk_context *)key, (unsigned char *)pem_key, 4096); return pem_key; } int32_t bctbx_signing_key_parse(bctbx_signing_key_t *key, const char *buffer, size_t buffer_length, const unsigned char *password, size_t password_length) { int err; err=pk_parse_key((pk_context *)key, (const unsigned char *)buffer, buffer_length+1, password, password_length); if(err==0 && !pk_can_do((pk_context *)key, POLARSSL_PK_RSA)) { err=POLARSSL_ERR_PK_TYPE_MISMATCH; } if (err<0) { char tmp[128]; error_strerror(err,tmp,sizeof(tmp)); bctbx_error("cannot parse public key because [%s]",tmp); return BCTBX_ERROR_UNABLE_TO_PARSE_KEY; } return 0; } int32_t bctbx_signing_key_parse_file(bctbx_signing_key_t *key, const char *path, const char *password) { int err; err=pk_parse_keyfile((pk_context *)key, path, password); if(err==0 && !pk_can_do((pk_context *)key,POLARSSL_PK_RSA)) { err=POLARSSL_ERR_PK_TYPE_MISMATCH; } if (err<0) { char tmp[128]; error_strerror(err,tmp,sizeof(tmp)); bctbx_error("cannot parse public key because [%s]",tmp); return BCTBX_ERROR_UNABLE_TO_PARSE_KEY; } return 0; } /*** Certificate ***/ char *bctbx_x509_certificates_chain_get_pem(bctbx_x509_certificate_t *cert) { char *pem_certificate = NULL; size_t olen=0; pem_certificate = (char *)bctbx_malloc0(4096); pem_write_buffer("-----BEGIN CERTIFICATE-----\n", "-----END CERTIFICATE-----\n", ((x509_crt *)cert)->raw.p, ((x509_crt *)cert)->raw.len, (unsigned char*)pem_certificate, 4096, &olen ); return pem_certificate; } bctbx_x509_certificate_t *bctbx_x509_certificate_new(void) { x509_crt *cert = bctbx_malloc0(sizeof(x509_crt)); x509_crt_init(cert); return (bctbx_x509_certificate_t *)cert; } void bctbx_x509_certificate_free(bctbx_x509_certificate_t *cert) { x509_crt_free((x509_crt *)cert); bctbx_free(cert); } int32_t bctbx_x509_certificate_get_info_string(char *buf, size_t size, const char *prefix, const bctbx_x509_certificate_t *cert) { return x509_crt_info(buf, size, prefix, (x509_crt *)cert); } int32_t bctbx_x509_certificate_parse_file(bctbx_x509_certificate_t *cert, const char *path) { return x509_crt_parse_file((x509_crt *)cert, path); } int32_t bctbx_x509_certificate_parse_path(bctbx_x509_certificate_t *cert, const char *path) { return x509_crt_parse_path((x509_crt *)cert, path); } int32_t bctbx_x509_certificate_parse(bctbx_x509_certificate_t *cert, const char *buffer, size_t buffer_length) { return x509_crt_parse((x509_crt *)cert, (const unsigned char *)buffer, buffer_length+1); } int32_t bctbx_x509_certificate_get_der_length(bctbx_x509_certificate_t *cert) { if (cert!=NULL) { return ((x509_crt *)cert)->raw.len; } return 0; } int32_t bctbx_x509_certificate_get_der(bctbx_x509_certificate_t *cert, unsigned char *buffer, size_t buffer_length) { if (cert==NULL) { return BCTBX_ERROR_INVALID_CERTIFICATE; } if (((x509_crt *)cert)->raw.len>buffer_length-1) { /* check buffer size is ok, +1 for the NULL termination added at the end */ return BCTBX_ERROR_OUTPUT_BUFFER_TOO_SMALL; } memcpy(buffer, ((x509_crt *)cert)->raw.p, ((x509_crt *)cert)->raw.len); buffer[((x509_crt *)cert)->raw.len] = '\0'; /* add a null termination char */ return 0; } int32_t bctbx_x509_certificate_get_subject_dn(bctbx_x509_certificate_t *cert, char *dn, size_t dn_length) { if (cert==NULL) { return BCTBX_ERROR_INVALID_CERTIFICATE; } return x509_dn_gets(dn, dn_length, &(((x509_crt *)cert)->subject)); } int32_t bctbx_x509_certificate_generate_selfsigned(const char *subject, bctbx_x509_certificate_t *certificate, bctbx_signing_key_t *pkey, char * pem, size_t pem_length) { entropy_context entropy; ctr_drbg_context ctr_drbg; int ret; mpi serial; x509write_cert crt; char file_buffer[8192]; size_t file_buffer_len = 0; char formatted_subject[512]; /* subject may be a sip URL or linphone-dtls-default-identity, add CN= before it to make a valid name */ memcpy(formatted_subject, "CN=", 3); memcpy(formatted_subject+3, subject, strlen(subject)+1); /* +1 to get the \0 termination */ entropy_init( &entropy ); if( ( ret = ctr_drbg_init( &ctr_drbg, entropy_func, &entropy, NULL, 0 ) ) != 0 ) { bctbx_error("Certificate generation can't init ctr_drbg: -%x", -ret); return BCTBX_ERROR_CERTIFICATE_GENERATION_FAIL; } /* generate 3072 bits RSA public/private key */ if ( (ret = pk_init_ctx( (pk_context *)pkey, pk_info_from_type( POLARSSL_PK_RSA ) )) != 0) { bctbx_error("Certificate generation can't init pk_ctx: -%x", -ret); return BCTBX_ERROR_CERTIFICATE_GENERATION_FAIL; } if ( ( ret = rsa_gen_key( pk_rsa( *(pk_context *)pkey ), ctr_drbg_random, &ctr_drbg, 3072, 65537 ) ) != 0) { bctbx_error("Certificate generation can't generate rsa key: -%x", -ret); return BCTBX_ERROR_CERTIFICATE_GENERATION_FAIL; } /* if there is no pem pointer, don't save the key in pem format */ if (pem!=NULL) { pk_write_key_pem((pk_context *)pkey, (unsigned char *)file_buffer, 4096); file_buffer_len = strlen(file_buffer); } /* generate the certificate */ x509write_crt_init( &crt ); x509write_crt_set_md_alg( &crt, POLARSSL_MD_SHA256 ); mpi_init( &serial ); if ( (ret = mpi_read_string( &serial, 10, "1" ) ) != 0 ) { bctbx_error("Certificate generation can't read serial mpi: -%x", -ret); return BCTBX_ERROR_CERTIFICATE_GENERATION_FAIL; } x509write_crt_set_subject_key( &crt, (pk_context *)pkey); x509write_crt_set_issuer_key( &crt, (pk_context *)pkey); if ( (ret = x509write_crt_set_subject_name( &crt, formatted_subject) ) != 0) { bctbx_error("Certificate generation can't set subject name: -%x", -ret); return BCTBX_ERROR_CERTIFICATE_GENERATION_FAIL; } if ( (ret = x509write_crt_set_issuer_name( &crt, formatted_subject) ) != 0) { bctbx_error("Certificate generation can't set issuer name: -%x", -ret); return BCTBX_ERROR_CERTIFICATE_GENERATION_FAIL; } if ( (ret = x509write_crt_set_serial( &crt, &serial ) ) != 0) { bctbx_error("Certificate generation can't set serial: -%x", -ret); return BCTBX_ERROR_CERTIFICATE_GENERATION_FAIL; } mpi_free(&serial); if ( (ret = x509write_crt_set_validity( &crt, "20010101000000", "20300101000000" ) ) != 0) { bctbx_error("Certificate generation can't set validity: -%x", -ret); return BCTBX_ERROR_CERTIFICATE_GENERATION_FAIL; } /* store anyway certificate in pem format in a string even if we do not have file to write as we need it to get it in a x509_crt structure */ if ( (ret = x509write_crt_pem( &crt, (unsigned char *)file_buffer+file_buffer_len, 4096, ctr_drbg_random, &ctr_drbg ) ) != 0) { bctbx_error("Certificate generation can't write crt pem: -%x", -ret); return BCTBX_ERROR_CERTIFICATE_WRITE_PEM; } x509write_crt_free(&crt); /* ctr_drg_free function is available from polarssl1.3.8 but we want to support previous versions */ #ifdef HAVE_CTR_DRGB_FREE ctr_drbg_free(&ctr_drbg); #endif entropy_free(&entropy); /* copy the key+cert in pem format into the given buffer */ if (pem != NULL) { if (strlen(file_buffer)+1>pem_length) { bctbx_error("Certificate generation can't copy the certificate to pem buffer: too short [%ld] but need [%ld] bytes", (long)pem_length, (long)strlen(file_buffer)); return BCTBX_ERROR_OUTPUT_BUFFER_TOO_SMALL; } strncpy(pem, file_buffer, pem_length); } if ( (ret = x509_crt_parse((x509_crt *)certificate, (unsigned char *)file_buffer, strlen(file_buffer)) ) != 0) { bctbx_error("Certificate generation can't parse crt pem: -%x", -ret); return BCTBX_ERROR_CERTIFICATE_PARSE_PEM; } return 0; } int32_t bctbx_x509_certificate_get_signature_hash_function(const bctbx_x509_certificate_t *certificate, bctbx_md_type_t *hash_algorithm) { x509_crt *crt; if (certificate == NULL) return BCTBX_ERROR_INVALID_CERTIFICATE; crt = (x509_crt *)certificate; switch (crt->sig_md) { case POLARSSL_MD_SHA1: *hash_algorithm = BCTBX_MD_SHA1; break; case POLARSSL_MD_SHA224: *hash_algorithm = BCTBX_MD_SHA224; break; case POLARSSL_MD_SHA256: *hash_algorithm = BCTBX_MD_SHA256; break; case POLARSSL_MD_SHA384: *hash_algorithm = BCTBX_MD_SHA384; break; case POLARSSL_MD_SHA512: *hash_algorithm = BCTBX_MD_SHA512; break; default: *hash_algorithm = BCTBX_MD_UNDEFINED; return BCTBX_ERROR_UNSUPPORTED_HASH_FUNCTION; break; } return 0; } /* maximum length of returned buffer will be 7(SHA-512 string)+3*hash_length(64)+null char = 200 bytes */ int32_t bctbx_x509_certificate_get_fingerprint(const bctbx_x509_certificate_t *certificate, char *fingerprint, size_t fingerprint_length, bctbx_md_type_t hash_algorithm) { unsigned char buffer[64]={0}; /* buffer is max length of returned hash, which is 64 in case we use sha-512 */ size_t hash_length = 0; const char *hash_alg_string=NULL; size_t fingerprint_size = 0; x509_crt *crt; md_type_t hash_id; if (certificate == NULL) return BCTBX_ERROR_INVALID_CERTIFICATE; crt = (x509_crt *)certificate; /* if there is a specified hash algorithm, use it*/ switch (hash_algorithm) { case BCTBX_MD_SHA1: hash_id = POLARSSL_MD_SHA1; break; case BCTBX_MD_SHA224: hash_id = POLARSSL_MD_SHA224; break; case BCTBX_MD_SHA256: hash_id = POLARSSL_MD_SHA256; break; case BCTBX_MD_SHA384: hash_id = POLARSSL_MD_SHA384; break; case BCTBX_MD_SHA512: hash_id = POLARSSL_MD_SHA512; break; default: /* nothing specified, use the hash algo used in the certificate signature */ hash_id = crt->sig_md; break; } /* fingerprint is a hash of the DER formated certificate (found in crt->raw.p) using the same hash function used by certificate signature */ switch (hash_id) { case POLARSSL_MD_SHA1: sha1(crt->raw.p, crt->raw.len, buffer); hash_length = 20; hash_alg_string="SHA-1"; break; case POLARSSL_MD_SHA224: sha256(crt->raw.p, crt->raw.len, buffer, 1); /* last argument is a boolean, indicate to output sha-224 and not sha-256 */ hash_length = 28; hash_alg_string="SHA-224"; break; case POLARSSL_MD_SHA256: sha256(crt->raw.p, crt->raw.len, buffer, 0); hash_length = 32; hash_alg_string="SHA-256"; break; case POLARSSL_MD_SHA384: sha512(crt->raw.p, crt->raw.len, buffer, 1); /* last argument is a boolean, indicate to output sha-384 and not sha-512 */ hash_length = 48; hash_alg_string="SHA-384"; break; case POLARSSL_MD_SHA512: sha512(crt->raw.p, crt->raw.len, buffer, 1); /* last argument is a boolean, indicate to output sha-384 and not sha-512 */ hash_length = 64; hash_alg_string="SHA-512"; break; default: return BCTBX_ERROR_UNSUPPORTED_HASH_FUNCTION; break; } if (hash_length>0) { size_t i; int fingerprint_index = strlen(hash_alg_string); char prefix=' '; fingerprint_size=fingerprint_index+3*hash_length+1; /* fingerprint will be : hash_alg_string+' '+HEX : separated values: length is strlen(hash_alg_string)+3*hash_lenght + 1 for null termination */ if (fingerprint_lengthbuffer_size) { return BCTBX_ERROR_OUTPUT_BUFFER_TOO_SMALL; } strncpy(buffer, outputString, buffer_size); return 0; } int32_t bctbx_x509_certificate_set_flag(uint32_t *flags, uint32_t flags_to_set) { if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_EXPIRED) *flags |= BADCERT_EXPIRED; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_REVOKED) *flags |= BADCERT_REVOKED; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_CN_MISMATCH) *flags |= BADCERT_CN_MISMATCH; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_NOT_TRUSTED) *flags |= BADCERT_NOT_TRUSTED; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_MISSING) *flags |= BADCERT_MISSING; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCRL_NOT_TRUSTED) *flags |= BADCRL_NOT_TRUSTED; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCRL_EXPIRED) *flags |= BADCRL_EXPIRED; return 0; } uint32_t bctbx_x509_certificate_remap_flag(uint32_t flags) { uint32_t ret = 0; if (flags & BADCERT_EXPIRED) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_EXPIRED; if (flags & BADCERT_REVOKED) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_REVOKED; if (flags & BADCERT_CN_MISMATCH) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_CN_MISMATCH; if (flags & BADCERT_NOT_TRUSTED) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_NOT_TRUSTED; if (flags & BADCERT_MISSING) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_MISSING; if (flags & BADCRL_NOT_TRUSTED) ret |= BCTBX_CERTIFICATE_VERIFY_BADCRL_NOT_TRUSTED; if (flags & BADCRL_EXPIRED) ret |= BCTBX_CERTIFICATE_VERIFY_BADCRL_EXPIRED; return ret; } int32_t bctbx_x509_certificate_unset_flag(uint32_t *flags, uint32_t flags_to_unset) { if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_EXPIRED) *flags &= ~BADCERT_EXPIRED; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_REVOKED) *flags &= ~BADCERT_REVOKED; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_CN_MISMATCH) *flags &= ~BADCERT_CN_MISMATCH; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_NOT_TRUSTED) *flags &= ~BADCERT_NOT_TRUSTED; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_MISSING) *flags &= ~BADCERT_MISSING; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCRL_NOT_TRUSTED) *flags &= ~BADCRL_NOT_TRUSTED; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCRL_EXPIRED) *flags &= ~BADCRL_EXPIRED; return 0; } /*** Diffie-Hellman-Merkle ***/ /* initialise de DHM context according to requested algorithm */ bctbx_DHMContext_t *bctbx_CreateDHMContext(uint8_t DHMAlgo, uint8_t secretLength) { dhm_context *polarsslDhmContext; /* create the context */ bctbx_DHMContext_t *context = (bctbx_DHMContext_t *)malloc(sizeof(bctbx_DHMContext_t)); memset (context, 0, sizeof(bctbx_DHMContext_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 BCTBX_DHM_2048: /* 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 BCTBX_DHM_3072: /* 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 bctbx_DHMCreatePublic(bctbx_DHMContext_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); } /* compute secret - the ->peer field of context must have been set before calling this function */ void bctbx_DHMComputeSecret(bctbx_DHMContext_t *context, int (*rngFunction)(void *, uint8_t *, size_t), void *rngContext) { size_t keyLength; uint8_t sharedSecretBuffer[384]; /* longest shared secret available in these mode */ /* 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 and reset the key buffer */ memset(context->key,0, keyLength); dhm_calc_secret((dhm_context *)(context->cryptoModuleData), sharedSecretBuffer, &keyLength, (int (*)(void *, unsigned char *, size_t))rngFunction, rngContext); /* now copy the resulting secret in the correct place in buffer(result may actually miss some front zero bytes, real length of output is now in keyLength but we want primeLength bytes) */ memcpy(context->key+(context->primeLength-keyLength), sharedSecretBuffer, keyLength); memset(sharedSecretBuffer, 0, 384); /* purge secret from temporary buffer */ } /* clean DHM context */ void bctbx_DestroyDHMContext(bctbx_DHMContext_t *context) { if (context!= NULL) { /* key and secret must be erased from memory and not just freed */ if (context->secret != NULL) { memset(context->secret, 0, context->secretLength); free(context->secret); } free(context->self); if (context->key != NULL) { memset(context->key, 0, context->primeLength); free(context->key); } free(context->peer); dhm_free((dhm_context *)context->cryptoModuleData); free(context->cryptoModuleData); free(context); } } /*** SSL Client ***/ /** context **/ struct bctbx_ssl_context_struct { ssl_context ssl_ctx; char *cn; int(*callback_cli_cert_function)(void *, bctbx_ssl_context_t *, unsigned char *, size_t); /**< pointer to the callback called to update client certificate during handshake callback params are user_data, ssl_context, certificate distinguished name, name length */ void *callback_cli_cert_data; /**< data passed to the client cert callback */ int(*callback_send_function)(void *, const unsigned char *, size_t); /* callbacks args are: callback data, data buffer to be send, size of data buffer */ int(*callback_recv_function)(void *, unsigned char *, size_t); /* args: callback data, data buffer to be read, size of data buffer */ void *callback_sendrecv_data; /**< data passed to send/recv callbacks */ }; bctbx_ssl_context_t *bctbx_ssl_context_new(void) { bctbx_ssl_context_t *ssl_ctx = bctbx_malloc0(sizeof(bctbx_ssl_context_t)); ssl_init(&(ssl_ctx->ssl_ctx)); ssl_ctx->callback_cli_cert_function = NULL; ssl_ctx->callback_cli_cert_data = NULL; ssl_ctx->callback_send_function = NULL; ssl_ctx->callback_recv_function = NULL; ssl_ctx->callback_sendrecv_data = NULL; return ssl_ctx; } void bctbx_ssl_context_free(bctbx_ssl_context_t *ssl_ctx) { if (ssl_ctx->cn) bctbx_free(ssl_ctx->cn); ssl_free(&(ssl_ctx->ssl_ctx)); bctbx_free(ssl_ctx); } int32_t bctbx_ssl_close_notify(bctbx_ssl_context_t *ssl_ctx) { return ssl_close_notify(&(ssl_ctx->ssl_ctx)); } int32_t bctbx_ssl_session_reset(bctbx_ssl_context_t *ssl_ctx) { return ssl_session_reset(&(ssl_ctx->ssl_ctx)); } int32_t bctbx_ssl_write(bctbx_ssl_context_t *ssl_ctx, const unsigned char *buf, size_t buf_length) { int ret = ssl_write(&(ssl_ctx->ssl_ctx), buf, buf_length); /* remap some output code */ if (ret == POLARSSL_ERR_NET_WANT_WRITE) { ret = BCTBX_ERROR_NET_WANT_WRITE; } return ret; } int32_t bctbx_ssl_read(bctbx_ssl_context_t *ssl_ctx, unsigned char *buf, size_t buf_length) { int ret = ssl_read(&(ssl_ctx->ssl_ctx), buf, buf_length); /* remap some output code */ if (ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY) { ret = BCTBX_ERROR_SSL_PEER_CLOSE_NOTIFY; } if (ret == POLARSSL_ERR_NET_WANT_READ) { ret = BCTBX_ERROR_NET_WANT_READ; } return ret; } int32_t bctbx_ssl_handshake(bctbx_ssl_context_t *ssl_ctx) { int ret = 0; while( ssl_ctx->ssl_ctx.state != SSL_HANDSHAKE_OVER ) { ret = ssl_handshake_step(&(ssl_ctx->ssl_ctx)); if( ret != 0 ) { break; } /* insert the callback function for client certificate request */ if (ssl_ctx->callback_cli_cert_function != NULL) { /* check we have a callback function */ /* when in state SSL_CLIENT_CERTIFICATE - which means, next call to ssl_handshake_step will send the client certificate to server - * and the client_auth flag is set - which means the server requested a client certificate - */ if (ssl_ctx->ssl_ctx.state == SSL_CLIENT_CERTIFICATE && ssl_ctx->ssl_ctx.client_auth > 0) { /* note: polarssl 1.3 is unable to retrieve certificate dn during handshake from server certificate request * so the dn params in the callback are set to NULL and 0(dn string length) */ if (ssl_ctx->callback_cli_cert_function(ssl_ctx->callback_cli_cert_data, ssl_ctx, NULL, 0)!=0) { if((ret=ssl_send_fatal_handshake_failure(&(ssl_ctx->ssl_ctx))) != 0 ) return( ret ); } } } } /* remap some output codes */ if (ret == POLARSSL_ERR_NET_WANT_READ) { ret = BCTBX_ERROR_NET_WANT_READ; } else if (ret == POLARSSL_ERR_NET_WANT_WRITE) { ret = BCTBX_ERROR_NET_WANT_WRITE; } return(ret); } int32_t bctbx_ssl_set_hs_own_cert(bctbx_ssl_context_t *ssl_ctx, bctbx_x509_certificate_t *cert, bctbx_signing_key_t *key) { return ssl_set_own_cert(&(ssl_ctx->ssl_ctx) , (x509_crt *)cert , (pk_context *)key); } int bctbx_ssl_send_callback(void *data, const unsigned char *buffer, size_t buffer_length) { int ret = 0; /* data is the ssl_context which contains the actual callback and data */ bctbx_ssl_context_t *ssl_ctx = (bctbx_ssl_context_t *)data; ret = ssl_ctx->callback_send_function(ssl_ctx->callback_sendrecv_data, buffer, buffer_length); return bctbx_ssl_sendrecv_callback_return_remap(ret); } int bctbx_ssl_recv_callback(void *data, unsigned char *buffer, size_t buffer_length) { int ret = 0; /* data is the ssl_context which contains the actual callback and data */ bctbx_ssl_context_t *ssl_ctx = (bctbx_ssl_context_t *)data; ret = ssl_ctx->callback_recv_function(ssl_ctx->callback_sendrecv_data, buffer, buffer_length); return bctbx_ssl_sendrecv_callback_return_remap(ret); } void bctbx_ssl_set_io_callbacks(bctbx_ssl_context_t *ssl_ctx, void *callback_data, int(*callback_send_function)(void *, const unsigned char *, size_t), /* callbacks args are: callback data, data buffer to be send, size of data buffer */ int(*callback_recv_function)(void *, unsigned char *, size_t)){ /* args: callback data, data buffer to be read, size of data buffer */ if (ssl_ctx==NULL) { return; } ssl_ctx->callback_send_function = callback_send_function; ssl_ctx->callback_recv_function = callback_recv_function; ssl_ctx->callback_sendrecv_data = callback_data; ssl_set_bio(&(ssl_ctx->ssl_ctx), bctbx_ssl_recv_callback, ssl_ctx, bctbx_ssl_send_callback, ssl_ctx); } const bctbx_x509_certificate_t *bctbx_ssl_get_peer_certificate(bctbx_ssl_context_t *ssl_ctx) { return (const bctbx_x509_certificate_t *)ssl_get_peer_cert(&(ssl_ctx->ssl_ctx)); } const char *bctbx_ssl_get_ciphersuite(bctbx_ssl_context_t *ssl_ctx){ return ssl_get_ciphersuite(&(ssl_ctx->ssl_ctx)); } const char *bctbx_ssl_get_version(bctbx_ssl_context_t *ssl_ctx){ return ssl_get_version(&(ssl_ctx->ssl_ctx)); } int32_t bctbx_ssl_set_hostname(bctbx_ssl_context_t *ssl_ctx, const char *hostname){ if (ssl_ctx->cn) bctbx_free(ssl_ctx->cn); if (hostname) ssl_ctx->cn = bctbx_strdup(hostname); else ssl_ctx->cn = NULL; ssl_ctx->ssl_ctx.peer_cn = ssl_ctx->cn; return 0; } /** DTLS SRTP functions **/ #ifdef HAVE_DTLS_SRTP uint8_t bctbx_dtls_srtp_supported(void) { return 1; } static bctbx_dtls_srtp_profile_t bctbx_srtp_profile_polarssl2bctoolbox(enum DTLS_SRTP_protection_profiles polarssl_profile) { switch (polarssl_profile) { case SRTP_AES128_CM_HMAC_SHA1_80: return BCTBX_SRTP_AES128_CM_HMAC_SHA1_80; case SRTP_AES128_CM_HMAC_SHA1_32: return BCTBX_SRTP_AES128_CM_HMAC_SHA1_32; case SRTP_NULL_HMAC_SHA1_80: return BCTBX_SRTP_NULL_HMAC_SHA1_80; case SRTP_NULL_HMAC_SHA1_32: return BCTBX_SRTP_NULL_HMAC_SHA1_32; default: return BCTBX_SRTP_UNDEFINED; } } static enum DTLS_SRTP_protection_profiles bctbx_srtp_profile_bctoolbox2polarssl(bctbx_dtls_srtp_profile_t bctbx_profile) { switch (bctbx_profile) { case BCTBX_SRTP_AES128_CM_HMAC_SHA1_80: return SRTP_AES128_CM_HMAC_SHA1_80; case BCTBX_SRTP_AES128_CM_HMAC_SHA1_32: return SRTP_AES128_CM_HMAC_SHA1_32; case BCTBX_SRTP_NULL_HMAC_SHA1_80: return SRTP_NULL_HMAC_SHA1_80; case BCTBX_SRTP_NULL_HMAC_SHA1_32: return SRTP_NULL_HMAC_SHA1_32; default: return SRTP_UNSET_PROFILE; } } bctbx_dtls_srtp_profile_t bctbx_ssl_get_dtls_srtp_protection_profile(bctbx_ssl_context_t *ssl_ctx) { if (ssl_ctx==NULL) { return BCTBX_ERROR_INVALID_SSL_CONTEXT; } return bctbx_srtp_profile_polarssl2bctoolbox(ssl_get_dtls_srtp_protection_profile(&(ssl_ctx->ssl_ctx))); }; int32_t bctbx_ssl_get_dtls_srtp_key_material(bctbx_ssl_context_t *ssl_ctx, char *output, size_t *output_length) { if (ssl_ctx==NULL) { return BCTBX_ERROR_INVALID_SSL_CONTEXT; } /* check output buffer size */ if (*output_lengthssl_ctx.dtls_srtp_keys_len) { return BCTBX_ERROR_OUTPUT_BUFFER_TOO_SMALL; } memcpy(output, ssl_ctx->ssl_ctx.dtls_srtp_keys, ssl_ctx->ssl_ctx.dtls_srtp_keys_len); *output_length = ssl_ctx->ssl_ctx.dtls_srtp_keys_len; return 0; } #else /* HAVE_DTLS_SRTP */ /* dummy DTLS api when not available */ uint8_t bctbx_dtls_srtp_supported(void) { return 0; } bctbx_dtls_srtp_profile_t bctbx_ssl_get_dtls_srtp_protection_profile(bctbx_ssl_context_t *ssl_ctx) { return BCTBX_SRTP_UNDEFINED; } int32_t bctbx_ssl_get_dtls_srtp_key_material(bctbx_ssl_context_t *ssl_ctx, char *output, size_t *output_length) { *output_length = 0; return BCTBX_ERROR_UNAVAILABLE_FUNCTION; } #endif /* HAVE_DTLS_SRTP */ /** DTLS SRTP functions **/ /** config **/ struct bctbx_ssl_config_struct { int8_t endpoint; /**< BCTBX_SSL_IS_CLIENT or BCTBX_SSL_IS_SERVER */ int8_t authmode; /**< BCTBX_SSL_VERIFY_NONE, BCTBX_SSL_VERIFY_OPTIONAL, BCTBX_SSL_VERIFY_REQUIRED */ int8_t transport; /**< BCTBX_SSL_TRANSPORT_STREAM(TLS) or BCTBX_SSL_TRANSPORT_DATAGRAM(DTLS) */ int(*rng_function)(void *, unsigned char *, size_t); /**< pointer to a random number generator function */ void *rng_context; /**< pointer to a the random number generator context */ int(*callback_verify_function)(void *, x509_crt *, int, int *); /**< pointer to the verify callback function */ void *callback_verify_data; /**< data passed to the verify callback */ x509_crt *ca_chain; /**< trusted CA chain */ x509_crt *own_cert; pk_context *own_cert_pk; int(*callback_cli_cert_function)(void *, bctbx_ssl_context_t *, unsigned char *, size_t); /**< pointer to the callback called to update client certificate during handshake callback params are user_data, ssl_context, certificate distinguished name, name length */ void *callback_cli_cert_data; /**< data passed to the client cert callback */ #ifdef HAVE_DTLS_SRTP enum DTLS_SRTP_protection_profiles dtls_srtp_profiles[4]; /**< Store a maximum of 4 DTLS SRTP profiles to use */ int dtls_srtp_profiles_number; /**< Number of DTLS SRTP profiles in use */ #endif }; bctbx_ssl_config_t *bctbx_ssl_config_new(void) { #ifdef HAVE_DTLS_SRTP int i; #endif bctbx_ssl_config_t *ssl_config = bctbx_malloc0(sizeof(bctbx_ssl_config_t)); /* set all properties to BCTBX_SSL_UNSET or NULL */ ssl_config->endpoint = BCTBX_SSL_UNSET; ssl_config->authmode = BCTBX_SSL_UNSET; ssl_config->transport = BCTBX_SSL_UNSET; ssl_config->rng_function = NULL; ssl_config->rng_context = NULL; ssl_config->callback_verify_function= NULL; ssl_config->callback_verify_data = NULL; ssl_config->callback_cli_cert_function = NULL; ssl_config->callback_cli_cert_data = NULL; ssl_config->ca_chain = NULL; ssl_config->own_cert = NULL; ssl_config->own_cert_pk = NULL; #ifdef HAVE_DTLS_SRTP for (i=0; i<4; i++) { ssl_config->dtls_srtp_profiles[i] = SRTP_UNSET_PROFILE; } ssl_config->dtls_srtp_profiles_number = 0; #endif return ssl_config; } int32_t bctbx_ssl_config_set_crypto_library_config(bctbx_ssl_config_t *ssl_config, void *internal_config) { return BCTBX_ERROR_UNAVAILABLE_FUNCTION; } void bctbx_ssl_config_free(bctbx_ssl_config_t *ssl_config) { bctbx_free(ssl_config); } int32_t bctbx_ssl_config_defaults(bctbx_ssl_config_t *ssl_config, int endpoint, int transport) { if (ssl_config != NULL) { if (endpoint == BCTBX_SSL_IS_CLIENT) { ssl_config->endpoint = SSL_IS_CLIENT; } else if (endpoint == BCTBX_SSL_IS_SERVER) { ssl_config->endpoint = SSL_IS_SERVER; } else { return BCTBX_ERROR_INVALID_SSL_ENDPOINT; } /* useful only for versions of polarssl which have SSL_TRANSPORT_XXX defined */ #ifdef SSL_TRANSPORT_DATAGRAM if (transport == BCTBX_SSL_TRANSPORT_STREAM) { ssl_config->transport = SSL_TRANSPORT_STREAM; } else if (transport == BCTBX_SSL_TRANSPORT_DATAGRAM) { ssl_config->transport = SSL_TRANSPORT_DATAGRAM; } else { return BCTBX_ERROR_INVALID_SSL_TRANSPORT; } #endif return 0; } return BCTBX_ERROR_INVALID_SSL_CONFIG; } int32_t bctbx_ssl_config_set_endpoint(bctbx_ssl_config_t *ssl_config, int endpoint) { if (ssl_config == NULL) { return BCTBX_ERROR_INVALID_SSL_CONFIG; } if (endpoint == BCTBX_SSL_IS_CLIENT) { ssl_config->endpoint = SSL_IS_CLIENT; } else if (endpoint == BCTBX_SSL_IS_SERVER) { ssl_config->endpoint = SSL_IS_SERVER; } else { return BCTBX_ERROR_INVALID_SSL_ENDPOINT; } return 0; } int32_t bctbx_ssl_config_set_transport (bctbx_ssl_config_t *ssl_config, int transport) { if (ssl_config == NULL) { return BCTBX_ERROR_INVALID_SSL_CONFIG; } /* useful only for versions of polarssl which have SSL_TRANSPORT_XXX defined */ #ifdef SSL_TRANSPORT_DATAGRAM if (transport == BCTBX_SSL_TRANSPORT_STREAM) { ssl_config->transport = SSL_TRANSPORT_STREAM; } else if (transport == BCTBX_SSL_TRANSPORT_DATAGRAM) { ssl_config->transport = SSL_TRANSPORT_DATAGRAM; } else { return BCTBX_ERROR_INVALID_SSL_TRANSPORT; } #endif return 0; } int32_t bctbx_ssl_config_set_authmode(bctbx_ssl_config_t *ssl_config, int authmode) { if (ssl_config != NULL) { switch (authmode) { case BCTBX_SSL_VERIFY_NONE: ssl_config->authmode = SSL_VERIFY_NONE; break; case BCTBX_SSL_VERIFY_OPTIONAL: ssl_config->authmode = SSL_VERIFY_OPTIONAL; break; case BCTBX_SSL_VERIFY_REQUIRED: ssl_config->authmode = SSL_VERIFY_REQUIRED; break; default: return BCTBX_ERROR_INVALID_SSL_AUTHMODE; break; } return 0; } return BCTBX_ERROR_INVALID_SSL_CONFIG; } int32_t bctbx_ssl_config_set_rng(bctbx_ssl_config_t *ssl_config, int(*rng_function)(void *, unsigned char *, size_t), void *rng_context) { if (ssl_config != NULL) { ssl_config->rng_function = rng_function; ssl_config->rng_context = rng_context; } return BCTBX_ERROR_INVALID_SSL_CONFIG; } int32_t bctbx_ssl_config_set_callback_verify(bctbx_ssl_config_t *ssl_config, int(*callback_function)(void *, bctbx_x509_certificate_t *, int, uint32_t *), void *callback_data) { if (ssl_config != NULL) { ssl_config->callback_verify_function = (int(*)(void *, x509_crt *, int, int *))callback_function; ssl_config->callback_verify_data = callback_data; } return BCTBX_ERROR_INVALID_SSL_CONFIG; } int32_t bctbx_ssl_config_set_callback_cli_cert(bctbx_ssl_config_t *ssl_config, int(*callback_function)(void *, bctbx_ssl_context_t *, unsigned char *, size_t), void *callback_data) { if (ssl_config != NULL) { ssl_config->callback_cli_cert_function = callback_function; ssl_config->callback_cli_cert_data = callback_data; } return BCTBX_ERROR_INVALID_SSL_CONFIG; } int32_t bctbx_ssl_config_set_ca_chain(bctbx_ssl_config_t *ssl_config, bctbx_x509_certificate_t *ca_chain) { if (ssl_config != NULL) { ssl_config->ca_chain = (x509_crt *)ca_chain; } return BCTBX_ERROR_INVALID_SSL_CONFIG; } int32_t bctbx_ssl_config_set_own_cert(bctbx_ssl_config_t *ssl_config, bctbx_x509_certificate_t *cert, bctbx_signing_key_t *key) { if (ssl_config != NULL) { ssl_config->own_cert = (x509_crt *)cert; ssl_config->own_cert_pk = (pk_context *)key; } return BCTBX_ERROR_INVALID_SSL_CONFIG; } /** DTLS SRTP functions **/ #ifdef HAVE_DTLS_SRTP int32_t bctbx_ssl_config_set_dtls_srtp_protection_profiles(bctbx_ssl_config_t *ssl_config, const bctbx_dtls_srtp_profile_t *profiles, size_t profiles_number) { size_t i; if (ssl_config == NULL) { return BCTBX_ERROR_INVALID_SSL_CONFIG; } /* convert the profiles array into a polarssl profiles array */ for (i=0; idtls_srtp_profiles[i] = bctbx_srtp_profile_bctoolbox2polarssl(profiles[i]); } for (;i<4; i++) { /* make sure to have harmless values in the rest of the array */ ssl_config->dtls_srtp_profiles[i] = SRTP_UNSET_PROFILE; } ssl_config->dtls_srtp_profiles_number = profiles_number; return 0; } #else /* HAVE_DTLS_SRTP */ int32_t bctbx_ssl_config_set_dtls_srtp_protection_profiles(bctbx_ssl_config_t *ssl_config, const bctbx_dtls_srtp_profile_t *profiles, size_t profiles_number) { return BCTBX_ERROR_UNAVAILABLE_FUNCTION; } #endif /* HAVE_DTLS_SRTP */ /** DTLS SRTP functions **/ int32_t bctbx_ssl_context_setup(bctbx_ssl_context_t *ssl_ctx, bctbx_ssl_config_t *ssl_config) { /* Check validity of context and config */ if (ssl_config == NULL) { return BCTBX_ERROR_INVALID_SSL_CONFIG; } if (ssl_ctx == NULL) { return BCTBX_ERROR_INVALID_SSL_CONTEXT; } /* apply all valids settings to the ssl_context */ if (ssl_config->endpoint != BCTBX_SSL_UNSET) { ssl_set_endpoint(&(ssl_ctx->ssl_ctx), ssl_config->endpoint); } if (ssl_config->authmode != BCTBX_SSL_UNSET) { ssl_set_authmode(&(ssl_ctx->ssl_ctx), ssl_config->authmode); } #ifdef HAVE_DTLS_SRTP if (ssl_config->transport != BCTBX_SSL_UNSET) { ssl_set_transport(&(ssl_ctx->ssl_ctx), ssl_config->transport); } #endif if (ssl_config->rng_function != NULL) { ssl_set_rng(&(ssl_ctx->ssl_ctx), ssl_config->rng_function, ssl_config->rng_context); } if (ssl_config->callback_verify_function != NULL) { ssl_set_verify(&(ssl_ctx->ssl_ctx), ssl_config->callback_verify_function, ssl_config->callback_verify_data); } if (ssl_config->callback_cli_cert_function != NULL) { ssl_ctx->callback_cli_cert_function = ssl_config->callback_cli_cert_function; ssl_ctx->callback_cli_cert_data = ssl_config->callback_cli_cert_data; } if (ssl_config->ca_chain != NULL) { ssl_set_ca_chain(&(ssl_ctx->ssl_ctx), ssl_config->ca_chain, NULL, ssl_ctx->cn); } if (ssl_config->own_cert != NULL && ssl_config->own_cert_pk != NULL) { ssl_set_own_cert(&(ssl_ctx->ssl_ctx) , ssl_config->own_cert , ssl_config->own_cert_pk); } #ifdef HAVE_DTLS_SRTP if (ssl_config->dtls_srtp_profiles_number > 0) { ssl_set_dtls_srtp_protection_profiles(&(ssl_ctx->ssl_ctx), ssl_config->dtls_srtp_profiles, ssl_config->dtls_srtp_profiles_number ); } /* We do not use DTLS SRTP cookie, so we must set to NULL the callbacks. Cookies are used to prevent DoS attack but our server is on only when during a brief period so we do not need this */ ssl_set_dtls_cookies(&(ssl_ctx->ssl_ctx), NULL, NULL, NULL); #endif return 0; } /*****************************************************************************/ /***** Hashing *****/ /*****************************************************************************/ /** * @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 bctbx_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); } } /** * @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 bctbx_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); } } /** * @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 bctbx_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); } } /** * @brief MD5 wrapper * output = md5(input) * @param[in] input Input data buffer * @param[in] inputLength Input data length in bytes * @param[out] output Output data buffer. * */ void bctbx_md5(const uint8_t *input, size_t inputLength, uint8_t output[16]) { md5(input, inputLength, output); } /*****************************************************************************/ /***** Encryption/Decryption *****/ /*****************************************************************************/ /***** GCM *****/ /** * @Brief AES-GCM encrypt and tag buffer * * @param[in] key Encryption key * @param[in] keyLength Key buffer length, in bytes, must be 16,24 or 32 * @param[in] plainText Buffer to be encrypted * @param[in] plainTextLength Length in bytes of buffer to be encrypted * @param[in] authenticatedData Buffer holding additional data to be used in tag computation * @param[in] authenticatedDataLength Additional data length in bytes * @param[in] initializationVector Buffer holding the initialisation vector * @param[in] initializationVectorLength Initialisation vector length in bytes * @param[out] tag Buffer holding the generated tag * @param[in] tagLength Requested length for the generated tag * @param[out] output Buffer holding the output, shall be at least the length of plainText buffer */ int32_t bctbx_aes_gcm_encrypt_and_tag(const uint8_t *key, size_t keyLength, const uint8_t *plainText, size_t plainTextLength, const uint8_t *authenticatedData, size_t authenticatedDataLength, const uint8_t *initializationVector, size_t initializationVectorLength, uint8_t *tag, size_t tagLength, uint8_t *output) { gcm_context gcmContext; int ret; ret = gcm_init(&gcmContext, POLARSSL_CIPHER_ID_AES, key, keyLength*8); if (ret != 0) return ret; ret = gcm_crypt_and_tag(&gcmContext, GCM_ENCRYPT, plainTextLength, initializationVector, initializationVectorLength, authenticatedData, authenticatedDataLength, plainText, output, tagLength, tag); gcm_free(&gcmContext); return ret; } /** * @Brief AES-GCM decrypt, compute authentication tag and compare it to the one provided * * @param[in] key Encryption key * @param[in] keyLength Key buffer length, in bytes, must be 16,24 or 32 * @param[in] cipherText Buffer to be decrypted * @param[in] cipherTextLength Length in bytes of buffer to be decrypted * @param[in] authenticatedData Buffer holding additional data to be used in auth tag computation * @param[in] authenticatedDataLength Additional data length in bytes * @param[in] initializationVector Buffer holding the initialisation vector * @param[in] initializationVectorLength Initialisation vector length in bytes * @param[in] tag Buffer holding the authentication tag * @param[in] tagLength Length in bytes for the authentication tag * @param[out] output Buffer holding the output, shall be at least the length of cipherText buffer * * @return 0 on succes, BCTBX_ERROR_AUTHENTICATION_FAILED if tag doesn't match or polarssl error code */ int32_t bctbx_aes_gcm_decrypt_and_auth(const uint8_t *key, size_t keyLength, const uint8_t *cipherText, size_t cipherTextLength, const uint8_t *authenticatedData, size_t authenticatedDataLength, const uint8_t *initializationVector, size_t initializationVectorLength, const uint8_t *tag, size_t tagLength, uint8_t *output) { gcm_context gcmContext; int ret; ret = gcm_init(&gcmContext, POLARSSL_CIPHER_ID_AES, key, keyLength*8); if (ret != 0) return ret; ret = gcm_auth_decrypt(&gcmContext, cipherTextLength, initializationVector, initializationVectorLength, authenticatedData, authenticatedDataLength, tag, tagLength, cipherText, output); gcm_free(&gcmContext); if (ret == POLARSSL_ERR_GCM_AUTH_FAILED) { return BCTBX_ERROR_AUTHENTICATION_FAILED; } return ret; } /** * @Brief create and initialise an AES-GCM encryption context * * @param[in] key encryption key * @param[in] keyLength key buffer length, in bytes, must be 16,24 or 32 * @param[in] authenticatedData Buffer holding additional data to be used in tag computation (can be NULL) * @param[in] authenticatedDataLength additional data length in bytes (can be 0) * @param[in] initializationVector Buffer holding the initialisation vector * @param[in] initializationVectorLength Initialisation vector length in bytes * @param[in] mode Operation mode : BCTBX_GCM_ENCRYPT or BCTBX_GCM_DECRYPT * * @return 0 on success, crypto library error code otherwise */ bctbx_aes_gcm_context_t *bctbx_aes_gcm_context_new(const uint8_t *key, size_t keyLength, const uint8_t *authenticatedData, size_t authenticatedDataLength, const uint8_t *initializationVector, size_t initializationVectorLength, uint8_t mode) { int ret = 0; int polarssl_mode; gcm_context *ctx = NULL; if (mode == BCTBX_GCM_ENCRYPT) { polarssl_mode = GCM_ENCRYPT; } else if ( mode == BCTBX_GCM_DECRYPT) { polarssl_mode = GCM_DECRYPT; } else { return NULL; } ctx = bctbx_malloc0(sizeof(gcm_context)); ret = gcm_init(ctx, POLARSSL_CIPHER_ID_AES, key, keyLength*8); if (ret != 0) { bctbx_free(ctx); return NULL; } ret = gcm_starts(ctx, polarssl_mode, initializationVector, initializationVectorLength, authenticatedData, authenticatedDataLength); if (ret != 0) { bctbx_free(ctx); return NULL; } return (bctbx_aes_gcm_context_t *)ctx; } /** * @Brief AES-GCM encrypt or decrypt a chunk of data * * @param[in/out] context a context already initialized using bctbx_aes_gcm_context_new * @param[in] input buffer holding the input data * @param[in] inputLength lenght of the input data * @param[out] output buffer to store the output data (same length as input one) * * @return 0 on success, crypto library error code otherwise */ int32_t bctbx_aes_gcm_process_chunk(bctbx_aes_gcm_context_t *context, const uint8_t *input, size_t inputLength, uint8_t *output) { return gcm_update((gcm_context *)context, inputLength, input, output); } /** * @Brief Conclude a AES-GCM encryption stream, generate tag if requested, free resources * * @param[in/out] context a context already initialized using bctbx_aes_gcm_context_new * @param[out] tag a buffer to hold the authentication tag. Can be NULL if tagLength is 0 * @param[in] tagLength length of reqested authentication tag, max 16 * * @return 0 on success, crypto library error code otherwise */ int32_t bctbx_aes_gcm_finish(bctbx_aes_gcm_context_t *context, uint8_t *tag, size_t tagLength) { int ret; ret = gcm_finish((gcm_context *)context, tag, tagLength); gcm_free((gcm_context *)context); bctbx_free(context); return ret; } /* * @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 bctbx_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 bctbx_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 bctbx_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 bctbx_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); } bctoolbox-0.6.0/src/crypto/polarssl1.2.c000066400000000000000000001207601313410701300200420ustar00rootroot00000000000000/* crypto_polarssl.c Copyright (C) 2016 Belledonne Communications SARL This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "utils.h" #include #include #include #include #include "polarssl/base64.h" #include #include #include #include #include #include #include #include #include "bctoolbox/logging.h" #ifdef _WIN32 #define snprintf _snprintf #endif static int bctbx_ssl_sendrecv_callback_return_remap(int32_t ret_code) { switch (ret_code) { case BCTBX_ERROR_NET_WANT_READ: return POLARSSL_ERR_NET_WANT_READ; case BCTBX_ERROR_NET_WANT_WRITE: return POLARSSL_ERR_NET_WANT_WRITE; case BCTBX_ERROR_NET_CONN_RESET: return POLARSSL_ERR_NET_CONN_RESET; default: return (int)ret_code; } } void bctbx_strerror(int32_t error_code, char *buffer, size_t buffer_length) { if (error_code>0) { snprintf(buffer, buffer_length, "%s", "Invalid Error code"); return ; } /* polarssl error code are all negatived and bas smaller than 0x0000F000 */ /* bctoolbox defined error codes are all in format -0x7XXXXXXX */ if (-error_code<0x00010000) { /* it's a polarssl error code */ error_strerror(error_code, buffer, buffer_length); return; } snprintf(buffer, buffer_length, "%s [-0x%x]", "bctoolbox defined error code", -error_code); return; } int32_t bctbx_base64_encode(unsigned char *output, size_t *output_length, const unsigned char *input, size_t input_length) { int ret = base64_encode(output, output_length, input, input_length); if (ret == POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL) { return BCTBX_ERROR_OUTPUT_BUFFER_TOO_SMALL; } return ret; } int32_t bctbx_base64_decode(unsigned char *output, size_t *output_length, const unsigned char *input, size_t input_length) { int ret = base64_decode(output, output_length, input, input_length); if (ret == POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL) { return BCTBX_ERROR_OUTPUT_BUFFER_TOO_SMALL; } if (ret == POLARSSL_ERR_BASE64_INVALID_CHARACTER) { return BCTBX_ERROR_INVALID_BASE64_INPUT; } return ret; } /*** Random Number Generation ***/ struct bctbx_rng_context_struct { entropy_context entropy; ctr_drbg_context ctr_drbg; }; bctbx_rng_context_t *bctbx_rng_context_new(void) { bctbx_rng_context_t *ctx = bctbx_malloc0(sizeof(bctbx_rng_context_t)); entropy_init(&(ctx->entropy)); ctr_drbg_init(&(ctx->ctr_drbg), entropy_func, &(ctx->entropy), NULL, 0); return ctx; } int32_t bctbx_rng_get(bctbx_rng_context_t *context, unsigned char*output, size_t output_length) { return ctr_drbg_random(&(context->ctr_drbg), output, output_length); } void bctbx_rng_context_free(bctbx_rng_context_t *context) { bctbx_free(context); } /*** signing key ***/ bctbx_signing_key_t *bctbx_signing_key_new(void) { rsa_context *key = bctbx_malloc0(sizeof(rsa_context)); rsa_init(key, RSA_PKCS_V15, 0); return (bctbx_signing_key_t *)key; } void bctbx_signing_key_free(bctbx_signing_key_t *key) { rsa_free((rsa_context *)key); bctbx_free(key); } char *bctbx_signing_key_get_pem(bctbx_signing_key_t *key) { return NULL; } int32_t bctbx_signing_key_parse(bctbx_signing_key_t *key, const char *buffer, size_t buffer_length, const unsigned char *password, size_t password_length) { int err; err=x509parse_key((rsa_context *)key, (const unsigned char *)buffer, buffer_length+1, password, password_length); if (err<0) { char tmp[128]; error_strerror(err,tmp,sizeof(tmp)); bctbx_error("cannot parse public key because [%s]",tmp); return BCTBX_ERROR_UNABLE_TO_PARSE_KEY; } return 0; } int32_t bctbx_signing_key_parse_file(bctbx_signing_key_t *key, const char *path, const char *password) { int err; err=x509parse_keyfile((rsa_context *)key, path, password); if (err<0) { char tmp[128]; error_strerror(err,tmp,sizeof(tmp)); bctbx_error("cannot parse public key because [%s]",tmp); return BCTBX_ERROR_UNABLE_TO_PARSE_KEY; } return 0; } /*** Certificate ***/ char *bctbx_x509_certificates_chain_get_pem(bctbx_x509_certificate_t *cert) { return NULL; } bctbx_x509_certificate_t *bctbx_x509_certificate_new(void) { x509_cert *cert = bctbx_malloc0(sizeof(x509_cert)); return (bctbx_x509_certificate_t *)cert; } void bctbx_x509_certificate_free(bctbx_x509_certificate_t *cert) { x509_free((x509_cert *)cert); bctbx_free(cert); } int32_t bctbx_x509_certificate_get_info_string(char *buf, size_t size, const char *prefix, const bctbx_x509_certificate_t *cert) { return x509parse_cert_info(buf, size, prefix, (x509_cert *)cert); } int32_t bctbx_x509_certificate_parse_file(bctbx_x509_certificate_t *cert, const char *path) { return x509parse_crtfile((x509_cert *)cert, path); } int32_t bctbx_x509_certificate_parse_path(bctbx_x509_certificate_t *cert, const char *path) { return x509parse_crtpath((x509_cert *)cert, path); } int32_t bctbx_x509_certificate_parse(bctbx_x509_certificate_t *cert, const char *buffer, size_t buffer_length) { return x509parse_crt((x509_cert *)cert, (const unsigned char *)buffer, buffer_length+1); } int32_t bctbx_x509_certificate_get_der_length(bctbx_x509_certificate_t *cert) { if (cert!=NULL) { return ((x509_cert *)cert)->raw.len; } return 0; } int32_t bctbx_x509_certificate_get_der(bctbx_x509_certificate_t *cert, unsigned char *buffer, size_t buffer_length) { if (cert==NULL) { return BCTBX_ERROR_INVALID_CERTIFICATE; } if (((x509_cert *)cert)->raw.len>buffer_length-1) { /* check buffer size is ok, +1 for the NULL termination added at the end */ return BCTBX_ERROR_OUTPUT_BUFFER_TOO_SMALL; } memcpy(buffer, ((x509_cert *)cert)->raw.p, ((x509_cert *)cert)->raw.len); buffer[((x509_cert *)cert)->raw.len] = '\0'; /* add a null termination char */ return 0; } int32_t bctbx_x509_certificate_get_subject_dn(bctbx_x509_certificate_t *cert, char *dn, size_t dn_length) { if (cert==NULL) { return BCTBX_ERROR_INVALID_CERTIFICATE; } return x509parse_dn_gets(dn, dn_length, &(((x509_cert *)cert)->subject)); } int32_t bctbx_x509_certificate_generate_selfsigned(const char *subject, bctbx_x509_certificate_t *certificate, bctbx_signing_key_t *pkey, char * pem, size_t pem_length) { return BCTBX_ERROR_UNAVAILABLE_FUNCTION; } int32_t bctbx_x509_certificate_get_signature_hash_function(const bctbx_x509_certificate_t *certificate, bctbx_md_type_t *hash_algorithm) { return BCTBX_ERROR_UNAVAILABLE_FUNCTION; } /* maximum length of returned buffer will be 7(SHA-512 string)+3*hash_length(64)+null char = 200 bytes */ int32_t bctbx_x509_certificate_get_fingerprint(const bctbx_x509_certificate_t *certificate, char *fingerprint, size_t fingerprint_length, bctbx_md_type_t hash_algorithm) { return BCTBX_ERROR_UNAVAILABLE_FUNCTION; } #define BCTBX_MAX_CERTIFICATE_FLAGS_STRING_LENGTH 128 int32_t bctbx_x509_certificate_flags_to_string(char *buffer, size_t buffer_size, uint32_t flags) { size_t i=0; char outputString[BCTBX_MAX_CERTIFICATE_FLAGS_STRING_LENGTH]; if (flags & BADCERT_EXPIRED) i+=snprintf(outputString+i, BCTBX_MAX_CERTIFICATE_FLAGS_STRING_LENGTH-i, "expired "); if (flags & BADCERT_REVOKED) i+=snprintf(outputString+i, BCTBX_MAX_CERTIFICATE_FLAGS_STRING_LENGTH-i, "revoked "); if (flags & BADCERT_CN_MISMATCH) i+=snprintf(outputString+i, BCTBX_MAX_CERTIFICATE_FLAGS_STRING_LENGTH-i, "CN-mismatch "); if (flags & BADCERT_NOT_TRUSTED) i+=snprintf(outputString+i, BCTBX_MAX_CERTIFICATE_FLAGS_STRING_LENGTH-i, "not-trusted "); if (flags & BADCERT_MISSING) i+=snprintf(outputString+i, BCTBX_MAX_CERTIFICATE_FLAGS_STRING_LENGTH-i, "missing "); if (flags & BADCRL_NOT_TRUSTED) i+=snprintf(outputString+i, BCTBX_MAX_CERTIFICATE_FLAGS_STRING_LENGTH-i, "crl-not-trusted "); if (flags & BADCRL_EXPIRED) i+=snprintf(outputString+i, BCTBX_MAX_CERTIFICATE_FLAGS_STRING_LENGTH-i, "crl-expired "); outputString[i] = '\0'; /* null terminate the string */ if (i+1>buffer_size) { return BCTBX_ERROR_OUTPUT_BUFFER_TOO_SMALL; } strncpy(buffer, outputString, buffer_size); return 0; } int32_t bctbx_x509_certificate_set_flag(uint32_t *flags, uint32_t flags_to_set) { if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_EXPIRED) *flags |= BADCERT_EXPIRED; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_REVOKED) *flags |= BADCERT_REVOKED; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_CN_MISMATCH) *flags |= BADCERT_CN_MISMATCH; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_NOT_TRUSTED) *flags |= BADCERT_NOT_TRUSTED; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCERT_MISSING) *flags |= BADCERT_MISSING; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCRL_NOT_TRUSTED) *flags |= BADCRL_NOT_TRUSTED; if (flags_to_set & BCTBX_CERTIFICATE_VERIFY_BADCRL_EXPIRED) *flags |= BADCRL_EXPIRED; return 0; } uint32_t bctbx_x509_certificate_remap_flag(uint32_t flags) { uint32_t ret = 0; if (flags & BADCERT_EXPIRED) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_EXPIRED; if (flags & BADCERT_REVOKED) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_REVOKED; if (flags & BADCERT_CN_MISMATCH) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_CN_MISMATCH; if (flags & BADCERT_NOT_TRUSTED) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_NOT_TRUSTED; if (flags & BADCERT_MISSING) ret |= BCTBX_CERTIFICATE_VERIFY_BADCERT_MISSING; if (flags & BADCRL_NOT_TRUSTED) ret |= BCTBX_CERTIFICATE_VERIFY_BADCRL_NOT_TRUSTED; if (flags & BADCRL_EXPIRED) ret |= BCTBX_CERTIFICATE_VERIFY_BADCRL_EXPIRED; return ret; } int32_t bctbx_x509_certificate_unset_flag(uint32_t *flags, uint32_t flags_to_unset) { if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_EXPIRED) *flags &= ~BADCERT_EXPIRED; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_REVOKED) *flags &= ~BADCERT_REVOKED; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_CN_MISMATCH) *flags &= ~BADCERT_CN_MISMATCH; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_NOT_TRUSTED) *flags &= ~BADCERT_NOT_TRUSTED; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCERT_MISSING) *flags &= ~BADCERT_MISSING; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCRL_NOT_TRUSTED) *flags &= ~BADCRL_NOT_TRUSTED; if (flags_to_unset & BCTBX_CERTIFICATE_VERIFY_BADCRL_EXPIRED) *flags &= ~BADCRL_EXPIRED; return 0; } /*** Diffie-Hellman-Merkle ***/ /* initialise de DHM context according to requested algorithm */ bctbx_DHMContext_t *bctbx_CreateDHMContext(uint8_t DHMAlgo, uint8_t secretLength) { dhm_context *polarsslDhmContext; /* create the context */ bctbx_DHMContext_t *context = (bctbx_DHMContext_t *)malloc(sizeof(bctbx_DHMContext_t)); memset (context, 0, sizeof(bctbx_DHMContext_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 BCTBX_DHM_2048: /* 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 BCTBX_DHM_3072: /* 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 bctbx_DHMCreatePublic(bctbx_DHMContext_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); } /* compute secret - the ->peer field of context must have been set before calling this function */ void bctbx_DHMComputeSecret(bctbx_DHMContext_t *context, int (*rngFunction)(void *, uint8_t *, size_t), void *rngContext) { size_t keyLength; uint8_t sharedSecretBuffer[384]; /* longest shared secret available in these mode */ /* 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 and reset the key buffer */ memset(context->key,0, keyLength); dhm_calc_secret((dhm_context *)(context->cryptoModuleData), sharedSecretBuffer, &keyLength); /* now copy the resulting secret in the correct place in buffer(result may actually miss some front zero bytes, real length of output is now in keyLength but we want primeLength bytes) */ memcpy(context->key+(context->primeLength-keyLength), sharedSecretBuffer, keyLength); memset(sharedSecretBuffer, 0, 384); /* purge secret from temporary buffer */ } /* clean DHM context */ void bctbx_DestroyDHMContext(bctbx_DHMContext_t *context) { if (context!= NULL) { /* key and secret must be erased from memory and not just freed */ if (context->secret != NULL) { memset(context->secret, 0, context->secretLength); free(context->secret); } free(context->self); if (context->key != NULL) { memset(context->key, 0, context->primeLength); free(context->key); } free(context->peer); dhm_free((dhm_context *)context->cryptoModuleData); free(context->cryptoModuleData); free(context); } } /*** SSL Client ***/ /** context **/ struct bctbx_ssl_context_struct { ssl_context ssl_ctx; char *cn; int(*callback_cli_cert_function)(void *, bctbx_ssl_context_t *, unsigned char *, size_t); /**< pointer to the callback called to update client certificate during handshake callback params are user_data, ssl_context, certificate distinguished name, name length */ void *callback_cli_cert_data; /**< data passed to the client cert callback */ int(*callback_send_function)(void *, const unsigned char *, size_t); /* callbacks args are: callback data, data buffer to be send, size of data buffer */ int(*callback_recv_function)(void *, unsigned char *, size_t); /* args: callback data, data buffer to be read, size of data buffer */ void *callback_sendrecv_data; /**< data passed to send/recv callbacks */ }; bctbx_ssl_context_t *bctbx_ssl_context_new(void) { bctbx_ssl_context_t *ssl_ctx = bctbx_malloc0(sizeof(bctbx_ssl_context_t)); ssl_init(&(ssl_ctx->ssl_ctx)); ssl_ctx->callback_cli_cert_function = NULL; ssl_ctx->callback_cli_cert_data = NULL; ssl_ctx->callback_send_function = NULL; ssl_ctx->callback_recv_function = NULL; ssl_ctx->callback_sendrecv_data = NULL; return ssl_ctx; } void bctbx_ssl_context_free(bctbx_ssl_context_t *ssl_ctx) { if (ssl_ctx->cn) bctbx_free(ssl_ctx->cn); ssl_free(&(ssl_ctx->ssl_ctx)); bctbx_free(ssl_ctx); } int32_t bctbx_ssl_close_notify(bctbx_ssl_context_t *ssl_ctx) { return ssl_close_notify(&(ssl_ctx->ssl_ctx)); } int32_t bctbx_ssl_session_reset(bctbx_ssl_context_t *ssl_ctx) { return ssl_session_reset(&(ssl_ctx->ssl_ctx)); } int32_t bctbx_ssl_write(bctbx_ssl_context_t *ssl_ctx, const unsigned char *buf, size_t buf_length) { int ret = ssl_write(&(ssl_ctx->ssl_ctx), buf, buf_length); /* remap some output code */ if (ret == POLARSSL_ERR_NET_WANT_WRITE) { ret = BCTBX_ERROR_NET_WANT_WRITE; } return ret; } int32_t bctbx_ssl_read(bctbx_ssl_context_t *ssl_ctx, unsigned char *buf, size_t buf_length) { int ret = ssl_read(&(ssl_ctx->ssl_ctx), buf, buf_length); /* remap some output code */ if (ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY) { ret = BCTBX_ERROR_SSL_PEER_CLOSE_NOTIFY; } if (ret == POLARSSL_ERR_NET_WANT_READ) { ret = BCTBX_ERROR_NET_WANT_READ; } return ret; } int32_t bctbx_ssl_handshake(bctbx_ssl_context_t *ssl_ctx) { int ret = 0; while( ssl_ctx->ssl_ctx.state != SSL_HANDSHAKE_OVER ) { ret = ssl_handshake_step(&(ssl_ctx->ssl_ctx)); if( ret != 0 ) { break; } /* insert the callback function for client certificate request */ if (ssl_ctx->callback_cli_cert_function != NULL) { /* check we have a callback function */ /* when in state SSL_CLIENT_CERTIFICATE - which means, next call to ssl_handshake_step will send the client certificate to server - * and the client_auth flag is set - which means the server requested a client certificate - */ if (ssl_ctx->ssl_ctx.state == SSL_CLIENT_CERTIFICATE && ssl_ctx->ssl_ctx.client_auth > 0) { /* note: polarssl 1.3 is unable to retrieve certificate dn during handshake from server certificate request * so the dn params in the callback are set to NULL and 0(dn string length) */ if (ssl_ctx->callback_cli_cert_function(ssl_ctx->callback_cli_cert_data, ssl_ctx, NULL, 0)!=0) { if((ret=ssl_send_fatal_handshake_failure(&(ssl_ctx->ssl_ctx))) != 0 ) return( ret ); } } } } /* remap some output codes */ if (ret == POLARSSL_ERR_NET_WANT_READ) { ret = BCTBX_ERROR_NET_WANT_READ; } else if (ret == POLARSSL_ERR_NET_WANT_WRITE) { ret = BCTBX_ERROR_NET_WANT_WRITE; } return(ret); } int32_t bctbx_ssl_set_hs_own_cert(bctbx_ssl_context_t *ssl_ctx, bctbx_x509_certificate_t *cert, bctbx_signing_key_t *key) { ssl_set_own_cert(&(ssl_ctx->ssl_ctx) , (x509_cert *)cert , (rsa_context *)key); return 0; } int bctbx_ssl_send_callback(void *data, const unsigned char *buffer, size_t buffer_length) { int ret = 0; /* data is the ssl_context which contains the actual callback and data */ bctbx_ssl_context_t *ssl_ctx = (bctbx_ssl_context_t *)data; ret = ssl_ctx->callback_send_function(ssl_ctx->callback_sendrecv_data, buffer, buffer_length); return bctbx_ssl_sendrecv_callback_return_remap(ret); } int bctbx_ssl_recv_callback(void *data, unsigned char *buffer, size_t buffer_length) { int ret = 0; /* data is the ssl_context which contains the actual callback and data */ bctbx_ssl_context_t *ssl_ctx = (bctbx_ssl_context_t *)data; ret = ssl_ctx->callback_recv_function(ssl_ctx->callback_sendrecv_data, buffer, buffer_length); return bctbx_ssl_sendrecv_callback_return_remap(ret); } void bctbx_ssl_set_io_callbacks(bctbx_ssl_context_t *ssl_ctx, void *callback_data, int(*callback_send_function)(void *, const unsigned char *, size_t), /* callbacks args are: callback data, data buffer to be send, size of data buffer */ int(*callback_recv_function)(void *, unsigned char *, size_t)){ /* args: callback data, data buffer to be read, size of data buffer */ if (ssl_ctx==NULL) { return; } ssl_ctx->callback_send_function = callback_send_function; ssl_ctx->callback_recv_function = callback_recv_function; ssl_ctx->callback_sendrecv_data = callback_data; ssl_set_bio(&(ssl_ctx->ssl_ctx), bctbx_ssl_recv_callback, ssl_ctx, bctbx_ssl_send_callback, ssl_ctx); } const bctbx_x509_certificate_t *bctbx_ssl_get_peer_certificate(bctbx_ssl_context_t *ssl_ctx) { return (const bctbx_x509_certificate_t *)ssl_get_peer_cert(&(ssl_ctx->ssl_ctx)); } const char *bctbx_ssl_get_ciphersuite(bctbx_ssl_context_t *ssl_ctx){ return ssl_get_ciphersuite(&(ssl_ctx->ssl_ctx)); } const char *bctbx_ssl_get_version(bctbx_ssl_context_t *ssl_ctx){ return ssl_get_version(&(ssl_ctx->ssl_ctx)); } int32_t bctbx_ssl_set_hostname(bctbx_ssl_context_t *ssl_ctx, const char *hostname){ if (ssl_ctx->cn) bctbx_free(ssl_ctx->cn); if (hostname) ssl_ctx->cn = bctbx_strdup(hostname); else ssl_ctx->cn = NULL; ssl_ctx->ssl_ctx.peer_cn = ssl_ctx->cn; return 0; } /** dummmy DTLS SRTP functions **/ uint8_t bctbx_dtls_srtp_supported(void) { return 0; } bctbx_dtls_srtp_profile_t bctbx_ssl_get_dtls_srtp_protection_profile(bctbx_ssl_context_t *ssl_ctx) { return BCTBX_SRTP_UNDEFINED; } int32_t bctbx_ssl_get_dtls_srtp_key_material(bctbx_ssl_context_t *ssl_ctx, char *output, size_t *output_length) { *output_length = 0; return BCTBX_ERROR_UNAVAILABLE_FUNCTION; } /** DTLS SRTP functions **/ /** config **/ struct bctbx_ssl_config_struct { int8_t endpoint; /**< BCTBX_SSL_IS_CLIENT or BCTBX_SSL_IS_SERVER */ int8_t authmode; /**< BCTBX_SSL_VERIFY_NONE, BCTBX_SSL_VERIFY_OPTIONAL, BCTBX_SSL_VERIFY_REQUIRED */ int8_t transport; /**< BCTBX_SSL_TRANSPORT_STREAM(TLS) or BCTBX_SSL_TRANSPORT_DATAGRAM(DTLS) */ int(*rng_function)(void *, unsigned char *, size_t); /**< pointer to a random number generator function */ void *rng_context; /**< pointer to a the random number generator context */ int(*callback_verify_function)(void *, x509_cert *, int, int *); /**< pointer to the verify callback function */ void *callback_verify_data; /**< data passed to the verify callback */ x509_cert *ca_chain; /**< trusted CA chain */ x509_cert *own_cert; rsa_context *own_cert_pk; int(*callback_cli_cert_function)(void *, bctbx_ssl_context_t *, unsigned char *, size_t); /**< pointer to the callback called to update client certificate during handshake callback params are user_data, ssl_context, certificate distinguished name, name length */ void *callback_cli_cert_data; /**< data passed to the client cert callback */ }; bctbx_ssl_config_t *bctbx_ssl_config_new(void) { bctbx_ssl_config_t *ssl_config = bctbx_malloc0(sizeof(bctbx_ssl_config_t)); /* set all properties to BCTBX_SSL_UNSET or NULL */ ssl_config->endpoint = BCTBX_SSL_UNSET; ssl_config->authmode = BCTBX_SSL_UNSET; ssl_config->transport = BCTBX_SSL_UNSET; ssl_config->rng_function = NULL; ssl_config->rng_context = NULL; ssl_config->callback_verify_function= NULL; ssl_config->callback_verify_data = NULL; ssl_config->callback_cli_cert_function = NULL; ssl_config->callback_cli_cert_data = NULL; ssl_config->ca_chain = NULL; ssl_config->own_cert = NULL; ssl_config->own_cert_pk = NULL; return ssl_config; } int32_t bctbx_ssl_config_set_crypto_library_config(bctbx_ssl_config_t *ssl_config, void *internal_config) { return BCTBX_ERROR_UNAVAILABLE_FUNCTION; } void bctbx_ssl_config_free(bctbx_ssl_config_t *ssl_config) { bctbx_free(ssl_config); } int32_t bctbx_ssl_config_defaults(bctbx_ssl_config_t *ssl_config, int endpoint, int transport) { if (ssl_config != NULL) { if (endpoint == BCTBX_SSL_IS_CLIENT) { ssl_config->endpoint = SSL_IS_CLIENT; } else if (endpoint == BCTBX_SSL_IS_SERVER) { ssl_config->endpoint = SSL_IS_SERVER; } else { return BCTBX_ERROR_INVALID_SSL_ENDPOINT; } /* useful only for versions of polarssl which have SSL_TRANSPORT_XXX defined */ #ifdef SSL_TRANSPORT_DATAGRAM if (transport == BCTBX_SSL_TRANSPORT_STREAM) { ssl_config->transport = SSL_TRANSPORT_STREAM; } else if (transport == BCTBX_SSL_TRANSPORT_DATAGRAM) { ssl_config->transport = SSL_TRANSPORT_DATAGRAM; } else { return BCTBX_ERROR_INVALID_SSL_TRANSPORT; } #endif return 0; } return BCTBX_ERROR_INVALID_SSL_CONFIG; } int32_t bctbx_ssl_config_set_endpoint(bctbx_ssl_config_t *ssl_config, int endpoint) { if (ssl_config == NULL) { return BCTBX_ERROR_INVALID_SSL_CONFIG; } if (endpoint == BCTBX_SSL_IS_CLIENT) { ssl_config->endpoint = SSL_IS_CLIENT; } else if (endpoint == BCTBX_SSL_IS_SERVER) { ssl_config->endpoint = SSL_IS_SERVER; } else { return BCTBX_ERROR_INVALID_SSL_ENDPOINT; } return 0; } int32_t bctbx_ssl_config_set_transport (bctbx_ssl_config_t *ssl_config, int transport) { if (ssl_config == NULL) { return BCTBX_ERROR_INVALID_SSL_CONFIG; } /* useful only for versions of polarssl which have SSL_TRANSPORT_XXX defined */ #ifdef SSL_TRANSPORT_DATAGRAM if (transport == BCTBX_SSL_TRANSPORT_STREAM) { ssl_config->transport = SSL_TRANSPORT_STREAM; } else if (transport == BCTBX_SSL_TRANSPORT_DATAGRAM) { ssl_config->transport = SSL_TRANSPORT_DATAGRAM; } else { return BCTBX_ERROR_INVALID_SSL_TRANSPORT; } #endif return 0; } int32_t bctbx_ssl_config_set_authmode(bctbx_ssl_config_t *ssl_config, int authmode) { if (ssl_config != NULL) { switch (authmode) { case BCTBX_SSL_VERIFY_NONE: ssl_config->authmode = SSL_VERIFY_NONE; break; case BCTBX_SSL_VERIFY_OPTIONAL: ssl_config->authmode = SSL_VERIFY_OPTIONAL; break; case BCTBX_SSL_VERIFY_REQUIRED: ssl_config->authmode = SSL_VERIFY_REQUIRED; break; default: return BCTBX_ERROR_INVALID_SSL_AUTHMODE; break; } return 0; } return BCTBX_ERROR_INVALID_SSL_CONFIG; } int32_t bctbx_ssl_config_set_rng(bctbx_ssl_config_t *ssl_config, int(*rng_function)(void *, unsigned char *, size_t), void *rng_context) { if (ssl_config != NULL) { ssl_config->rng_function = rng_function; ssl_config->rng_context = rng_context; } return BCTBX_ERROR_INVALID_SSL_CONFIG; } int32_t bctbx_ssl_config_set_callback_verify(bctbx_ssl_config_t *ssl_config, int(*callback_function)(void *, bctbx_x509_certificate_t *, int, uint32_t *), void *callback_data) { if (ssl_config != NULL) { ssl_config->callback_verify_function = (int(*)(void *, x509_cert *, int, int *))callback_function; ssl_config->callback_verify_data = callback_data; } return BCTBX_ERROR_INVALID_SSL_CONFIG; } int32_t bctbx_ssl_config_set_callback_cli_cert(bctbx_ssl_config_t *ssl_config, int(*callback_function)(void *, bctbx_ssl_context_t *, unsigned char *, size_t), void *callback_data) { if (ssl_config != NULL) { ssl_config->callback_cli_cert_function = callback_function; ssl_config->callback_cli_cert_data = callback_data; } return BCTBX_ERROR_INVALID_SSL_CONFIG; } int32_t bctbx_ssl_config_set_ca_chain(bctbx_ssl_config_t *ssl_config, bctbx_x509_certificate_t *ca_chain) { if (ssl_config != NULL) { ssl_config->ca_chain = (x509_cert *)ca_chain; } return BCTBX_ERROR_INVALID_SSL_CONFIG; } int32_t bctbx_ssl_config_set_own_cert(bctbx_ssl_config_t *ssl_config, bctbx_x509_certificate_t *cert, bctbx_signing_key_t *key) { if (ssl_config != NULL) { ssl_config->own_cert = (x509_cert *)cert; ssl_config->own_cert_pk = (rsa_context *)key; } return BCTBX_ERROR_INVALID_SSL_CONFIG; } /** dummy DTLS SRTP functions **/ int32_t bctbx_ssl_config_set_dtls_srtp_protection_profiles(bctbx_ssl_config_t *ssl_config, const bctbx_dtls_srtp_profile_t *profiles, size_t profiles_number) { return BCTBX_ERROR_UNAVAILABLE_FUNCTION; } /** DTLS SRTP functions **/ int32_t bctbx_ssl_context_setup(bctbx_ssl_context_t *ssl_ctx, bctbx_ssl_config_t *ssl_config) { /* Check validity of context and config */ if (ssl_config == NULL) { return BCTBX_ERROR_INVALID_SSL_CONFIG; } if (ssl_ctx == NULL) { return BCTBX_ERROR_INVALID_SSL_CONTEXT; } /* apply all valids settings to the ssl_context */ if (ssl_config->endpoint != BCTBX_SSL_UNSET) { ssl_set_endpoint(&(ssl_ctx->ssl_ctx), ssl_config->endpoint); } if (ssl_config->authmode != BCTBX_SSL_UNSET) { ssl_set_authmode(&(ssl_ctx->ssl_ctx), ssl_config->authmode); } if (ssl_config->rng_function != NULL) { ssl_set_rng(&(ssl_ctx->ssl_ctx), ssl_config->rng_function, ssl_config->rng_context); } if (ssl_config->callback_verify_function != NULL) { ssl_set_verify(&(ssl_ctx->ssl_ctx), ssl_config->callback_verify_function, ssl_config->callback_verify_data); } if (ssl_config->callback_cli_cert_function != NULL) { ssl_ctx->callback_cli_cert_function = ssl_config->callback_cli_cert_function; ssl_ctx->callback_cli_cert_data = ssl_config->callback_cli_cert_data; } if (ssl_config->ca_chain != NULL) { ssl_set_ca_chain(&(ssl_ctx->ssl_ctx), ssl_config->ca_chain, NULL, ssl_ctx->cn); } if (ssl_config->own_cert != NULL && ssl_config->own_cert_pk != NULL) { ssl_set_own_cert(&(ssl_ctx->ssl_ctx) , ssl_config->own_cert , ssl_config->own_cert_pk); } return 0; } /*****************************************************************************/ /***** Hashing *****/ /*****************************************************************************/ /** * @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 bctbx_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); } } /** * @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 bctbx_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); } } /** * @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 bctbx_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); } } /** * @brief MD5 wrapper * output = md5(input) * @param[in] input Input data buffer * @param[in] inputLength Input data length in bytes * @param[out] output Output data buffer. * */ void bctbx_md5(const uint8_t *input, size_t inputLength, uint8_t output[16]) { md5(input, inputLength, output); } /*****************************************************************************/ /***** Encryption/Decryption *****/ /*****************************************************************************/ /***** GCM *****/ /** * @Brief AES-GCM encrypt and tag buffer * * @param[in] key Encryption key * @param[in] keyLength Key buffer length, in bytes, must be 16,24 or 32 * @param[in] plainText Buffer to be encrypted * @param[in] plainTextLength Length in bytes of buffer to be encrypted * @param[in] authenticatedData Buffer holding additional data to be used in tag computation * @param[in] authenticatedDataLength Additional data length in bytes * @param[in] initializationVector Buffer holding the initialisation vector * @param[in] initializationVectorLength Initialisation vector length in bytes * @param[out] tag Buffer holding the generated tag * @param[in] tagLength Requested length for the generated tag * @param[out] output Buffer holding the output, shall be at least the length of plainText buffer */ int32_t bctbx_aes_gcm_encrypt_and_tag(const uint8_t *key, size_t keyLength, const uint8_t *plainText, size_t plainTextLength, const uint8_t *authenticatedData, size_t authenticatedDataLength, const uint8_t *initializationVector, size_t initializationVectorLength, uint8_t *tag, size_t tagLength, uint8_t *output) { gcm_context gcmContext; int ret; ret = gcm_init(&gcmContext, key, keyLength*8); if (ret != 0) return ret; ret = gcm_crypt_and_tag(&gcmContext, GCM_ENCRYPT, plainTextLength, initializationVector, initializationVectorLength, authenticatedData, authenticatedDataLength, plainText, output, tagLength, tag); return ret; } /** * @Brief AES-GCM decrypt, compute authentication tag and compare it to the one provided * * @param[in] key Encryption key * @param[in] keyLength Key buffer length, in bytes, must be 16,24 or 32 * @param[in] cipherText Buffer to be decrypted * @param[in] cipherTextLength Length in bytes of buffer to be decrypted * @param[in] authenticatedData Buffer holding additional data to be used in auth tag computation * @param[in] authenticatedDataLength Additional data length in bytes * @param[in] initializationVector Buffer holding the initialisation vector * @param[in] initializationVectorLength Initialisation vector length in bytes * @param[in] tag Buffer holding the authentication tag * @param[in] tagLength Length in bytes for the authentication tag * @param[out] output Buffer holding the output, shall be at least the length of cipherText buffer * * @return 0 on succes, BCTBX_ERROR_AUTHENTICATION_FAILED if tag doesn't match or polarssl error code */ int32_t bctbx_aes_gcm_decrypt_and_auth(const uint8_t *key, size_t keyLength, const uint8_t *cipherText, size_t cipherTextLength, const uint8_t *authenticatedData, size_t authenticatedDataLength, const uint8_t *initializationVector, size_t initializationVectorLength, const uint8_t *tag, size_t tagLength, uint8_t *output) { gcm_context gcmContext; int ret; ret = gcm_init(&gcmContext, key, keyLength*8); if (ret != 0) return ret; ret = gcm_auth_decrypt(&gcmContext, cipherTextLength, initializationVector, initializationVectorLength, authenticatedData, authenticatedDataLength, tag, tagLength, cipherText, output); if (ret == POLARSSL_ERR_GCM_AUTH_FAILED) { return BCTBX_ERROR_AUTHENTICATION_FAILED; } return ret; } /** * @Brief create and initialise an AES-GCM encryption context * * @param[in] key encryption key * @param[in] keyLength key buffer length, in bytes, must be 16,24 or 32 * @param[in] authenticatedData Buffer holding additional data to be used in tag computation (can be NULL) * @param[in] authenticatedDataLength additional data length in bytes (can be 0) * @param[in] initializationVector Buffer holding the initialisation vector * @param[in] initializationVectorLength Initialisation vector length in bytes * @param[in] mode Operation mode : BCTBX_GCM_ENCRYPT or BCTBX_GCM_DECRYPT * * @return 0 on success, crypto library error code otherwise */ bctbx_aes_gcm_context_t *bctbx_aes_gcm_context_new(const uint8_t *key, size_t keyLength, const uint8_t *authenticatedData, size_t authenticatedDataLength, const uint8_t *initializationVector, size_t initializationVectorLength, uint8_t mode) { return NULL; } /** * @Brief AES-GCM encrypt or decrypt a chunk of data * * @param[in/out] context a context already initialized using bctbx_aes_gcm_context_new * @param[in] input buffer holding the input data * @param[in] inputLength lenght of the input data * @param[out] output buffer to store the output data (same length as input one) * * @return 0 on success, crypto library error code otherwise */ int32_t bctbx_aes_gcm_process_chunk(bctbx_aes_gcm_context_t *context, const uint8_t *input, size_t inputLength, uint8_t *output) { return BCTBX_ERROR_UNAVAILABLE_FUNCTION; } /** * @Brief Conclude a AES-GCM encryption stream, generate tag if requested, free resources * * @param[in/out] context a context already initialized using bctbx_aes_gcm_context_new * @param[out] tag a buffer to hold the authentication tag. Can be NULL if tagLength is 0 * @param[in] tagLength length of reqested authentication tag, max 16 * * @return 0 on success, crypto library error code otherwise */ int32_t bctbx_aes_gcm_finish(bctbx_aes_gcm_context_t *context, uint8_t *tag, size_t tagLength) { return BCTBX_ERROR_UNAVAILABLE_FUNCTION; } /* * @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 bctbx_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 bctbx_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 bctbx_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 bctbx_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); } bctoolbox-0.6.0/src/logging/000077500000000000000000000000001313410701300157165ustar00rootroot00000000000000bctoolbox-0.6.0/src/logging/logging.c000066400000000000000000000467621313410701300175270ustar00rootroot00000000000000/* bctoolbox Copyright (C) 2016 Belledonne Communications SARL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "bctoolbox/logging.h" #include #include #include #include #ifdef _MSC_VER #ifndef access #define access _access #endif #ifndef fileno #define fileno _fileno #endif #endif typedef struct{ char *domain; unsigned int logmask; }BctoolboxLogDomain; static void bctbx_log_domain_destroy(BctoolboxLogDomain *obj){ if (obj->domain) bctbx_free(obj->domain); bctbx_free(obj); } typedef struct _bctbx_logger_t { bctbx_list_t *logv_outs; unsigned int log_mask; /*the default log mask, if no per-domain settings are found*/ unsigned long log_thread_id; bctbx_list_t *log_stored_messages_list; bctbx_list_t *log_domains; bctbx_mutex_t log_stored_messages_mutex; bctbx_mutex_t domains_mutex; bctbx_mutex_t log_mutex; } bctbx_logger_t; struct _bctbx_log_handler_t { BctbxLogHandlerFunc func; BctbxLogHandlerDestroyFunc destroy; void* user_info; }; typedef struct _bctbx_file_log_handler_t { char* path; char* name; uint64_t max_size; uint64_t size; FILE* file; } bctbx_file_log_handler_t; static bctbx_logger_t __bctbx_logger = { NULL, BCTBX_LOG_WARNING|BCTBX_LOG_ERROR|BCTBX_LOG_FATAL, 0}; static unsigned int bctbx_init_logger_refcount = 0; void bctbx_init_logger(bool_t create){ if (bctbx_init_logger_refcount++ > 0) return; /*already initialized*/ bctbx_mutex_init(&__bctbx_logger.domains_mutex, NULL); bctbx_mutex_init(&__bctbx_logger.log_mutex, NULL); if(create) { bctbx_log_handler_t* handler = bctbx_create_log_handler(bctbx_logv_out, bctbx_logv_out_destroy, NULL); bctbx_add_log_handler(handler); } } void bctbx_log_handlers_free(void) { bctbx_list_t *loggers = bctbx_list_first_elem(__bctbx_logger.logv_outs); while (loggers) { bctbx_log_handler_t* handler = (bctbx_log_handler_t*)loggers->data; handler->destroy(handler); loggers = loggers->next; } } void bctbx_uninit_logger(void){ if (--bctbx_init_logger_refcount <= 0) { bctbx_logv_flush(); bctbx_mutex_destroy(&__bctbx_logger.domains_mutex); bctbx_mutex_destroy(&__bctbx_logger.log_mutex); bctbx_log_handlers_free(); __bctbx_logger.logv_outs = bctbx_list_free(__bctbx_logger.logv_outs); __bctbx_logger.log_domains = bctbx_list_free_with_data(__bctbx_logger.log_domains, (void (*)(void*))bctbx_log_domain_destroy); } } bctbx_log_handler_t* bctbx_create_log_handler(BctbxLogHandlerFunc func, BctbxLogHandlerDestroyFunc destroy, void* user_info) { bctbx_log_handler_t* handler = (bctbx_log_handler_t*)bctbx_malloc(sizeof(bctbx_log_handler_t)); handler->func = func; handler->destroy = destroy; handler->user_info = user_info; return handler; } bctbx_log_handler_t* bctbx_create_file_log_handler(uint64_t max_size, const char* path, const char* name, FILE* f) { bctbx_log_handler_t* handler = (bctbx_log_handler_t*)bctbx_malloc0(sizeof(bctbx_log_handler_t)); bctbx_file_log_handler_t* filehandler = (bctbx_file_log_handler_t*)bctbx_malloc(sizeof(bctbx_file_log_handler_t)); char *full_name = bctbx_strdup_printf("%s/%s", path, name); struct stat buf; memset(&buf, 0, sizeof(buf)); handler->func=bctbx_logv_file; handler->destroy=bctbx_logv_file_destroy; filehandler->max_size = max_size; // init with actual file size if(stat(full_name, &buf) != 0) { fprintf(stderr,"Error while creating file log handler. \n"); return NULL; } bctbx_free(full_name); filehandler->size = buf.st_size; filehandler->path = bctbx_strdup(path); filehandler->name = bctbx_strdup(name); filehandler->file = f; handler->user_info=(void*) filehandler; return handler; } /** *@param func: your logging function, compatible with the BctoolboxLogFunc prototype. * **/ void bctbx_add_log_handler(bctbx_log_handler_t* handler){ if (handler && !bctbx_list_find(__bctbx_logger.logv_outs, handler)) __bctbx_logger.logv_outs = bctbx_list_append(__bctbx_logger.logv_outs, (void*)handler); /*else, already in*/ } static void wrapper(void* info,const char *domain, BctbxLogLevel lev, const char *fmt, va_list args) { BctbxLogFunc func = (BctbxLogFunc)info; func(domain, lev, fmt, args); } void bctbx_set_log_handler(BctbxLogFunc func){ static bctbx_log_handler_t handler; handler.func=wrapper; handler.destroy=(BctbxLogHandlerDestroyFunc)bctbx_logv_out_destroy; handler.user_info=(void*)func; bctbx_add_log_handler(&handler); } void bctbx_set_log_file(FILE* f){ static bctbx_file_log_handler_t filehandler; static bctbx_log_handler_t handler; handler.func=bctbx_logv_file; handler.destroy=(BctbxLogHandlerDestroyFunc)bctbx_logv_file_destroy; filehandler.max_size = -1; filehandler.file = f; handler.user_info=(void*) &filehandler; bctbx_add_log_handler(&handler); } bctbx_list_t* bctbx_get_log_handlers(void){ return __bctbx_logger.logv_outs; } static BctoolboxLogDomain * get_log_domain(const char *domain){ bctbx_list_t *it; if (domain == NULL) return NULL; for (it = __bctbx_logger.log_domains; it != NULL; it = bctbx_list_next(it)) { BctoolboxLogDomain *ld = (BctoolboxLogDomain*)bctbx_list_get_data(it); if (ld->domain && strcmp(ld->domain, domain) == 0 ){ return ld; } } return NULL; } static BctoolboxLogDomain *get_log_domain_rw(const char *domain){ BctoolboxLogDomain *ret; if (domain == NULL) return NULL; ret = get_log_domain(domain); if (ret) return ret; /*it does not exist, hence create it by taking the mutex*/ bctbx_mutex_lock(&__bctbx_logger.domains_mutex); ret = get_log_domain(domain); if (!ret){ ret = bctbx_new0(BctoolboxLogDomain,1); ret->domain = bctbx_strdup(domain); ret->logmask = __bctbx_logger.log_mask; __bctbx_logger.log_domains = bctbx_list_prepend(__bctbx_logger.log_domains, ret); } bctbx_mutex_unlock(&__bctbx_logger.domains_mutex); return ret; } /** * @ param levelmask a mask of BCTBX_DEBUG, BCTBX_MESSAGE, BCTBX_WARNING, BCTBX_ERROR * BCTBX_FATAL . **/ void bctbx_set_log_level_mask(const char *domain, int levelmask){ if (domain == NULL) __bctbx_logger.log_mask=levelmask; else get_log_domain_rw(domain)->logmask = levelmask; } void bctbx_set_log_level(const char *domain, BctbxLogLevel level){ int levelmask = BCTBX_LOG_FATAL; if (level<=BCTBX_LOG_ERROR){ levelmask |= BCTBX_LOG_ERROR; } if (level<=BCTBX_LOG_WARNING){ levelmask |= BCTBX_LOG_WARNING; } if (level<=BCTBX_LOG_MESSAGE){ levelmask |= BCTBX_LOG_MESSAGE; } if (level<=BCTBX_LOG_TRACE) { levelmask |= BCTBX_LOG_TRACE; } if (level<=BCTBX_LOG_DEBUG){ levelmask |= BCTBX_LOG_DEBUG; } bctbx_set_log_level_mask(domain, levelmask); } unsigned int bctbx_get_log_level_mask(const char *domain) { BctoolboxLogDomain *ld; if (domain == NULL || (ld = get_log_domain(domain)) == NULL) return __bctbx_logger.log_mask; else return ld->logmask; } void bctbx_set_log_thread_id(unsigned long thread_id) { if (thread_id == 0) { bctbx_logv_flush(); bctbx_mutex_destroy(&__bctbx_logger.log_stored_messages_mutex); } else { bctbx_mutex_init(&__bctbx_logger.log_stored_messages_mutex, NULL); } __bctbx_logger.log_thread_id = thread_id; } char * bctbx_strdup_vprintf(const char *fmt, va_list ap) { /* Guess we need no more than 100 bytes. */ int n, size = 200; char *p,*np; #ifndef _WIN32 va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/ #endif if ((p = (char *) bctbx_malloc (size)) == NULL) return NULL; while (1){ /* Try to print in the allocated space. */ #ifndef _WIN32 va_copy(cap,ap); n = vsnprintf (p, size, fmt, cap); va_end(cap); #else /*this works on 32 bits, luckily*/ n = vsnprintf (p, size, fmt, ap); #endif /* If that worked, return the string. */ if (n > -1 && n < size) return p; //printf("Reallocing space.\n"); /* Else try again with more space. */ if (n > -1) /* glibc 2.1 */ size = n + 1; /* precisely what is needed */ else /* glibc 2.0 */ size *= 2; /* twice the old size */ if ((np = (char *) bctbx_realloc (p, size)) == NULL) { free(p); return NULL; } else { p = np; } } } char *bctbx_strdup_printf(const char *fmt,...){ char *ret; va_list args; va_start (args, fmt); ret=bctbx_strdup_vprintf(fmt, args); va_end (args); return ret; } char * bctbx_strcat_vprintf(char* dst, const char *fmt, va_list ap){ char *ret; size_t dstlen, retlen; ret=bctbx_strdup_vprintf(fmt, ap); if (!dst) return ret; dstlen = strlen(dst); retlen = strlen(ret); if ((dst = bctbx_realloc(dst, dstlen+retlen+1)) != NULL){ strncat(dst,ret,retlen); dst[dstlen+retlen] = '\0'; bctbx_free(ret); return dst; } else { bctbx_free(ret); return NULL; } } char *bctbx_strcat_printf(char* dst, const char *fmt,...){ char *ret; va_list args; va_start (args, fmt); ret=bctbx_strcat_vprintf(dst, fmt, args); va_end (args); return ret; } #if defined(_WIN32) || defined(_WIN32_WCE) #define ENDLINE "\r\n" #else #define ENDLINE "\n" #endif typedef struct { int level; char *msg; char *domain; } bctbx_stored_log_t; void _bctbx_logv_flush(int dummy, ...) { bctbx_list_t *elem; bctbx_list_t *msglist; va_list empty_va_list; va_start(empty_va_list, dummy); bctbx_mutex_lock(&__bctbx_logger.log_stored_messages_mutex); msglist = __bctbx_logger.log_stored_messages_list; __bctbx_logger.log_stored_messages_list = NULL; bctbx_mutex_unlock(&__bctbx_logger.log_stored_messages_mutex); for (elem = msglist; elem != NULL; elem = bctbx_list_next(elem)) { bctbx_stored_log_t *l = (bctbx_stored_log_t *)bctbx_list_get_data(elem); bctbx_list_t *loggers = bctbx_list_first_elem(__bctbx_logger.logv_outs); #ifdef _WIN32 while (loggers) { bctbx_log_handler_t* handler = (bctbx_log_handler_t*)loggers->data; if(handler) { va_list cap; va_copy(cap, empty_va_list); handler->func(handler->user_info, l->domain, l->level, l->msg, cap); va_end(cap); } loggers = loggers->next; } #else while (loggers) { bctbx_log_handler_t* handler = (bctbx_log_handler_t*)loggers->data; if(handler) { va_list cap; va_copy(cap, empty_va_list); handler->func(handler->user_info, l->domain, l->level, l->msg, cap); va_end(cap); } loggers = loggers->next; } #endif if (l->domain) bctbx_free(l->domain); bctbx_free(l->msg); bctbx_free(l); } bctbx_list_free(msglist); va_end(empty_va_list); } void bctbx_logv_flush(void) { _bctbx_logv_flush(0); } void bctbx_logv(const char *domain, BctbxLogLevel level, const char *fmt, va_list args) { if ((__bctbx_logger.logv_outs != NULL) && bctbx_log_level_enabled(domain, level)) { if (__bctbx_logger.log_thread_id == 0) { bctbx_list_t *loggers = bctbx_list_first_elem(__bctbx_logger.logv_outs); while (loggers) { bctbx_log_handler_t* handler = (bctbx_log_handler_t*)loggers->data; if(handler) { va_list tmp; va_copy(tmp, args); handler->func(handler->user_info, domain, level, fmt, tmp); va_end(tmp); } loggers = loggers->next; } } else if (__bctbx_logger.log_thread_id == bctbx_thread_self()) { bctbx_list_t *loggers; bctbx_logv_flush(); loggers = bctbx_list_first_elem(__bctbx_logger.logv_outs); while (loggers) { bctbx_log_handler_t* handler = (bctbx_log_handler_t*)loggers->data; if(handler) { va_list tmp; va_copy(tmp, args); handler->func(handler->user_info, domain, level, fmt, tmp); va_end(tmp); } loggers = loggers->next; } } else { bctbx_stored_log_t *l = bctbx_new(bctbx_stored_log_t, 1); l->domain = domain ? bctbx_strdup(domain) : NULL; l->level = level; l->msg = bctbx_strdup_vprintf(fmt, args); bctbx_mutex_lock(&__bctbx_logger.log_stored_messages_mutex); __bctbx_logger.log_stored_messages_list = bctbx_list_append(__bctbx_logger.log_stored_messages_list, l); bctbx_mutex_unlock(&__bctbx_logger.log_stored_messages_mutex); } } #if !defined(_WIN32_WCE) if (level == BCTBX_LOG_FATAL) { bctbx_logv_flush(); abort(); } #endif } /*This function does the default formatting and output to file*/ void bctbx_logv_out(void* user_info, const char *domain, BctbxLogLevel lev, const char *fmt, va_list args){ const char *lname="undef"; char *msg; struct timeval tp; struct tm *lt; #ifndef _WIN32 struct tm tmbuf; #endif time_t tt; FILE *std = stdout; bctbx_gettimeofday(&tp,NULL); tt = (time_t)tp.tv_sec; #ifdef _WIN32 lt = localtime(&tt); #else lt = localtime_r(&tt,&tmbuf); #endif switch(lev){ case BCTBX_LOG_DEBUG: lname = "debug"; break; case BCTBX_LOG_MESSAGE: lname = "message"; break; case BCTBX_LOG_WARNING: lname = "warning"; break; case BCTBX_LOG_ERROR: lname = "error"; std = stderr; break; case BCTBX_LOG_FATAL: lname = "fatal"; std = stderr; break; default: lname = "badlevel"; } msg=bctbx_strdup_vprintf(fmt,args); #if defined(_MSC_VER) && !defined(_WIN32_WCE) #ifndef _UNICODE OutputDebugStringA(msg); OutputDebugStringA("\r\n"); #else { size_t len=strlen(msg); wchar_t *tmp=(wchar_t*)bctbx_malloc0((len+1)*sizeof(wchar_t)); mbstowcs(tmp,msg,len); OutputDebugStringW(tmp); OutputDebugStringW(L"\r\n"); bctbx_free(tmp); } #endif #endif fprintf(std,"%i-%.2i-%.2i %.2i:%.2i:%.2i:%.3i %s-%s-%s" ENDLINE ,1900+lt->tm_year,1+lt->tm_mon,lt->tm_mday,lt->tm_hour,lt->tm_min,lt->tm_sec ,(int)(tp.tv_usec/1000), (domain?domain:"bctoolbox"), lname, msg); fflush(std); bctbx_free(msg); } void bctbx_logv_out_destroy(bctbx_log_handler_t* handler) { handler->user_info=NULL; } static int _try_open_log_collection_file(bctbx_file_log_handler_t *filehandler) { struct stat statbuf; char *log_filename; log_filename = bctbx_strdup_printf("%s/%s", filehandler->path, filehandler->name); filehandler->file = fopen(log_filename, "a"); bctbx_free(log_filename); if (filehandler->file == NULL) return -1; fstat(fileno(filehandler->file), &statbuf); if ((uint64_t)statbuf.st_size > filehandler->max_size) { fclose(filehandler->file); return -1; } filehandler->size = statbuf.st_size; return 0; } static void _rotate_log_collection_files(bctbx_file_log_handler_t *filehandler) { char *log_filename; char *log_filename2; char *file_no_extension = bctbx_strdup(filehandler->name); char *extension = strrchr(file_no_extension, '.'); char *extension2 = bctbx_strdup(extension); int n = 1; file_no_extension[extension - file_no_extension] = '\0'; log_filename = bctbx_strdup_printf("%s/%s_1%s", filehandler->path, file_no_extension, extension2); while(access(log_filename, F_OK) != -1) { // file exists n++; log_filename = bctbx_strdup_printf("%s/%s_%d%s", filehandler->path, file_no_extension, n, extension2); } while(n > 1) { log_filename = bctbx_strdup_printf("%s/%s_%d%s", filehandler->path, file_no_extension, n-1, extension2); log_filename2 = bctbx_strdup_printf("%s/%s_%d%s", filehandler->path, file_no_extension, n, extension2); n--; rename(log_filename, log_filename2); } log_filename = bctbx_strdup_printf("%s/%s", filehandler->path, filehandler->name); log_filename2 = bctbx_strdup_printf("%s/%s_1%s", filehandler->path, file_no_extension, extension2); rename(log_filename, log_filename2); bctbx_free(log_filename); bctbx_free(log_filename2); bctbx_free(extension2); bctbx_free(file_no_extension); } static void _open_log_collection_file(bctbx_file_log_handler_t *filehandler) { if (_try_open_log_collection_file(filehandler) < 0) { _rotate_log_collection_files(filehandler); _try_open_log_collection_file(filehandler); } } static void _close_log_collection_file(bctbx_file_log_handler_t *filehandler) { if (filehandler->file) { fclose(filehandler->file); filehandler->file = NULL; filehandler->size = 0; } } void bctbx_logv_file(void* user_info, const char *domain, BctbxLogLevel lev, const char *fmt, va_list args){ const char *lname="undef"; char *msg; struct timeval tp; struct tm *lt; #ifndef _WIN32 struct tm tmbuf; #endif time_t tt; int ret = -1; bctbx_file_log_handler_t *filehandler = (bctbx_file_log_handler_t *) user_info; FILE *f; bctbx_mutex_lock(&__bctbx_logger.log_mutex); f = filehandler->file; bctbx_gettimeofday(&tp,NULL); tt = (time_t)tp.tv_sec; #ifdef _WIN32 lt = localtime(&tt); #else lt = localtime_r(&tt,&tmbuf); #endif if(!f) { return; } switch(lev){ case BCTBX_LOG_DEBUG: lname = "debug"; break; case BCTBX_LOG_MESSAGE: lname = "message"; break; case BCTBX_LOG_WARNING: lname = "warning"; break; case BCTBX_LOG_ERROR: lname = "error"; break; case BCTBX_LOG_FATAL: lname = "fatal"; break; default: lname = "badlevel"; } msg=bctbx_strdup_vprintf(fmt,args); #if defined(_MSC_VER) && !defined(_WIN32_WCE) #ifndef _UNICODE OutputDebugStringA(msg); OutputDebugStringA("\r\n"); #else { size_t len=strlen(msg); wchar_t *tmp=(wchar_t*)bctbx_malloc0((len+1)*sizeof(wchar_t)); mbstowcs(tmp,msg,len); OutputDebugStringW(tmp); OutputDebugStringW(L"\r\n"); bctbx_free(tmp); } #endif #endif ret = fprintf(f,"%i-%.2i-%.2i %.2i:%.2i:%.2i:%.3i %s-%s-%s" ENDLINE ,1900+lt->tm_year,1+lt->tm_mon,lt->tm_mday,lt->tm_hour,lt->tm_min,lt->tm_sec ,(int)(tp.tv_usec/1000), (domain?domain:"bctoolbox"), lname, msg); fflush(f); if (filehandler->max_size > 0 && ret > 0) { filehandler->size += ret; if (filehandler->size > filehandler->max_size) { _close_log_collection_file(filehandler); _open_log_collection_file(filehandler); } } bctbx_mutex_unlock(&__bctbx_logger.log_mutex); bctbx_free(msg); } void bctbx_logv_file_destroy(bctbx_log_handler_t* handler) { bctbx_file_log_handler_t *filehandler = (bctbx_file_log_handler_t *) handler->user_info; fclose(filehandler->file); bctbx_free(filehandler->path); bctbx_free(filehandler->name); bctbx_logv_out_destroy(handler); } #ifdef __QNX__ #include static bool_t slog2_registered = FALSE; static slog2_buffer_set_config_t slog2_buffer_config; static slog2_buffer_t slog2_buffer_handle[2]; void bctbx_qnx_log_handler(const char *domain, BctbxLogLevel lev, const char *fmt, va_list args) { uint8_t severity = SLOG2_DEBUG1; uint8_t buffer_idx = 1; char* msg; if (slog2_registered != TRUE) { slog2_buffer_config.buffer_set_name = domain; slog2_buffer_config.num_buffers = 2; slog2_buffer_config.verbosity_level = SLOG2_DEBUG2; slog2_buffer_config.buffer_config[0].buffer_name = "hi_rate"; slog2_buffer_config.buffer_config[0].num_pages = 6; slog2_buffer_config.buffer_config[1].buffer_name = "lo_rate"; slog2_buffer_config.buffer_config[1].num_pages = 2; if (slog2_register(&slog2_buffer_config, slog2_buffer_handle, 0) == 0) { slog2_registered = TRUE; } else { fprintf(stderr, "Error registering slogger2 buffer!\n"); return; } } switch(lev){ case BCTBX_LOG_DEBUG: severity = SLOG2_DEBUG1; break; case BCTBX_LOG_MESSAGE: severity = SLOG2_INFO; break; case BCTBX_LOG_WARNING: severity = SLOG2_WARNING; break; case BCTBX_LOG_ERROR: severity = SLOG2_ERROR; break; case BCTBX_LOG_FATAL: severity = SLOG2_CRITICAL; break; default: severity = SLOG2_CRITICAL; } msg = bctbx_strdup_vprintf(fmt,args); slog2c(slog2_buffer_handle[buffer_idx], 0, severity, msg); } #endif /* __QNX__ */ bctoolbox-0.6.0/src/parser.c000066400000000000000000000053201313410701300157300ustar00rootroot00000000000000/* parser.c Copyright (C) 2017 Belledonne Communications SARL This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "bctoolbox/port.h" #include "bctoolbox/parser.h" #include "bctoolbox/logging.h" char* bctbx_escape(const char* buff, const bctbx_noescape_rules_t noescapes) { size_t outbuf_size=strlen(buff); size_t orig_size=outbuf_size; char *output_buff=(char*)bctbx_malloc(outbuf_size + 1); int i; size_t out_buff_index=0; for(i=0; buff[i] != '\0'; i++) { int c = ((unsigned char*)buff)[i]; if (outbuf_size < out_buff_index + 3){ // we will possibly add 3 chars outbuf_size += MAX(orig_size/2,3); output_buff = bctbx_realloc(output_buff, outbuf_size + 1); } if (noescapes[c] == 1) { output_buff[out_buff_index++]=c; } else { // this will write 3 characters out_buff_index+=snprintf(output_buff+out_buff_index, outbuf_size +1 - out_buff_index, "%%%02x", c); } } output_buff[out_buff_index]='\0'; return output_buff; } void bctbx_noescape_rules_add_list(bctbx_noescape_rules_t noescapes, const char *allowed) { while (*allowed) { noescapes[(unsigned int) *allowed] = 1; ++allowed; } } void bctbx_noescape_rules_add_range(bctbx_noescape_rules_t noescapes, char first, char last) { memset(noescapes + (unsigned int)first, 1, last-first+1); } void bctbx_noescape_rules_add_alfanums(bctbx_noescape_rules_t noescapes) { bctbx_noescape_rules_add_range(noescapes, '0', '9'); bctbx_noescape_rules_add_range(noescapes, 'A', 'Z'); bctbx_noescape_rules_add_range(noescapes, 'a', 'z'); } static int is_escaped_char(const char *a){ return a[0] == '%' && a[1] != '\0' && a[2] != '\0'; } size_t bctbx_get_char (const char*a, char*out) { if (is_escaped_char(a)) { unsigned int tmp; sscanf(a+1,"%02x",&tmp); *out=(char)tmp; return 3; } else { *out=*a; return 1; } } char* bctbx_unescaped_string(const char* buff) { char *output_buff=bctbx_malloc(strlen(buff)+1); size_t i; size_t out_buff_index=0; for(i=0; buff[i]!='\0'; out_buff_index++) { i+=bctbx_get_char(buff+i,output_buff+out_buff_index); } output_buff[out_buff_index]='\0'; return output_buff; } bctoolbox-0.6.0/src/tester.c000066400000000000000000000606501313410701300157510ustar00rootroot00000000000000/* tester - liblinphone test suite Copyright (C) 2013 Belledonne Communications SARL 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, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #ifndef _WIN32 #include #endif #ifndef IN_BCUNIT_SOURCES #include #include #include #include #else #include "Basic.h" #include "Automated.h" #include "MyMem.h" #include "Util.h" #endif #ifdef _WIN32 #if defined(__MINGW32__) || !defined(WINAPI_FAMILY_PARTITION) || !defined(WINAPI_PARTITION_DESKTOP) #define BC_TESTER_WINDOWS_DESKTOP 1 #elif defined(WINAPI_FAMILY_PARTITION) #if defined(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define BC_TESTER_WINDOWS_DESKTOP 1 #elif defined(WINAPI_PARTITION_PHONE_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) #define BC_TESTER_WINDOWS_PHONE 1 #elif defined(WINAPI_PARTITION_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) #define BC_TESTER_WINDOWS_UNIVERSAL 1 #endif #endif #endif #ifdef __linux /*for monitoring total space allocated via malloc*/ #include #endif #ifndef F_OK #define F_OK 00 /* Visual Studio does not define F_OK */ #endif #ifdef HAVE_BCUNIT_CUCURSES_H #define HAVE_CU_CURSES 1 #endif static char *bc_tester_resource_dir_prefix = NULL; // by default writable will always write near the executable static char *bc_tester_writable_dir_prefix = NULL; static char *bc_current_suite_name = NULL; static char *bc_current_test_name = NULL; int bc_printf_verbosity_info; int bc_printf_verbosity_error; static test_suite_t **test_suite = NULL; static int nb_test_suites = 0; #ifdef HAVE_CU_CURSES #include "BCUnit/CUCurses.h" static unsigned char curses = 0; #endif char* xml_file = "BCUnitAutomated-Results.xml"; int xml_enabled = 0; char * suite_name = NULL; char * test_name = NULL; char * tag_name = NULL; char * expected_res = NULL; static size_t max_vm_kb = 0; int run_skipped_tests = 0; static void (*tester_printf_va)(int level, const char *format, va_list args)=NULL; void bc_tester_printf(int level, const char *format, ...) { va_list args; va_start (args, format); if (tester_printf_va) { tester_printf_va(level, format, args); }else{ vfprintf(stderr, format, args); } va_end (args); } int bc_tester_run_suite(test_suite_t *suite, const char *tag_name) { int i; CU_pSuite pSuite; if (tag_name != NULL) { size_t j; int nb_tests_for_tag = 0; for (i = 0; i < suite->nb_tests; i++) { for (j = 0; j < (sizeof(suite->tests[i].tags) / sizeof(suite->tests[i].tags[0])); j++) { if ((suite->tests[i].tags[j] != NULL) && (strcasecmp(tag_name, suite->tests[i].tags[j]) == 0)) { nb_tests_for_tag++; } } } if (nb_tests_for_tag > 0) { pSuite = CU_add_suite_with_setup_and_teardown(suite->name, suite->before_all, suite->after_all, suite->before_each, suite->after_each); for (i = 0; i < suite->nb_tests; i++) { for (j = 0; j < (sizeof(suite->tests[i].tags) / sizeof(suite->tests[i].tags[0])); j++) { if ((suite->tests[i].tags[j] != NULL) && (strcasecmp(tag_name, suite->tests[i].tags[j]) == 0)) { if (NULL == CU_add_test(pSuite, suite->tests[i].name, suite->tests[i].func)) { return CU_get_error(); } } } } } } else { pSuite = CU_add_suite_with_setup_and_teardown(suite->name, suite->before_all, suite->after_all, suite->before_each, suite->after_each); for (i = 0; i < suite->nb_tests; i++) { size_t j; bool_t skip = FALSE; for (j = 0; j < (sizeof(suite->tests[i].tags) / sizeof(suite->tests[i].tags[0])); j++) { if ((suite->tests[i].tags[j] != NULL) && (strcasecmp("Skip", suite->tests[i].tags[j]) == 0) && (run_skipped_tests == 0)) { skip = TRUE; } } if (!skip) { if (NULL == CU_add_test(pSuite, suite->tests[i].name, suite->tests[i].func)) { return CU_get_error(); } } } } return 0; } const char * bc_tester_suite_name(int suite_index) { if (suite_index >= nb_test_suites) return NULL; return test_suite[suite_index]->name; } int bc_tester_suite_index(const char *suite_name) { int i; for (i = 0; i < nb_test_suites; i++) { if (strcmp(suite_name, test_suite[i]->name) == 0) { return i; } } return -1; } int bc_tester_test_index(test_suite_t *suite, const char *test_name) { int i; for (i = 0; i < suite->nb_tests; i++) { if (strcmp(test_name, suite->tests[i].name) == 0) { return i; } } return -1; } int bc_tester_nb_suites(void) { return nb_test_suites; } const char * bc_tester_test_name(const char *suite_name, int test_index) { test_suite_t *suite = NULL; size_t j = 0; bool_t skip = FALSE; int suite_index = bc_tester_suite_index(suite_name); if ((suite_index < 0) || (suite_index >= nb_test_suites)) return NULL; suite = test_suite[suite_index]; if (test_index >= suite->nb_tests) return NULL; for (j = 0; j < (sizeof(suite->tests[test_index].tags) / sizeof(suite->tests[test_index].tags[0])); j++) { if ((suite->tests[test_index].tags[j] != NULL) && (strcasecmp("Skip", suite->tests[test_index].tags[j]) == 0) && (run_skipped_tests == 0)) { skip = TRUE; } } if (skip) return NULL; return suite->tests[test_index].name; } int bc_tester_nb_tests(const char *suite_name) { int i = bc_tester_suite_index(suite_name); if (i < 0) return 0; return test_suite[i]->nb_tests; } void bc_tester_list_suites(void) { int j; for(j=0;jpName); } static void suite_cleanup_failure_message_handler(const CU_pSuite pSuite) { bc_tester_printf(bc_printf_verbosity_error,"Suite cleanup failed for [%s]", pSuite->pName); } #ifdef HAVE_CU_GET_SUITE static uint64_t suite_start_time = 0; static void suite_start_message_handler(const CU_pSuite pSuite) { bc_tester_printf(bc_printf_verbosity_info,"Suite [%s] started\n", pSuite->pName); suite_start_time = bctbx_get_cur_time_ms(); bc_current_suite_name = pSuite->pName; } static void suite_complete_message_handler(const CU_pSuite pSuite, const CU_pFailureRecord pFailure) { bc_tester_printf(bc_printf_verbosity_info, "Suite [%s] ended in %.3f sec\n", pSuite->pName, (bctbx_get_cur_time_ms() - suite_start_time) / 1000.f); } static uint64_t test_start_time = 0; static void test_start_message_handler(const CU_pTest pTest, const CU_pSuite pSuite) { bc_tester_printf(bc_printf_verbosity_info,"Suite [%s] Test [%s] started", pSuite->pName,pTest->pName); test_start_time = bctbx_get_cur_time_ms(); bc_current_test_name = pTest->pName; } /*derivated from bcunit*/ static void test_complete_message_handler(const CU_pTest pTest, const CU_pSuite pSuite, const CU_pFailureRecord pFailureList) { int i; CU_pFailureRecord pFailure = pFailureList; char *buffer = NULL; char* result = bc_sprintf("Suite [%s] Test [%s] %s in %.3f secs", pSuite->pName, pTest->pName, pFailure ? "failed" : "passed", (bctbx_get_cur_time_ms() - test_start_time) / 1000.f); if (pFailure) { for (i = 1; (NULL != pFailure); pFailure = pFailure->pNext, i++) { buffer = bc_sprintf("%s\n %d. %s:%u - %s", result, i, (NULL != pFailure->strFileName) ? pFailure->strFileName : "", pFailure->uiLineNumber, (NULL != pFailure->strCondition) ? pFailure->strCondition : ""); free(result); result = buffer; } } bc_tester_printf(bc_printf_verbosity_info,"%s", result); free(result); //insert empty line bc_tester_printf(bc_printf_verbosity_info,""); #ifdef __linux /* use mallinfo() to monitor allocated space. It is linux specific but other methods don't work: * setrlimit() RLIMIT_DATA doesn't count memory allocated via mmap() (which is used internally by malloc) * setrlimit() RLIMIT_AS works but also counts virtual memory allocated by thread stacks, which is very big and * hardly controllable. * setrlimit() RLIMIT_RSS does nothing interesting on linux. * getrusage() of RSS is unreliable: memory blocks can be leaked without being read or written, which would not * appear in RSS. * mallinfo() itself is the less worse solution. Allocated bytes are returned as 'int' so limited to 2GB */ if (max_vm_kb) { struct mallinfo minfo = mallinfo(); if ((size_t)minfo.uordblks > max_vm_kb * 1024) { bc_tester_printf( bc_printf_verbosity_error, "The program exceeded the maximum amount of memory allocatable (%i bytes), aborting now.\n", minfo.uordblks); abort(); } } #endif } #endif int bc_tester_run_tests(const char *suite_name, const char *test_name, const char *tag_name) { int i; /* initialize the BCUnit test registry */ if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error(); for (i = 0; i < nb_test_suites; i++) { bc_tester_run_suite(test_suite[i], tag_name); } #ifdef HAVE_CU_GET_SUITE CU_set_suite_start_handler(suite_start_message_handler); CU_set_suite_complete_handler(suite_complete_message_handler); CU_set_test_start_handler(test_start_message_handler); CU_set_test_complete_handler(test_complete_message_handler); #endif CU_set_all_test_complete_handler(all_complete_message_handler); CU_set_suite_init_failure_handler(suite_init_failure_message_handler); CU_set_suite_cleanup_failure_handler(suite_cleanup_failure_message_handler); if (xml_enabled == 1) { CU_automated_run_tests(); } else { #ifndef HAVE_CU_GET_SUITE if( suite_name ){ bc_tester_printf(bc_printf_verbosity_info, "Tester compiled without CU_get_suite() function, running all tests instead of suite '%s'", suite_name); } #else if (suite_name){ CU_pSuite suite; suite=CU_get_suite(suite_name); if (!suite) { if (tag_name != NULL) { bc_tester_printf(bc_printf_verbosity_error, "Could not find suite '%s' or this suite has no tests with tag '%s'. Available suites are:", suite_name, tag_name); } else { bc_tester_printf(bc_printf_verbosity_error, "Could not find suite '%s'. Available suites are:", suite_name); } bc_tester_list_suites(); return -1; } else if (test_name) { CU_pTest test=CU_get_test_by_name(test_name, suite); if (!test) { if (tag_name != NULL) { bc_tester_printf(bc_printf_verbosity_error, "Could not find test '%s' in suite '%s' or this test is not tagged '%s'. Available tests are:", test_name, suite_name, tag_name); } else { bc_tester_printf(bc_printf_verbosity_error, "Could not find test '%s' in suite '%s'. Available tests are:", test_name, suite_name); } // do not use suite_name here, since this method is case sensitive bc_tester_list_tests(suite->pName); return -2; } else { CU_ErrorCode err= CU_run_test(suite, test); if (err != CUE_SUCCESS) bc_tester_printf(bc_printf_verbosity_error, "CU_basic_run_test error %d", err); } } else { CU_run_suite(suite); } } else #endif { #ifdef HAVE_CU_CURSES if (curses) { /* Run tests using the BCUnit curses interface */ CU_curses_run_tests(); } else #endif { /* Run all tests using the BCUnit Basic interface */ CU_run_all_tests(); } } } #ifdef __linux bc_tester_printf(bc_printf_verbosity_info, "Still %i kilobytes allocated when all tests are finished.", mallinfo().uordblks / 1024); #endif return CU_get_number_of_tests_failed()!=0; } #if !defined(BC_TESTER_WINDOWS_PHONE) && !defined(BC_TESTER_WINDOWS_UNIVERSAL) && !defined(__QNX__) && !defined(__ANDROID__) && !defined(IOS) static int file_exists(const char* root_path) { char * res_path = bc_sprintf("%s/%s", root_path, expected_res); int err = bctbx_file_exist(res_path); free(res_path); return err == 0; } #endif static void detect_res_prefix(const char* prog) { char* progpath = NULL; char* progname = NULL; FILE* writable_file = NULL; if (prog != NULL) { char *ptr; progpath = strdup(prog); if (strchr(prog, '/') != NULL) { progpath[strrchr(prog, '/') - prog + 1] = '\0'; } else if (strchr(prog, '\\') != NULL) { progpath[strrchr(prog, '\\') - prog + 1] = '\0'; } ptr = strrchr(prog, '/'); if (ptr == NULL) { ptr = strrchr(prog, '\\'); } if (ptr != NULL) { #ifdef BC_TESTER_WINDOWS_DESKTOP char *exe = strstr(prog, ".exe"); if (exe != NULL) exe[0] = '\0'; #endif progname = strdup(ptr + 1); } } #if !defined(BC_TESTER_WINDOWS_PHONE) && !defined(BC_TESTER_WINDOWS_UNIVERSAL) && !defined(__QNX__) && !defined(__ANDROID__) && !defined(IOS) { char* prefix = NULL; char *installed_resources_path = NULL; if ((progname != NULL) && (progpath != NULL)) { installed_resources_path = bc_sprintf("%s../share/%s", progpath, progname); } if (file_exists(".")) { prefix = strdup("."); } else if (file_exists("..")) { prefix = strdup(".."); } else if ((installed_resources_path != NULL) && file_exists(installed_resources_path)) { prefix = strdup(installed_resources_path); } else if (progpath) { //for autotools, binary is in .libs/ subdirectory char * progpath2 = bc_sprintf("%s/../", progpath); if (file_exists(progpath)) { prefix = strdup(progpath); } else if (file_exists(progpath2)) { prefix = strdup(progpath2); } free(progpath2); } if (installed_resources_path != NULL) free(installed_resources_path); if (bc_tester_resource_dir_prefix != NULL && !file_exists(bc_tester_resource_dir_prefix)) { bc_tester_printf(bc_printf_verbosity_error, "Invalid provided resource directory: could not find expected resources '%s' in '%s'.", expected_res, bc_tester_resource_dir_prefix); free(bc_tester_resource_dir_prefix); bc_tester_resource_dir_prefix = NULL; } if (prefix != NULL) { if (bc_tester_resource_dir_prefix == NULL) { bc_tester_printf(bc_printf_verbosity_error, "Resource directory set to %s", prefix); bc_tester_set_resource_dir_prefix(prefix); } if (bc_tester_writable_dir_prefix == NULL) { bc_tester_printf(bc_printf_verbosity_error, "Writable directory set to %s", prefix); bc_tester_set_writable_dir_prefix(prefix); } free(prefix); } } #endif // check that we can write in writable directory if (bc_tester_writable_dir_prefix != NULL) { char * writable_file_path = bc_sprintf("%s/%s", bc_tester_writable_dir_prefix, ".bc_tester_utils.tmp"); writable_file = fopen(writable_file_path, "w"); if (writable_file) { fclose(writable_file); } free(writable_file_path); } if (bc_tester_resource_dir_prefix == NULL || writable_file == NULL) { if (bc_tester_resource_dir_prefix == NULL) { bc_tester_printf(bc_printf_verbosity_error, "Could not find resource directory '%s' in '%s'! Please try again using option --resource-dir.", expected_res, progpath); } if (writable_file == NULL) { bc_tester_printf(bc_printf_verbosity_error, "Failed to write file in %s. Please try again using option --writable-dir.", bc_tester_writable_dir_prefix); } abort(); } if (progpath != NULL) { free(progpath); } if(progname) { free(progname); } } void bc_tester_init(void (*ftester_printf)(int level, const char *format, va_list args), int iverbosity_info, int iverbosity_error, const char* aexpected_res) { tester_printf_va = ftester_printf; bc_printf_verbosity_error = iverbosity_error; bc_printf_verbosity_info = iverbosity_info; if (!bc_tester_writable_dir_prefix) { bc_tester_writable_dir_prefix = strdup("."); } if (aexpected_res) { expected_res = strdup(aexpected_res); } } void bc_tester_set_max_vm(size_t amax_vm_kb) { #ifdef __linux max_vm_kb = (size_t)amax_vm_kb; bc_tester_printf(bc_printf_verbosity_info, "Maximum virtual memory space set to %li kilo bytes", max_vm_kb); #else bc_tester_printf(bc_printf_verbosity_error, "Maximum virtual memory space setting is only implemented on Linux."); #endif } void bc_tester_helper(const char *name, const char* additionnal_helper) { bc_tester_printf(bc_printf_verbosity_info, "%s --help\n" #ifdef HAVE_CU_CURSES "\t\t\t--curses\n" #endif "\t\t\t--list-suites\n" "\t\t\t--list-tests \n" "\t\t\t--suite \n" "\t\t\t--test \n" "\t\t\t--tag (execute all tests with the given tag)\n" "\t\t\t--all (execute all tests, even the ones with the Skip flag)\n" "\t\t\t--resource-dir (directory where tester resource are located)\n" "\t\t\t--writable-dir (directory where temporary files should be created)\n" "\t\t\t--xml\n" "\t\t\t--xml-file \n" "\t\t\t--max-alloc (maximum amount of memory obtained via malloc allocator)\n" "And additionally:\n" "%s", name, additionnal_helper); } int bc_tester_parse_args(int argc, char **argv, int argid) { int i = argid; if (strcmp(argv[i],"--help")==0){ return -1; } else if (strcmp(argv[i],"--test")==0){ CHECK_ARG("--test", ++i, argc); test_name=argv[i]; } else if (strcmp(argv[i],"--suite")==0){ CHECK_ARG("--suite", ++i, argc); suite_name=argv[i]; } else if (strcmp(argv[i], "--tag") == 0) { CHECK_ARG("--tag", ++i, argc); tag_name = argv[i]; } else if (strcmp(argv[i], "--all") == 0) { run_skipped_tests = 1; } else if (strcmp(argv[i],"--list-suites")==0){ bc_tester_list_suites(); return 0; } else if (strcmp(argv[i],"--list-tests")==0){ CHECK_ARG("--list-tests", ++i, argc); suite_name = argv[i]; bc_tester_list_tests(suite_name); return 0; } else if (strcmp(argv[i], "--xml-file") == 0){ CHECK_ARG("--xml-file", ++i, argc); xml_file = argv[i]; xml_enabled = 1; } else if (strcmp(argv[i], "--xml") == 0){ xml_enabled = 1; } else if (strcmp(argv[i], "--max-alloc") == 0) { CHECK_ARG("--max-alloc", ++i, argc); max_vm_kb = atol(argv[i]); } else if (strcmp(argv[i], "--resource-dir") == 0) { CHECK_ARG("--resource-dir", ++i, argc); bc_tester_resource_dir_prefix = strdup(argv[i]); } else if (strcmp(argv[i], "--writable-dir") == 0) { CHECK_ARG("--writable-dir", ++i, argc); bc_tester_writable_dir_prefix = strdup(argv[i]); } else { bc_tester_printf(bc_printf_verbosity_error, "Unknown option \"%s\"", argv[i]); return -1; } if( xml_enabled && (suite_name || test_name) ){ bc_tester_printf(bc_printf_verbosity_error, "Cannot use both XML and specific test suite"); return -1; } /* returns number of arguments read + 1 */ return i - argid + 1; } int bc_tester_start(const char* prog_name) { int ret; if (expected_res) detect_res_prefix(prog_name); if (max_vm_kb) bc_tester_set_max_vm(max_vm_kb); if( xml_enabled ){ char * xml_tmp_file = bc_sprintf("%s.tmp", xml_file); CU_set_output_filename(xml_tmp_file); CU_automated_enable_junit_xml(TRUE); /* this requires 3.0.1 because previous versions crash automated.c */ free(xml_tmp_file); } ret = bc_tester_run_tests(suite_name, test_name, tag_name); return ret; } void bc_tester_add_suite(test_suite_t *suite) { if (test_suite == NULL) { test_suite = (test_suite_t **)malloc(10 * sizeof(test_suite_t *)); } test_suite[nb_test_suites] = suite; nb_test_suites++; if ((nb_test_suites % 10) == 0) { test_suite = (test_suite_t **)realloc(test_suite, (nb_test_suites + 10) * sizeof(test_suite_t *)); } } void bc_tester_uninit(void) { /* Redisplay list of failed tests on end */ /*BUG: do not display list of failures on mingw, it crashes mysteriously*/ #if !defined(_WIN32) && !defined(_MSC_VER) /* Redisplay list of failed tests on end */ if (CU_get_number_of_failure_records()){ CU_basic_show_failures(CU_get_failure_list()); } #endif CU_cleanup_registry(); /*add missing final newline*/ bc_tester_printf(bc_printf_verbosity_info,""); if (xml_enabled) { /*create real xml file only if tester did not crash*/ char * xml_tmp_file = bc_sprintf("%s.tmp-Results.xml", xml_file); bc_tester_printf(bc_printf_verbosity_info, "Tests ended, renaming temporary result file %s to %s", xml_tmp_file, xml_file); if (rename(xml_tmp_file, xml_file) != 0) { bc_tester_printf(bc_printf_verbosity_error, "Failed to rename XML file: %s", strerror(errno)); } free(xml_tmp_file); } if (test_suite != NULL) { free(test_suite); test_suite = NULL; nb_test_suites = 0; } if (bc_tester_resource_dir_prefix != NULL) { free(bc_tester_resource_dir_prefix); bc_tester_resource_dir_prefix = NULL; } if (bc_tester_writable_dir_prefix != NULL) { free(bc_tester_writable_dir_prefix); bc_tester_writable_dir_prefix = NULL; } } static void bc_tester_set_dir_prefix(char **prefix, const char *name) { if (*prefix != NULL) free(*prefix); *prefix = strdup(name); } const char * bc_tester_get_resource_dir_prefix(void) { return bc_tester_resource_dir_prefix; } void bc_tester_set_resource_dir_prefix(const char *name) { bc_tester_set_dir_prefix(&bc_tester_resource_dir_prefix, name); } const char * bc_tester_get_writable_dir_prefix(void) { return bc_tester_writable_dir_prefix; } void bc_tester_set_writable_dir_prefix(const char *name) { bc_tester_set_dir_prefix(&bc_tester_writable_dir_prefix, name); } static char * bc_tester_path(const char *prefix, const char *name) { if (name) { return bc_sprintf("%s/%s", prefix, name); } else { return NULL; } } char * bc_tester_res(const char *name) { return bc_tester_path(bc_tester_resource_dir_prefix, name); } char * bc_tester_file(const char *name) { return bc_tester_path(bc_tester_writable_dir_prefix, name); } char* bc_sprintfva(const char* format, va_list args) { /* Guess we need no more than 100 bytes. */ int n, size = 200; char *p,*np; #ifndef _WIN32 va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/ #endif if ((p = malloc(size)) == NULL) return NULL; while (1) { /* Try to print in the allocated space. */ #ifndef _WIN32 va_copy(cap,args); n = vsnprintf (p, size, format, cap); va_end(cap); #else /*this works on 32 bits, luckily*/ n = vsnprintf (p, size, format, args); #endif /* If that worked, return the string. */ if (n > -1 && n < size) return p; //bc_tester_printf(bc_printf_verbosity_error, "Reallocing space."); /* Else try again with more space. */ if (n > -1) /* glibc 2.1 */ size = n + 1; /* precisely what is needed */ else /* glibc 2.0 */ size *= 2; /* twice the old size */ if ((np = realloc (p, size)) == NULL) { free(p); return NULL; } else { p = np; } } } char* bc_sprintf(const char* format, ...) { va_list args; char* res; va_start(args, format); res = bc_sprintfva(format, args); va_end (args); return res; } void bc_free(void *ptr) { free(ptr); } const char * bc_tester_current_suite_name(void) { return bc_current_suite_name; } const char * bc_tester_current_test_name(void) { return bc_current_test_name; } const char ** bc_tester_current_test_tags(void) { if (bc_current_suite_name && bc_current_test_name) { int suite_index = bc_tester_suite_index(bc_current_suite_name); int test_index = bc_tester_test_index(test_suite[suite_index], bc_current_test_name); return test_suite[suite_index]->tests[test_index].tags; } return NULL; } unsigned int bc_get_number_of_failures(void) { return CU_get_number_of_failures(); } void bc_set_trace_handler(void(*handler)(int, const char*, va_list)) { #ifdef HAVE_CU_SET_TRACE_HANDLER CU_set_trace_handler(handler); #else bc_tester_printf(bc_printf_verbosity_error, "CU_set_trace_handler not implemented"); #endif } int bc_assert(const char* file, int line, int predicate, const char* format) { if (!predicate) bc_tester_printf(bc_printf_verbosity_info, format, NULL); return CU_assertImplementation(predicate, line, format, file, "", FALSE); } bctoolbox-0.6.0/src/utils.h000066400000000000000000000014111313410701300155760ustar00rootroot00000000000000/* utils.h Copyright (C) 2016 Belledonne Communications SARL This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "bctoolbox/port.h"bctoolbox-0.6.0/src/utils/000077500000000000000000000000001313410701300154305ustar00rootroot00000000000000bctoolbox-0.6.0/src/utils/exception.cc000066400000000000000000000072571313410701300177500ustar00rootroot00000000000000/* Flexisip, a flexible SIP proxy server with media capabilities. Copyright (C) 2010-2015 Belledonne Communications SARL, All rights reserved. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #include "bctoolbox/exception.hh" #include #include #include "bctoolbox/logging.h" #include "dlfcn.h" #include #include #include #include using namespace std; static void uncaught_handler() { std::exception_ptr p = current_exception(); try { rethrow_exception(p); } catch (BctbxException &e) { BCTBX_SLOGE(NULL) << e; } catch (std::exception &ee) { BCTBX_SLOGE(NULL) << "Unexpected exception [" << ee.what() << " ] use BctbxException for better debug"; } abort(); } BctbxException::BctbxException(const char *message) : mOffset(1), mSize(0) { mSize = backtrace(mArray, sizeof(mArray) / sizeof(void *)); if (message) mOs << message; #if __clang if (get_terminate() != uncaught_handler) #endif set_terminate(uncaught_handler); // invoke in case of uncautch exception for this thread } BctbxException::BctbxException(const BctbxException &other) : mOffset(other.mOffset), mSize(other.mSize) { memcpy(mArray, other.mArray, sizeof(mArray)); mOs << other.str(); } #if __cplusplus > 199711L BctbxException::BctbxException(const string &msg) : BctbxException(msg.c_str()) { mOffset++; } #else BctbxException::BctbxException(const string &message) : mOffset(2) { mSize = backtrace(mArray, sizeof(mArray) / sizeof(void *)); *this << message; set_terminate(uncaught_handler); // invoke in case of uncautch exception for this thread } #endif BctbxException::~BctbxException() throw() { // nop } #if __cplusplus > 199711L BctbxException::BctbxException() : BctbxException("") { mOffset++; } #else BctbxException::BctbxException() : mOffset(2) { mSize = backtrace(mArray, sizeof(mArray) / sizeof(void *)); *this << ""; set_terminate(uncaught_handler); // invoke in case of uncautch exception for this thread } #endif void BctbxException::printStackTrace() const { backtrace_symbols_fd(mArray + mOffset, mSize - mOffset, STDERR_FILENO); } void BctbxException::printStackTrace(std::ostream &os) const { char **bt = backtrace_symbols(mArray, mSize); int position=0; for (unsigned int i = mOffset; i < mSize; ++i) { Dl_info info; char *demangled = NULL; int status = -1; if (dladdr(mArray[i], &info) && info.dli_sname) { demangled = abi::__cxa_demangle(info.dli_sname, NULL, 0, &status); os << position++ << setw(20) << basename((char*)info.dli_fname) << setw(16) << info.dli_saddr ; os << " "; if (demangled) { os << demangled; free(demangled); } else{ os << info.dli_sname; } } else { os << bt[i]; } os << std::endl; } free(bt); } const std::string &BctbxException::str() const { mMessage = mOs.str(); // avoid returning a reference to temporary return mMessage; } const char *BctbxException::what() const throw() { return str().c_str(); } // Class BctbxException std::ostream &operator<<(std::ostream &__os, const BctbxException &e) { __os << e.str() << std::endl; e.printStackTrace(__os); return __os; } bctoolbox-0.6.0/src/utils/port.c000066400000000000000000001306721313410701300165710ustar00rootroot00000000000000 /* bctoolbox Copyright (C) 2016 Belledonne Communications SARL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "bctoolbox/logging.h" #include "bctoolbox/port.h" #include "bctoolbox/vconnect.h" #include "bctoolbox/list.h" #include "utils.h" #if defined(_WIN32) && !defined(_WIN32_WCE) #include #endif #ifdef _MSC_VER #ifndef access #define access _access #endif #endif #ifdef HAVE_SYS_SHM_H #include #endif #ifndef MIN #define MIN(a,b) a<=b ? a : b #endif static void *bctbx_libc_malloc(size_t sz){ return malloc(sz); } static void *bctbx_libc_realloc(void *ptr, size_t sz){ return realloc(ptr,sz); } static void bctbx_libc_free(void*ptr){ free(ptr); } static bool_t allocator_used=FALSE; static BctoolboxMemoryFunctions bctbx_allocator={ bctbx_libc_malloc, bctbx_libc_realloc, bctbx_libc_free }; void bctbx_set_memory_functions(BctoolboxMemoryFunctions *functions){ if (allocator_used){ bctbx_fatal("bctbx_set_memory_functions() must be called before " "first use of bctbx_malloc or bctbx_realloc"); return; } bctbx_allocator=*functions; } void* bctbx_malloc(size_t sz){ allocator_used=TRUE; return bctbx_allocator.malloc_fun(sz); } void* bctbx_realloc(void *ptr, size_t sz){ allocator_used=TRUE; return bctbx_allocator.realloc_fun(ptr,sz); } void bctbx_free(void* ptr){ bctbx_allocator.free_fun(ptr); } void * bctbx_malloc0(size_t size){ void *ptr=bctbx_malloc(size); memset(ptr,0,size); return ptr; } char * bctbx_strdup(const char *tmp){ size_t sz; char *ret; if (tmp==NULL) return NULL; sz=strlen(tmp)+1; ret=(char*)bctbx_malloc(sz); strcpy(ret,tmp); ret[sz-1]='\0'; return ret; } char * bctbx_dirname(const char *path) { char *ptr; char *dname = bctbx_strdup(path); bool_t found = FALSE; ptr = strrchr(path, '/'); if (ptr != NULL) { dname[ptr - path] = '\0'; found = TRUE; } else { ptr = strrchr(path, '\\'); if (ptr != NULL) { dname[ptr - path] = '\0'; found = TRUE; } } if (found == FALSE) { bctbx_free(dname); return NULL; } return dname; } char * bctbx_basename(const char *path) { char *ptr = strrchr(path, '/'); if (ptr == NULL) ptr = strrchr(path, '\\'); if (ptr == NULL) return NULL; return bctbx_strdup(ptr + 1); } /* * this method is an utility method that calls fnctl() on UNIX or * ioctlsocket on Win32. * int retrun the result of the system method */ int bctbx_socket_set_non_blocking(bctbx_socket_t sock){ #if !defined(_WIN32) && !defined(_WIN32_WCE) return fcntl (sock, F_SETFL, O_NONBLOCK); #else unsigned long nonBlock = 1; return ioctlsocket(sock, FIONBIO , &nonBlock); #endif } int bctbx_file_exist(const char *pathname) { return access(pathname,F_OK); } #if !defined(_WIN32) && !defined(_WIN32_WCE) /* Use UNIX inet_aton method */ #else int __bctbx_WIN_inet_aton (const char * cp, struct in_addr * addr) { unsigned long retval; retval = inet_addr (cp); if (retval == INADDR_NONE) { return -1; } else { addr->S_un.S_addr = retval; return 1; } } #endif char *bctbx_strndup(const char *str,int n){ int min=MIN((int)strlen(str),n)+1; char *ret=(char*)bctbx_malloc(min); strncpy(ret,str,min); ret[min-1]='\0'; return ret; } #if !defined(_WIN32) && !defined(_WIN32_WCE) int __bctbx_thread_join(bctbx_thread_t thread, void **ptr){ int err=pthread_join(thread,ptr); if (err!=0) { bctbx_error("pthread_join error: %s",strerror(err)); } return err; } int __bctbx_thread_create(bctbx_thread_t *thread, pthread_attr_t *attr, void * (*routine)(void*), void *arg){ pthread_attr_t my_attr; pthread_attr_init(&my_attr); if (attr) my_attr = *attr; #ifdef BCTBX_DEFAULT_THREAD_STACK_SIZE if (BCTBX_DEFAULT_THREAD_STACK_SIZE!=0) pthread_attr_setstacksize(&my_attr, BCTBX_DEFAULT_THREAD_STACK_SIZE); #endif return pthread_create(thread, &my_attr, routine, arg); } unsigned long __bctbx_thread_self(void) { return (unsigned long)pthread_self(); } #endif #if defined(_WIN32) || defined(_WIN32_WCE) int __bctbx_WIN_mutex_init(bctbx_mutex_t *mutex, void *attr) { #ifdef BCTBX_WINDOWS_DESKTOP *mutex=CreateMutex(NULL, FALSE, NULL); #else InitializeSRWLock(mutex); #endif return 0; } int __bctbx_WIN_mutex_lock(bctbx_mutex_t * hMutex) { #ifdef BCTBX_WINDOWS_DESKTOP WaitForSingleObject(*hMutex, INFINITE); /* == WAIT_TIMEOUT; */ #else AcquireSRWLockExclusive(hMutex); #endif return 0; } int __bctbx_WIN_mutex_unlock(bctbx_mutex_t * hMutex) { #ifdef BCTBX_WINDOWS_DESKTOP ReleaseMutex(*hMutex); #else ReleaseSRWLockExclusive(hMutex); #endif return 0; } int __bctbx_WIN_mutex_destroy(bctbx_mutex_t * hMutex) { #ifdef BCTBX_WINDOWS_DESKTOP CloseHandle(*hMutex); #endif return 0; } typedef struct thread_param{ void * (*func)(void *); void * arg; }thread_param_t; static unsigned WINAPI thread_starter(void *data){ thread_param_t *params=(thread_param_t*)data; params->func(params->arg); bctbx_free(data); return 0; } #if defined _WIN32_WCE # define _beginthreadex CreateThread # define _endthreadex ExitThread #endif int __bctbx_WIN_thread_create(bctbx_thread_t *th, void *attr, void * (*func)(void *), void *data) { thread_param_t *params=bctbx_new(thread_param_t,1); params->func=func; params->arg=data; *th=(HANDLE)_beginthreadex( NULL, 0, thread_starter, params, 0, NULL); return 0; } int __bctbx_WIN_thread_join(bctbx_thread_t thread_h, void **unused) { if (thread_h!=NULL) { WaitForSingleObjectEx(thread_h, INFINITE, FALSE); CloseHandle(thread_h); } return 0; } unsigned long __bctbx_WIN_thread_self(void) { return (unsigned long)GetCurrentThreadId(); } int __bctbx_WIN_cond_init(bctbx_cond_t *cond, void *attr) { #ifdef BCTBX_WINDOWS_DESKTOP *cond=CreateEvent(NULL, FALSE, FALSE, NULL); #else InitializeConditionVariable(cond); #endif return 0; } int __bctbx_WIN_cond_wait(bctbx_cond_t* hCond, bctbx_mutex_t * hMutex) { #ifdef BCTBX_WINDOWS_DESKTOP //gulp: this is not very atomic ! bug here ? __bctbx_WIN_mutex_unlock(hMutex); WaitForSingleObject(*hCond, INFINITE); __bctbx_WIN_mutex_lock(hMutex); #else SleepConditionVariableSRW(hCond, hMutex, INFINITE, 0); #endif return 0; } int __bctbx_WIN_cond_signal(bctbx_cond_t * hCond) { #ifdef BCTBX_WINDOWS_DESKTOP SetEvent(*hCond); #else WakeConditionVariable(hCond); #endif return 0; } int __bctbx_WIN_cond_broadcast(bctbx_cond_t * hCond) { __bctbx_WIN_cond_signal(hCond); return 0; } int __bctbx_WIN_cond_destroy(bctbx_cond_t * hCond) { #ifdef BCTBX_WINDOWS_DESKTOP CloseHandle(*hCond); #endif return 0; } #if defined(_WIN32_WCE) #include const char * bctbx_strerror(DWORD value) { static TCHAR msgBuf[256]; FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, value, 0, // Default language (LPTSTR) &msgBuf, 0, NULL ); return (const char *)msgBuf; } int gettimeofday (struct timeval *tv, void *tz) { DWORD timemillis = GetTickCount(); tv->tv_sec = timemillis/1000; tv->tv_usec = (timemillis - (tv->tv_sec*1000)) * 1000; return 0; } #else int bctbx_gettimeofday (struct timeval *tv, void* tz) { union { __int64 ns100; /*time since 1 Jan 1601 in 100ns units */ FILETIME fileTime; } now; GetSystemTimeAsFileTime (&now.fileTime); tv->tv_usec = (long) ((now.ns100 / 10LL) % 1000000LL); tv->tv_sec = (long) ((now.ns100 - 116444736000000000LL) / 10000000LL); return (0); } #endif const char *__bctbx_getWinSocketError(int error) { static char buf[256]; FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, sizeof(buf), NULL); return buf; } #ifdef _WORKAROUND_MINGW32_BUGS char * WSAAPI gai_strerror(int errnum){ return (char*)__bctbx_getWinSocketError(errnum); } #endif #endif #ifndef _WIN32 #include #include #include #include static char *make_pipe_name(const char *name){ return bctbx_strdup_printf("/tmp/%s",name); } /* portable named pipes */ bctbx_socket_t bctbx_server_pipe_create(const char *name){ struct sockaddr_un sa; char *pipename=make_pipe_name(name); bctbx_socket_t sock; sock=socket(AF_UNIX,SOCK_STREAM,0); sa.sun_family=AF_UNIX; strncpy(sa.sun_path,pipename,sizeof(sa.sun_path)-1); unlink(pipename);/*in case we didn't finished properly previous time */ bctbx_free(pipename); fchmod(sock,S_IRUSR|S_IWUSR); if (bind(sock,(struct sockaddr*)&sa,sizeof(sa))!=0){ bctbx_error("Failed to bind command unix socket: %s",strerror(errno)); return -1; } listen(sock,1); return sock; } bctbx_socket_t bctbx_server_pipe_accept_client(bctbx_socket_t server){ struct sockaddr_un su; socklen_t ssize=sizeof(su); bctbx_socket_t client_sock=accept(server,(struct sockaddr*)&su,&ssize); return client_sock; } int bctbx_server_pipe_close_client(bctbx_socket_t client){ return close(client); } int bctbx_server_pipe_close(bctbx_socket_t spipe){ struct sockaddr_un sa; socklen_t len=sizeof(sa); int err; /*this is to retrieve the name of the pipe, in order to unlink the file*/ err=getsockname(spipe,(struct sockaddr*)&sa,&len); if (err==0){ unlink(sa.sun_path); }else bctbx_error("getsockname(): %s",strerror(errno)); return close(spipe); } bctbx_socket_t bctbx_client_pipe_connect(const char *name){ bctbx_socket_t sock = -1; struct sockaddr_un sa; struct stat fstats; char *pipename=make_pipe_name(name); uid_t uid = getuid(); // check that the creator of the pipe is us if( (stat(name, &fstats) == 0) && (fstats.st_uid != uid) ){ bctbx_error("UID of file %s (%lu) differs from ours (%lu)", pipename, (unsigned long)fstats.st_uid, (unsigned long)uid); return -1; } sock = socket(AF_UNIX,SOCK_STREAM,0); sa.sun_family=AF_UNIX; strncpy(sa.sun_path,pipename,sizeof(sa.sun_path)-1); bctbx_free(pipename); if (connect(sock,(struct sockaddr*)&sa,sizeof(sa))!=0){ close(sock); return -1; } return sock; } int bctbx_pipe_read(bctbx_socket_t p, uint8_t *buf, int len){ return read(p,buf,len); } int bctbx_pipe_write(bctbx_socket_t p, const uint8_t *buf, int len){ return write(p,buf,len); } int bctbx_client_pipe_close(bctbx_socket_t sock){ return close(sock); } #ifdef HAVE_SYS_SHM_H void *bctbx_shm_open(unsigned int keyid, int size, int create){ key_t key=keyid; void *mem; int perms=S_IRUSR|S_IWUSR; int fd=shmget(key,size,create ? (IPC_CREAT | perms ) : perms); if (fd==-1){ printf("shmget failed: %s\n",strerror(errno)); return NULL; } mem=shmat(fd,NULL,0); if (mem==(void*)-1){ printf("shmat() failed: %s", strerror(errno)); return NULL; } return mem; } void bctbx_shm_close(void *mem){ shmdt(mem); } #endif #elif defined(_WIN32) && !defined(_WIN32_WCE) static char *make_pipe_name(const char *name){ return bctbx_strdup_printf("\\\\.\\pipe\\%s",name); } static HANDLE event=NULL; /* portable named pipes */ bctbx_pipe_t bctbx_server_pipe_create(const char *name){ #ifdef BCTBX_WINDOWS_DESKTOP bctbx_pipe_t h; char *pipename=make_pipe_name(name); h=CreateNamedPipe(pipename,PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,PIPE_TYPE_MESSAGE|PIPE_WAIT,1, 32768,32768,0,NULL); bctbx_free(pipename); if (h==INVALID_HANDLE_VALUE){ bctbx_error("Fail to create named pipe %s",pipename); } if (event==NULL) event=CreateEvent(NULL,TRUE,FALSE,NULL); return h; #else bctbx_error("%s not supported!", __FUNCTION__); return INVALID_HANDLE_VALUE; #endif } /*this function is a bit complex because we need to wakeup someday even if nobody connects to the pipe. bctbx_server_pipe_close() makes this function to exit. */ bctbx_pipe_t bctbx_server_pipe_accept_client(bctbx_pipe_t server){ #ifdef BCTBX_WINDOWS_DESKTOP OVERLAPPED ol; DWORD undef; HANDLE handles[2]; memset(&ol,0,sizeof(ol)); ol.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL); ConnectNamedPipe(server,&ol); handles[0]=ol.hEvent; handles[1]=event; WaitForMultipleObjects(2,handles,FALSE,INFINITE); if (GetOverlappedResult(server,&ol,&undef,FALSE)){ CloseHandle(ol.hEvent); return server; } CloseHandle(ol.hEvent); return INVALID_HANDLE_VALUE; #else bctbx_error("%s not supported!", __FUNCTION__); return INVALID_HANDLE_VALUE; #endif } int bctbx_server_pipe_close_client(bctbx_pipe_t server){ #ifdef BCTBX_WINDOWS_DESKTOP return DisconnectNamedPipe(server)==TRUE ? 0 : -1; #else bctbx_error("%s not supported!", __FUNCTION__); return -1; #endif } int bctbx_server_pipe_close(bctbx_pipe_t spipe){ #ifdef BCTBX_WINDOWS_DESKTOP SetEvent(event); //CancelIoEx(spipe,NULL); /*vista only*/ return CloseHandle(spipe); #else bctbx_error("%s not supported!", __FUNCTION__); return -1; #endif } bctbx_pipe_t bctbx_client_pipe_connect(const char *name){ #ifdef BCTBX_WINDOWS_DESKTOP char *pipename=make_pipe_name(name); bctbx_pipe_t hpipe = CreateFile( pipename, // pipe name GENERIC_READ | // read and write access GENERIC_WRITE, 0, // no sharing NULL, // default security attributes OPEN_EXISTING, // opens existing pipe 0, // default attributes NULL); // no template file bctbx_free(pipename); return hpipe; #else bctbx_error("%s not supported!", __FUNCTION__); return INVALID_HANDLE_VALUE; #endif } int bctbx_pipe_read(bctbx_pipe_t p, uint8_t *buf, int len){ DWORD ret=0; if (ReadFile(p,buf,len,&ret,NULL)) return ret; /*bctbx_error("Could not read from pipe: %s",strerror(GetLastError()));*/ return -1; } int bctbx_pipe_write(bctbx_pipe_t p, const uint8_t *buf, int len){ DWORD ret=0; if (WriteFile(p,buf,len,&ret,NULL)) return ret; /*bctbx_error("Could not write to pipe: %s",strerror(GetLastError()));*/ return -1; } int bctbx_client_pipe_close(bctbx_pipe_t sock){ return CloseHandle(sock); } typedef struct MapInfo{ HANDLE h; void *mem; }MapInfo; static bctbx_list_t *maplist=NULL; void *bctbx_shm_open(unsigned int keyid, int size, int create){ #ifdef BCTBX_WINDOWS_DESKTOP HANDLE h; char name[64]; void *buf; snprintf(name,sizeof(name),"%x",keyid); if (create){ h = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) size, // maximum object size (low-order DWORD) name); // name of mapping object }else{ h = OpenFileMapping( FILE_MAP_ALL_ACCESS, // read/write access FALSE, // do not inherit the name name); // name of mapping object } if (h==(HANDLE)-1) { bctbx_error("Fail to open file mapping (create=%i)",create); return NULL; } buf = (LPTSTR) MapViewOfFile(h, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, size); if (buf!=NULL){ MapInfo *i=(MapInfo*)bctbx_new(MapInfo,1); i->h=h; i->mem=buf; maplist=bctbx_list_append(maplist,i); }else{ CloseHandle(h); bctbx_error("MapViewOfFile failed"); } return buf; #else bctbx_error("%s not supported!", __FUNCTION__); return NULL; #endif } void bctbx_shm_close(void *mem){ #ifdef BCTBX_WINDOWS_DESKTOP bctbx_list_t *elem; for(elem=maplist;elem;elem=bctbx_list_next(elem)){ MapInfo *i=(MapInfo*)bctbx_list_get_data(elem); if (i->mem==mem){ CloseHandle(i->h); UnmapViewOfFile(mem); bctbx_free(i); maplist=bctbx_list_erase_link(maplist,elem); return; } } bctbx_error("No shared memory at %p was found.",mem); #else bctbx_error("%s not supported!", __FUNCTION__); #endif } #endif #ifdef __MACH__ #include #include #endif void _bctbx_get_cur_time(bctoolboxTimeSpec *ret, bool_t realtime){ #if defined(_WIN32_WCE) || defined(WIN32) #ifdef BCTBX_WINDOWS_DESKTOP DWORD timemillis; # if defined(_WIN32_WCE) timemillis=GetTickCount(); # else timemillis=timeGetTime(); # endif ret->tv_sec=timemillis/1000; ret->tv_nsec=(timemillis%1000)*1000000LL; #else ULONGLONG timemillis = GetTickCount64(); ret->tv_sec = timemillis / 1000; ret->tv_nsec = (timemillis % 1000) * 1000000LL; #endif #elif defined(__MACH__) && defined(__GNUC__) && (__GNUC__ >= 3) struct timeval tv; gettimeofday(&tv, NULL); ret->tv_sec=tv.tv_sec; ret->tv_nsec=tv.tv_usec*1000LL; #elif defined(__MACH__) struct timeb time_val; ftime (&time_val); ret->tv_sec = time_val.time; ret->tv_nsec = time_val.millitm * 1000000LL; #else struct timespec ts; if (clock_gettime(realtime ? CLOCK_REALTIME : CLOCK_MONOTONIC,&ts)<0){ bctbx_fatal("clock_gettime() doesn't work: %s",strerror(errno)); } ret->tv_sec=ts.tv_sec; ret->tv_nsec=ts.tv_nsec; #endif } void bctbx_get_utc_cur_time(bctoolboxTimeSpec *ret){ _bctbx_get_cur_time(ret, TRUE); } void bctbx_get_cur_time(bctoolboxTimeSpec *ret){ _bctbx_get_cur_time(ret, FALSE); } uint64_t bctbx_get_cur_time_ms(void) { bctoolboxTimeSpec ts; _bctbx_get_cur_time(&ts, TRUE); return (ts.tv_sec * 1000LL) + ((ts.tv_nsec + 500000LL) / 1000000LL); } void bctbx_sleep_ms(int ms){ #ifdef _WIN32 #ifdef BCTBX_WINDOWS_DESKTOP Sleep(ms); #else HANDLE sleepEvent = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); if (!sleepEvent) return; WaitForSingleObjectEx(sleepEvent, ms, FALSE); CloseHandle(sleepEvent); #endif #else struct timespec ts; ts.tv_sec=ms/1000; ts.tv_nsec=(ms%1000)*1000000LL; nanosleep(&ts,NULL); #endif } void bctbx_sleep_until(const bctoolboxTimeSpec *ts){ #ifdef __linux struct timespec rq; rq.tv_sec=ts->tv_sec; rq.tv_nsec=ts->tv_nsec; while (clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &rq, NULL)==-1 && errno==EINTR){ } #else bctoolboxTimeSpec current; bctoolboxTimeSpec diff; _bctbx_get_cur_time(¤t, TRUE); diff.tv_sec=ts->tv_sec-current.tv_sec; diff.tv_nsec=ts->tv_nsec-current.tv_nsec; if (diff.tv_nsec<0){ diff.tv_nsec+=1000000000LL; diff.tv_sec-=1; } #ifdef _WIN32 bctbx_sleep_ms((int)((diff.tv_sec * 1000LL) + (diff.tv_nsec/1000000LL))); #else { struct timespec dur,rem; dur.tv_sec=diff.tv_sec; dur.tv_nsec=diff.tv_nsec; while (nanosleep(&dur,&rem)==-1 && errno==EINTR){ dur=rem; }; } #endif #endif } /** * @brief Add given amount of seconds to a timeSpec structure * * @param[in/out] ts The timeSpec structure used as input, modified in output by increnting it according to second argument * @param[in] lap In seconds, number of seconds to modify the given timeSpec, can be negative(which may set the original timeSpec to 0) */ void bctbx_timespec_add(bctoolboxTimeSpec *ts, const int64_t lap) { if (lap<0 && -lap > ts->tv_sec) { ts->tv_sec = 0; ts->tv_nsec = 0; } else { ts->tv_sec += lap; } } /** * @brief Compares two TimeSpec s1 and s2. * * @param[in] s1 First time spec * @param[in] s2 Second time spec * * @return a negative value if s1 is earlier than s2, 0 if they are equal, a positive value if s1 is later than s2 */ int bctbx_timespec_compare(const bctoolboxTimeSpec *s1, const bctoolboxTimeSpec *s2){ int64_t secdiff = s1->tv_sec - s2->tv_sec; if (secdiff == 0){ int64_t nsec_diff = s1->tv_nsec - s2->tv_nsec; if (nsec_diff < 0){ return -1; }else if (nsec_diff > 0){ return 1; }else return 0; }else if (secdiff < 0){ return -1; }else return 1; } uint32_t bctbx_time_string_to_sec(const char *timeString) { char *p = NULL; char *o = NULL; int32_t n=0; uint32_t ret=0; if (timeString == NULL) { return 0; } o = p = bctbx_strdup(timeString); while (*p!='\0') { n=strtol(p, &p, 10); switch (*p) { case '\0': ret+=n; break; case 'Y': ret +=n*365*24*3600; p++; break; case 'M': ret +=n*30*24*3600; p++; break; case 'W': ret +=n*7*24*3600; p++; break; case 'd': ret +=n*24*3600; p++; break; case 'h': ret +=n*3600; p++; break; case 'm': ret +=n*60; p++; break; case 's': ret+=n; p++; break; default: /* just ignore any other suffix */ p++; break; } } bctbx_free(o); return ret; } #if defined(_WIN32) && !defined(_MSC_VER) char* strtok_r(char *str, const char *delim, char **nextp){ char *ret; if (str == NULL){ str = *nextp; } str += strspn(str, delim); if (*str == '\0'){ return NULL; } ret = str; str += strcspn(str, delim); if (*str){ *str++ = '\0'; } *nextp = str; return ret; } #endif #if defined(_WIN32) && !defined(_MSC_VER) #include static int bctbx_wincrypto_random(unsigned int *rand_number){ static HCRYPTPROV hProv=(HCRYPTPROV)-1; static int initd=0; if (!initd){ if (!CryptAcquireContext(&hProv,NULL,NULL,PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)){ bctbx_error("bctbx_wincrypto_random(): Could not acquire a windows crypto context"); return -1; } initd=TRUE; } if (hProv==(HCRYPTPROV)-1) return -1; if (!CryptGenRandom(hProv,4,(BYTE*)rand_number)){ bctbx_error("bctbx_wincrypto_random(): CryptGenRandom() failed."); return -1; } return 0; } #endif unsigned int bctbx_random(void){ #ifdef HAVE_ARC4RANDOM return arc4random(); #elif defined(__linux) || defined(__APPLE__) static int fd=-1; if (fd==-1) fd=open("/dev/urandom",O_RDONLY); if (fd!=-1){ unsigned int tmp; if (read(fd,&tmp,4)!=4){ bctbx_error("Reading /dev/urandom failed."); }else return tmp; }else bctbx_error("Could not open /dev/urandom"); #elif defined(_WIN32) static int initd=0; unsigned int ret; #ifdef _MSC_VER /*rand_s() is pretty nice and simple function but is not wrapped by mingw.*/ if (rand_s(&ret)==0){ return ret; } #else if (bctbx_wincrypto_random(&ret)==0){ return ret; } #endif /* Windows's rand() is unsecure but is used as a fallback*/ if (!initd) { struct timeval tv; bctbx_gettimeofday(&tv,NULL); srand((unsigned int)tv.tv_sec+tv.tv_usec); initd=1; bctbx_warning("bctoolbox: Random generator is using rand(), this is unsecure !"); } return rand()<<16 | rand(); #endif /*fallback to UNIX random()*/ #ifndef _WIN32 return (unsigned int) random(); #endif } bool_t bctbx_is_multicast_addr(const struct sockaddr *addr) { switch (addr->sa_family) { case AF_INET: return IN_MULTICAST(ntohl(((struct sockaddr_in *) addr)->sin_addr.s_addr)); case AF_INET6: return IN6_IS_ADDR_MULTICAST(&(((struct sockaddr_in6 *) addr)->sin6_addr)); default: return FALSE; } } #ifdef _WIN32 ssize_t bctbx_send(bctbx_socket_t socket, const void *buffer, size_t length, int flags) { return send(socket, (const char *)buffer, (int)length, flags); } ssize_t bctbx_sendto(bctbx_socket_t socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len) { return sendto(socket, (const char *)message, (int)length, flags, dest_addr, (int)dest_len); } ssize_t bctbx_recv(bctbx_socket_t socket, void *buffer, size_t length, int flags) { return recv(socket, (char *)buffer, (int)length, flags); } ssize_t bctbx_recvfrom(bctbx_socket_t socket, void *buffer, size_t length, int flags, struct sockaddr *address, socklen_t *address_len) { return recvfrom(socket, (char *)buffer, (int)length, flags, address, (int *)address_len); } ssize_t bctbx_read(int fd, void *buf, size_t nbytes) { return (ssize_t)_read(fd, buf, (unsigned int)nbytes); } ssize_t bctbx_write(int fd, const void *buf, size_t nbytes) { return (ssize_t)_write(fd, buf, (unsigned int)nbytes); } #else ssize_t bctbx_send(bctbx_socket_t socket, const void *buffer, size_t length, int flags) { return send(socket, buffer, length, flags); } ssize_t bctbx_sendto(bctbx_socket_t socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len) { return sendto(socket, message, length, flags, dest_addr, dest_len); } ssize_t bctbx_recv(bctbx_socket_t socket, void *buffer, size_t length, int flags) { return recv(socket, buffer, length, flags); } ssize_t bctbx_recvfrom(bctbx_socket_t socket, void *buffer, size_t length, int flags, struct sockaddr *address, socklen_t *address_len) { return recvfrom(socket, buffer, length, flags, address, address_len); } ssize_t bctbx_read(int fd, void *buf, size_t nbytes) { return read(fd, buf, nbytes); } ssize_t bctbx_write(int fd, const void *buf, size_t nbytes) { return write(fd, buf, nbytes); } #endif static char allocated_by_bctbx_magic[10] = "bctbx"; static struct addrinfo *_bctbx_alloc_addrinfo(int ai_family, int socktype, int proto){ struct addrinfo *ai=(struct addrinfo*)bctbx_malloc0(sizeof(struct addrinfo) + sizeof(struct sockaddr_storage)); ai->ai_family=ai_family; ai->ai_socktype=socktype; ai->ai_protocol=proto; ai->ai_addrlen=AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); ai->ai_addr=(struct sockaddr*)(((unsigned char*)ai) + sizeof(struct addrinfo)); ai->ai_canonname = allocated_by_bctbx_magic; /*this is the way we will recognize our own allocated addrinfo structures in bctbx_freeaddrinfo()*/ return ai; } static struct addrinfo *convert_to_v4mapped(const struct addrinfo *ai){ struct addrinfo *res=NULL; const struct addrinfo *it; struct addrinfo *v4m=NULL; struct addrinfo *last=NULL; for (it=ai;it!=NULL;it=it->ai_next){ struct sockaddr_in6 *sin6; struct sockaddr_in *sin; v4m=_bctbx_alloc_addrinfo(AF_INET6, it->ai_socktype, it->ai_protocol); v4m->ai_flags|=AI_V4MAPPED; sin6=(struct sockaddr_in6*)v4m->ai_addr; sin=(struct sockaddr_in*)it->ai_addr; sin6->sin6_family=AF_INET6; ((uint8_t*)&sin6->sin6_addr)[10]=0xff; ((uint8_t*)&sin6->sin6_addr)[11]=0xff; memcpy(((uint8_t*)&sin6->sin6_addr)+12,&sin->sin_addr,4); sin6->sin6_port=sin->sin_port; if (last){ last->ai_next=v4m; }else{ res=v4m; } last=v4m; } return res; } #if defined(__ANDROID__) || defined(_WIN32) /* * SHAME !!! bionic's getaddrinfo does not implement the AI_V4MAPPED flag ! * It is declared in header file but rejected by the implementation. * The code below is to emulate a _compliant_ getaddrinfo for android. **/ /** * SHAME AGAIN !!! Win32's implementation of getaddrinfo is bogus ! * it is not able to return an IPv6 addrinfo from an IPv4 address when AI_V4MAPPED is set ! **/ struct addrinfo *addrinfo_concat(struct addrinfo *a1, struct addrinfo *a2){ struct addrinfo *it; struct addrinfo *last=NULL; for (it=a1;it!=NULL;it=it->ai_next){ last=it; } if (last){ last->ai_next=a2; return a1; }else return a2; } int bctbx_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res){ if (hints && hints->ai_family!=AF_INET && hints->ai_flags & AI_V4MAPPED){ struct addrinfo *res6=NULL; struct addrinfo *res4=NULL; struct addrinfo lhints={0}; int err; if (hints) memcpy(&lhints,hints,sizeof(lhints)); lhints.ai_flags &= ~(AI_ALL | AI_V4MAPPED); /*remove the unsupported flags*/ lhints.ai_family = AF_INET6; err = getaddrinfo(node, service, &lhints, &res6); if (hints->ai_flags & AI_ALL) { lhints.ai_family=AF_INET; err=getaddrinfo(node, service, &lhints, &res4); if (err==0){ struct addrinfo *v4m=convert_to_v4mapped(res4); freeaddrinfo(res4); res4=v4m; } *res=addrinfo_concat(res6,res4); if (*res) err=0; } return err; } return getaddrinfo(node, service, hints, res); } #else int bctbx_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res){ int result = getaddrinfo(node, service, hints, res); #if __APPLE__ if (*res && (*res)->ai_family == AF_INET6) { struct sockaddr_in6* sockaddr = (struct sockaddr_in6*)(*res)->ai_addr; if (sockaddr->sin6_port == 0 && service) { int possible_port = atoi(service); if (possible_port > 0 && possible_port <= 65535) { bctbx_message("Apple nat64 getaddrinfo bug, fixing port to [%i]",possible_port); sockaddr->sin6_port = htons(possible_port); } } } #endif return result; } #endif int bctbx_getnameinfo(const struct sockaddr *addr, socklen_t addrlen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags) { #if __APPLE__ /* What an unpleasant surprise... It appears getnameinfo from Apple is calling inet_ntoa internally that is not thread-safe: * https://opensource.apple.com/source/Libc/Libc-583/net/FreeBSD/inet_ntoa.c * http://www.educatedguesswork.org/2009/02/well_thats_an_unpleasant_surpr.html */ int i; int err; for (i = 0; i < 50; i++) { err = getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags); if (!(host && strstr(host, "[inet_ntoa error]"))) return err; } return EAI_AGAIN; #else return getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags); #endif } static void _bctbx_addrinfo_to_ip_address_error(int err, char *ip, size_t ip_size) { bctbx_error("getnameinfo() error: %s", gai_strerror(err)); strncpy(ip, "", ip_size); } int bctbx_addrinfo_to_ip_address(const struct addrinfo *ai, char *ip, size_t ip_size, int *port){ char serv[16]; int err=bctbx_getnameinfo(ai->ai_addr,(socklen_t)ai->ai_addrlen,ip,(socklen_t)ip_size,serv,(socklen_t)sizeof(serv),NI_NUMERICHOST|NI_NUMERICSERV); if (err!=0) _bctbx_addrinfo_to_ip_address_error(err, ip, ip_size); if (port) *port=atoi(serv); return 0; } int bctbx_addrinfo_to_printable_ip_address(const struct addrinfo *ai, char *printable_ip, size_t printable_ip_size) { char ip[64]; char serv[16]; int err = bctbx_getnameinfo(ai->ai_addr, (socklen_t)ai->ai_addrlen, ip, sizeof(ip), serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV); if (err != 0) _bctbx_addrinfo_to_ip_address_error(err, ip, sizeof(ip)); if (ai->ai_family == AF_INET) snprintf(printable_ip, printable_ip_size, "%s:%s", ip, serv); else if (ai->ai_family == AF_INET6) snprintf(printable_ip, printable_ip_size, "[%s]:%s", ip, serv); return 0; } int bctbx_sockaddr_to_ip_address(const struct sockaddr *sa, socklen_t salen, char *ip, size_t ip_size, int *port) { struct addrinfo ai = { 0 }; ai.ai_addr = (struct sockaddr*)sa; ai.ai_addrlen = salen; ai.ai_family = sa->sa_family; return bctbx_addrinfo_to_ip_address(&ai, ip, ip_size, port); } int bctbx_sockaddr_to_printable_ip_address(struct sockaddr *sa, socklen_t salen, char *printable_ip, size_t printable_ip_size) { if ((sa->sa_family == 0) || (salen == 0)) { snprintf(printable_ip, printable_ip_size, "no-addr"); return 0; } else { struct addrinfo ai = { 0 }; ai.ai_addr = sa; ai.ai_addrlen = salen; ai.ai_family = sa->sa_family; return bctbx_addrinfo_to_printable_ip_address(&ai, printable_ip, printable_ip_size); } } static struct addrinfo * _bctbx_name_to_addrinfo(int family, int socktype, const char *ipaddress, int port, int numeric_only){ struct addrinfo *res=NULL; struct addrinfo hints={0}; char serv[10]; int err; snprintf(serv,sizeof(serv),"%i",port); hints.ai_family=family; if (numeric_only) hints.ai_flags=AI_NUMERICSERV|AI_NUMERICHOST; hints.ai_socktype=socktype; if (family == AF_INET6) { hints.ai_flags |= AI_V4MAPPED; hints.ai_flags |= AI_ALL; } err=bctbx_getaddrinfo(ipaddress,serv,&hints,&res); if (err!=0){ if (!numeric_only || err!=EAI_NONAME) bctbx_error("%s(%s): getaddrinfo failed: %s",__FUNCTION__, ipaddress, gai_strerror(err)); return NULL; } return res; } struct addrinfo * bctbx_name_to_addrinfo(int family, int socktype, const char *name, int port){ return _bctbx_name_to_addrinfo(family, socktype, name, port, FALSE); } struct addrinfo * bctbx_ip_address_to_addrinfo(int family, int socktype, const char *name, int port){ struct addrinfo * res = _bctbx_name_to_addrinfo(family, socktype, name, port, TRUE); #if __APPLE__ /*required for nat64 on apple platform*/ if (res) { /*fine, we are sure that name was an ip address, give a chance to get its nat64 form*/ bctbx_freeaddrinfo(res); res = bctbx_name_to_addrinfo(family, SOCK_STREAM, name, port); } #endif return res; } #ifndef IN6_GET_ADDR_V4MAPPED #define IN6_GET_ADDR_V4MAPPED(sin6_addr) *(unsigned int*)((unsigned char*)(sin6_addr)+12) #endif void bctbx_sockaddr_remove_v4_mapping(const struct sockaddr *v6, struct sockaddr *result, socklen_t *result_len) { if (v6->sa_family == AF_INET6) { struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)v6; if (IN6_IS_ADDR_V4MAPPED(&in6->sin6_addr)) { struct sockaddr_in *in = (struct sockaddr_in *)result; result->sa_family = AF_INET; in->sin_addr.s_addr = IN6_GET_ADDR_V4MAPPED(&in6->sin6_addr); in->sin_port = in6->sin6_port; *result_len = sizeof(struct sockaddr_in); } else { if (v6 != result) memcpy(result, v6, sizeof(struct sockaddr_in6)); *result_len = sizeof(struct sockaddr_in6); } } else { *result_len = sizeof(struct sockaddr_in); if (v6 != result) memcpy(result, v6, sizeof(struct sockaddr_in)); } } void bctbx_sockaddr_remove_nat64_mapping(const struct sockaddr *v6, struct sockaddr *result, socklen_t *result_len) { if (v6->sa_family == AF_INET6) { struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)v6; if (htonl(0x0064ff9b) == #ifdef _MSC_VER ((in6->sin6_addr.u.Word[0] << 16) & in6->sin6_addr.u.Word[1]) #elif __APPLE__ in6->sin6_addr.__u6_addr.__u6_addr32[0] #else in6->sin6_addr.s6_addr32[0] #endif ) { struct sockaddr_in *in = (struct sockaddr_in *)result; result->sa_family = AF_INET; in->sin_addr.s_addr = IN6_GET_ADDR_V4MAPPED(&in6->sin6_addr); in->sin_port = in6->sin6_port; *result_len = sizeof(struct sockaddr_in); } } else { *result_len = sizeof(struct sockaddr_in); if (v6 != result) memcpy(result, v6, sizeof(struct sockaddr_in)); } } void bctbx_sockaddr_ipv6_to_ipv4(const struct sockaddr *v6, struct sockaddr *result, socklen_t *result_len) { bctbx_sockaddr_remove_v4_mapping(v6, result, result_len); } void bctbx_sockaddr_ipv4_to_ipv6(const struct sockaddr *v4, struct sockaddr *result, socklen_t *result_len) { if (v4->sa_family == AF_INET) { struct addrinfo *v4m; struct addrinfo ai = { 0 }; struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)result; ai.ai_addr = (struct sockaddr *)v4; ai.ai_addrlen = sizeof(struct sockaddr_in); ai.ai_family = v4->sa_family; v4m = convert_to_v4mapped(&ai); *result_len = sizeof(struct sockaddr_in6); memcpy(v6, v4m->ai_addr, *result_len); bctbx_freeaddrinfo(v4m); } } char * bctbx_concat(const char *str, ...) { va_list ap; size_t allocated = 100; char *result = (char *) malloc (allocated); if (result != NULL) { char *newp; char *wp; const char* s; va_start (ap, str); wp = result; for (s = str; s != NULL; s = va_arg (ap, const char *)) { size_t len = strlen (s); /* Resize the allocated memory if necessary. */ if (wp + len + 1 > result + allocated) { allocated = (allocated + len) * 2; newp = (char *) realloc (result, allocated); if (newp == NULL) { free (result); return NULL; } wp = newp + (wp - result); result = newp; } memcpy (wp, s, len); wp +=len; } /* Terminate the result string. */ *wp++ = '\0'; /* Resize memory to the optimal size. */ newp = realloc (result, wp - result); if (newp != NULL) result = newp; va_end (ap); } return result; } bool_t bctbx_sockaddr_equals(const struct sockaddr * sa, const struct sockaddr * sb) { if (sa->sa_family != sb->sa_family) return FALSE; if (sa->sa_family == AF_INET) { if ((((struct sockaddr_in*)sa)->sin_addr.s_addr != ((struct sockaddr_in*)sb)->sin_addr.s_addr || ((struct sockaddr_in*)sa)->sin_port != ((struct sockaddr_in*)sb)->sin_port)) return FALSE; } else if (sa->sa_family == AF_INET6) { if (memcmp(&((struct sockaddr_in6*)sa)->sin6_addr , &((struct sockaddr_in6*)sb)->sin6_addr , sizeof(struct in6_addr)) !=0 || ((struct sockaddr_in6*)sa)->sin6_port != ((struct sockaddr_in6*)sb)->sin6_port) return FALSE; } else { bctbx_warning ("Cannot compare family type [%d]", sa->sa_family); return FALSE; } return TRUE; } static const char *ai_family_to_string(int af) { switch(af) { case AF_INET: return "AF_INET"; case AF_INET6: return "AF_INET6"; case AF_UNSPEC: return "AF_UNSPEC"; default: return "invalid address family"; } } static int get_local_ip_for_with_connect(int type, const char *dest, int port, char *result, size_t result_len) { int err, tmp; struct addrinfo hints; struct addrinfo *res = NULL; struct sockaddr_storage addr; struct sockaddr *p_addr = (struct sockaddr *)&addr; bctbx_socket_t sock; socklen_t s; char port_str[6] = { 0 }; memset(&hints, 0, sizeof(hints)); hints.ai_family = type; hints.ai_socktype = SOCK_DGRAM; /*hints.ai_flags = AI_NUMERICHOST | AI_CANONNAME;*/ snprintf(port_str, sizeof(port_str), "%i", port); err = getaddrinfo(dest, port_str, &hints, &res); if (err != 0) { bctbx_error("getaddrinfo() error for %s: %s",dest, gai_strerror(err)); return -1; } if (res == NULL) { bctbx_error("bug: getaddrinfo returned nothing."); return -1; } sock = socket(res->ai_family, SOCK_DGRAM, 0); if (sock == (bctbx_socket_t)-1) { bctbx_error("get_local_ip_for_with_connect() could not create [%s] socket: %s", ai_family_to_string(res->ai_family), getSocketError()); return -1; } tmp = 1; err = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (SOCKET_OPTION_VALUE)&tmp, sizeof(int)); if (err == -1) bctbx_warning("Error in setsockopt: %s", getSocketError()); err = connect(sock, res->ai_addr, (int)res->ai_addrlen); if (err == -1) { /* The network isn't reachable. We don't display the error as it is the case that we want to check in normal operation. */ if ( getSocketErrorCode() != BCTBX_ENETUNREACH && getSocketErrorCode() != BCTBX_EHOSTUNREACH && getSocketErrorCode() != BCTBX_EPROTOTYPE) bctbx_error("Error in connect: %s", getSocketError()); freeaddrinfo(res); bctbx_socket_close(sock); return -1; } freeaddrinfo(res); res = NULL; s = sizeof(addr); err = getsockname(sock, (struct sockaddr *)&addr, &s); if (err != 0) { bctbx_error("Error in getsockname: %s", getSocketError()); bctbx_socket_close(sock); return -1; } if (p_addr->sa_family == AF_INET) { struct sockaddr_in *p_sin = (struct sockaddr_in *)p_addr; if (p_sin->sin_addr.s_addr == 0) { bctbx_socket_close(sock); return -1; } } err = bctbx_getnameinfo((struct sockaddr *)&addr, s, result, (socklen_t)result_len, NULL, 0, NI_NUMERICHOST); if (err != 0) bctbx_error("getnameinfo error: %s", gai_strerror(err)); /* Avoid ipv6 link-local addresses */ if ((p_addr->sa_family == AF_INET6) && (strchr(result, '%') != NULL)) { strcpy(result, "::1"); bctbx_socket_close(sock); return -1; } bctbx_socket_close(sock); return 0; } int bctbx_get_local_ip_for(int type, const char *dest, int port, char *result, size_t result_len) { strncpy(result, (type == AF_INET) ? "127.0.0.1" : "::1", result_len); if (dest == NULL) { if (type == AF_INET) dest="87.98.157.38"; /* A public IP address */ else dest = "2a00:1450:8002::68"; } if (port == 0) port = 5060; return get_local_ip_for_with_connect(type, dest, port, result, result_len); } void _bctbx_freeaddrinfo(struct addrinfo *res){ struct addrinfo *it,*next_it; for(it=res;it!=NULL;it=next_it){ next_it=it->ai_next; bctbx_free(it); } } void bctbx_freeaddrinfo(struct addrinfo *res){ struct addrinfo *it; struct addrinfo *previt = NULL; struct addrinfo *beginit = res; bool_t looking_for_allocated_by_bctbx = (res->ai_canonname == allocated_by_bctbx_magic) ? TRUE : FALSE; for (it = res; it != NULL; it = it->ai_next) { if ((looking_for_allocated_by_bctbx == TRUE) && (it->ai_canonname != allocated_by_bctbx_magic)) { if (previt) { previt->ai_next = NULL; _bctbx_freeaddrinfo(beginit); looking_for_allocated_by_bctbx = FALSE; beginit = it; } } else if ((looking_for_allocated_by_bctbx == FALSE) && (it->ai_canonname == allocated_by_bctbx_magic)) { if (previt) { previt->ai_next = NULL; freeaddrinfo(beginit); looking_for_allocated_by_bctbx = TRUE; beginit = it; } } previt = it; } if (looking_for_allocated_by_bctbx == TRUE) _bctbx_freeaddrinfo(beginit); else freeaddrinfo(beginit); } uint8_t bctbx_char_to_byte(uint8_t input_char) { /* 0-9 */ if (input_char>0x29 && input_char<0x3A) { return input_char - 0x30; } /* a-f */ if (input_char>0x60 && input_char<0x67) { return input_char - 0x57; /* 0x57 = 0x61(a) + 0x0A*/ } /* A-F */ if (input_char>0x40 && input_char<0x47) { return input_char - 0x37; /* 0x37 = 0x41(a) + 0x0A*/ } /* shall never arrive here, string is not Hex*/ return 0; } uint8_t bctbx_byte_to_char(uint8_t input_byte) { uint8_t input_byte_crop = input_byte&0x0F; /* restrict the input value to range [0-15] */ /* 0-9 */ if(input_byte_crop<0x0A) { return input_byte_crop+0x30; } /* a-f */ return input_byte_crop + 0x57; } void bctbx_str_to_uint8(uint8_t *output_bytes, const uint8_t *input_string, size_t input_string_length) { size_t i; for (i=0; i>4)&0x0F); output_string[2*i+1] = bctbx_byte_to_char(input_bytes[i]&0x0F); } } void bctbx_uint32_to_str(uint8_t output_string[9], uint32_t input_uint32) { output_string[0] = bctbx_byte_to_char((uint8_t)((input_uint32>>28)&0x0F)); output_string[1] = bctbx_byte_to_char((uint8_t)((input_uint32>>24)&0x0F)); output_string[2] = bctbx_byte_to_char((uint8_t)((input_uint32>>20)&0x0F)); output_string[3] = bctbx_byte_to_char((uint8_t)((input_uint32>>16)&0x0F)); output_string[4] = bctbx_byte_to_char((uint8_t)((input_uint32>>12)&0x0F)); output_string[5] = bctbx_byte_to_char((uint8_t)((input_uint32>>8)&0x0F)); output_string[6] = bctbx_byte_to_char((uint8_t)((input_uint32>>4)&0x0F)); output_string[7] = bctbx_byte_to_char((uint8_t)((input_uint32)&0x0F)); output_string[8] = '\0'; } uint32_t bctbx_str_to_uint32(const uint8_t *input_string) { return (((uint32_t)bctbx_char_to_byte(input_string[0]))<<28) | (((uint32_t)bctbx_char_to_byte(input_string[1]))<<24) | (((uint32_t)bctbx_char_to_byte(input_string[2]))<<20) | (((uint32_t)bctbx_char_to_byte(input_string[3]))<<16) | (((uint32_t)bctbx_char_to_byte(input_string[4]))<<12) | (((uint32_t)bctbx_char_to_byte(input_string[5]))<<8) | (((uint32_t)bctbx_char_to_byte(input_string[6]))<<4) | (((uint32_t)bctbx_char_to_byte(input_string[7]))); } void bctbx_uint64_to_str(uint8_t output_string[17], uint64_t input_uint64) { output_string[0] = bctbx_byte_to_char((uint8_t)((input_uint64>>60)&0x0F)); output_string[1] = bctbx_byte_to_char((uint8_t)((input_uint64>>56)&0x0F)); output_string[2] = bctbx_byte_to_char((uint8_t)((input_uint64>>52)&0x0F)); output_string[3] = bctbx_byte_to_char((uint8_t)((input_uint64>>48)&0x0F)); output_string[4] = bctbx_byte_to_char((uint8_t)((input_uint64>>44)&0x0F)); output_string[5] = bctbx_byte_to_char((uint8_t)((input_uint64>>40)&0x0F)); output_string[6] = bctbx_byte_to_char((uint8_t)((input_uint64>>36)&0x0F)); output_string[7] = bctbx_byte_to_char((uint8_t)((input_uint64>>32)&0x0F)); output_string[8] = bctbx_byte_to_char((uint8_t)((input_uint64>>28)&0x0F)); output_string[9] = bctbx_byte_to_char((uint8_t)((input_uint64>>24)&0x0F)); output_string[10] = bctbx_byte_to_char((uint8_t)((input_uint64>>20)&0x0F)); output_string[11] = bctbx_byte_to_char((uint8_t)((input_uint64>>16)&0x0F)); output_string[12] = bctbx_byte_to_char((uint8_t)((input_uint64>>12)&0x0F)); output_string[13] = bctbx_byte_to_char((uint8_t)((input_uint64>>8)&0x0F)); output_string[14] = bctbx_byte_to_char((uint8_t)((input_uint64>>4)&0x0F)); output_string[15] = bctbx_byte_to_char((uint8_t)((input_uint64)&0x0F)); output_string[16] = '\0'; } uint64_t bctbx_str_to_uint64(const uint8_t input_string[17]) { return (((uint64_t)bctbx_char_to_byte(input_string[0]))<<60) | (((uint64_t)bctbx_char_to_byte(input_string[1]))<<56) | (((uint64_t)bctbx_char_to_byte(input_string[2]))<<52) | (((uint64_t)bctbx_char_to_byte(input_string[3]))<<48) | (((uint64_t)bctbx_char_to_byte(input_string[4]))<<44) | (((uint64_t)bctbx_char_to_byte(input_string[5]))<<40) | (((uint64_t)bctbx_char_to_byte(input_string[6]))<<36) | (((uint64_t)bctbx_char_to_byte(input_string[7]))<<32) | (((uint64_t)bctbx_char_to_byte(input_string[8]))<<28) | (((uint64_t)bctbx_char_to_byte(input_string[9]))<<24) | (((uint64_t)bctbx_char_to_byte(input_string[10]))<<20) | (((uint64_t)bctbx_char_to_byte(input_string[11]))<<16) | (((uint64_t)bctbx_char_to_byte(input_string[12]))<<12) | (((uint64_t)bctbx_char_to_byte(input_string[13]))<<8) | (((uint64_t)bctbx_char_to_byte(input_string[14]))<<4) | (((uint64_t)bctbx_char_to_byte(input_string[15]))); } bctoolbox-0.6.0/src/vconnect.c000066400000000000000000000126621313410701300162620ustar00rootroot00000000000000/* vconnect.c Copyright (C) 2017 Belledonne Communications SARL This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "bctoolbox/vconnect.h" #include "bctoolbox/port.h" #include "bctoolbox/logging.h" #include #include #include /**============================================================ * Wrappers around default libc calls used to handle windows * differences in function prototypes. *=============================================================*/ static bctbx_socket_t vsocket_socket(int socket_family, int socket_type, int protocol){ return socket(socket_family, socket_type, protocol); } static int vsocket_connect(bctbx_socket_t sock, const struct sockaddr *address, socklen_t address_len){ #ifdef _WIN32 return connect(sock, address, (int)address_len); #else return connect(sock, address, address_len); #endif } static int vsocket_bind(bctbx_socket_t sock, const struct sockaddr *address, socklen_t address_len){ #ifdef _WIN32 return bind(sock, address, (int)address_len); #else return bind(sock, address, address_len); #endif } static int vsocket_getsockname(bctbx_socket_t sockfd, struct sockaddr *addr, socklen_t *addrlen){ #ifdef _WIN32 return getsockname(sockfd, addr, (int*)addrlen); #else return getsockname(sockfd, addr, addrlen); #endif } static int vsocket_getsockopt(bctbx_socket_t sockfd, int level, int optname, void *optval, socklen_t* optlen){ #ifdef _WIN32 return getsockopt(sockfd, level, optname, (char*)optval, (int*)optlen); #else return getsockopt(sockfd, level, optname, optval, optlen); #endif } static int vsocket_setsockopt(bctbx_socket_t sockfd, int level, int optname, const void *optval, socklen_t optlen){ #ifdef _WIN32 return setsockopt(sockfd, level, optname, (char*)optval, (int)optlen); #else return setsockopt(sockfd, level, optname, optval, optlen); #endif } static int vsocket_close(bctbx_socket_t sock){ #ifdef _WIN32 return closesocket(sock); #else return close(sock); #endif } static int vsocket_shutdown(bctbx_socket_t sock, int how){ return shutdown(sock, how); } #if !defined(_WIN32) && !defined(_WIN32_WCE) static char* vsocket_error(int err){ return strerror (err); } #else static char* vsocket_error(int err){ return (char*)__bctbx_getWinSocketError(err); } #endif /**=================================================== * Socket API default methods pointer definition. * ===================================================*/ static const bctbx_vsocket_methods_t bcSocketAPI = { vsocket_socket, vsocket_connect, vsocket_bind, vsocket_getsockname, vsocket_getsockopt, vsocket_setsockopt, vsocket_close, vsocket_error, vsocket_shutdown, }; static bctbx_vsocket_api_t bcvSocket = { "bctbx_socket", /* vSockName */ &bcSocketAPI, /*pSocketMethods */ }; /* Pointer to default socket methods initialized to standard libc implementation here.*/ static bctbx_vsocket_api_t *pDefaultvSocket = &bcvSocket; bctbx_socket_t bctbx_socket(int socket_family, int socket_type, int protocol){ return pDefaultvSocket->pSocketMethods->pFuncSocket( socket_family, socket_type, protocol); } int bctbx_socket_close(bctbx_socket_t sock){ return pDefaultvSocket->pSocketMethods->pFuncClose(sock); } int bctbx_bind(bctbx_socket_t sock, const struct sockaddr *address, socklen_t address_len){ return pDefaultvSocket->pSocketMethods->pFuncBind(sock, address, address_len); } int bctbx_connect(bctbx_socket_t sock, const struct sockaddr *address, socklen_t address_len){ return pDefaultvSocket->pSocketMethods->pFuncConnect(sock, address, address_len); } int bctbx_getsockname(bctbx_socket_t sockfd, struct sockaddr *addr, socklen_t *addrlen){ return pDefaultvSocket->pSocketMethods->pFuncGetSockName(sockfd, addr, addrlen); } int bctbx_getsockopt(bctbx_socket_t sockfd, int level, int optname, void *optval, socklen_t* optlen){ return pDefaultvSocket->pSocketMethods->pFuncGetSockOpt(sockfd, level, optname, optval, optlen); } int bctbx_setsockopt(bctbx_socket_t sockfd, int level, int optname, const void *optval, socklen_t optlen){ return pDefaultvSocket->pSocketMethods->pFuncSetSockOpt(sockfd, level, optname, optval, optlen); } int bctbx_shutdown(bctbx_socket_t sock, int how){ return pDefaultvSocket->pSocketMethods->pFuncShutdown(sock, how); } char* bctbx_socket_error(int err){ return pDefaultvSocket->pSocketMethods->pFuncGetError(err); } void bctbx_vsocket_api_set_default(bctbx_vsocket_api_t *my_vsocket_api) { if (my_vsocket_api == NULL){ pDefaultvSocket = &bcvSocket; } else { pDefaultvSocket = my_vsocket_api ; } } bctbx_vsocket_api_t* bctbx_vsocket_api_get_default(void) { return pDefaultvSocket; } bctbx_vsocket_api_t* bctbx_vsocket_api_get_standard(void) { return &bcvSocket; } bctoolbox-0.6.0/src/vfs.c000066400000000000000000000306571313410701300152450ustar00rootroot00000000000000/* vfs.c Copyright (C) 2016 Belledonne Communications SARL This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "bctoolbox/vfs.h" #include "bctoolbox/port.h" #include "bctoolbox/logging.h" #include #include #include /** * Opens the file with filename fName, associate it to the file handle pointed * by pFile, sets the methods bctbx_io_methods_t to the bcio structure * and initializes the file size. * Sets the error in pErrSvd if an error occurred while opening the file fName. * @param pVfs Pointer to bctx_vfs VFS. * @param fName Absolute path filename. * @param openFlags Flags to use when opening the file. * @return BCTBX_VFS_ERROR if an error occurs, BCTBX_VFS_OK otherwise. */ static int bcOpen(bctbx_vfs_t *pVfs, bctbx_vfs_file_t *pFile, const char *fName, int openFlags); static bctbx_vfs_t bcVfs = { "bctbx_vfs", /* vfsName */ bcOpen, /*xOpen */ }; /* Pointer to default VFS initialized to standard VFS implemented here.*/ static bctbx_vfs_t *pDefaultVfs = &bcVfs; /** * Closes file by closing the associated file descriptor. * Sets the error errno in the argument pErrSrvd after allocating it * if an error occurrred. * @param pFile bctbx_vfs_file_t File handle pointer. * @return BCTBX_VFS_OK if successful, BCTBX_VFS_ERROR otherwise. */ static int bcClose(bctbx_vfs_file_t *pFile) { int ret; ret = close(pFile->fd); if (!ret) { ret = BCTBX_VFS_OK; } else { ret = -errno; } return ret; } /** * Repositions the open file offset given by the file descriptor fd from the file handle pFile * to the parameter offset, according to whence. * @param pFile File handle pointer. * @param offset file offset where to set the position to * @param whence Either SEEK_SET, SEEK_CUR,SEEK_END . * @return offset bytes from the beginning of the file, BCTBX_VFS_ERROR otherwise */ static off_t bcSeek(bctbx_vfs_file_t *pFile, off_t offset, int whence) { off_t ofst; if (pFile) { ofst = lseek(pFile->fd, offset, whence); if (ofst < 0) return -errno; return ofst; } return BCTBX_VFS_ERROR; } /** * Read count bytes from the open file given by pFile, starting at offset. * Sets the error errno in the argument pErrSrvd after allocating it * if an error occurrred. * @param pFile File handle pointer. * @param buf buffer to write the read bytes to. * @param count number of bytes to read * @param offset file offset where to start reading * @return -errno if erroneous read, number of bytes read (count) on success, * if the error was something else BCTBX_VFS_ERROR otherwise */ static ssize_t bcRead(bctbx_vfs_file_t *pFile, void *buf, size_t count, off_t offset) { ssize_t nRead; /* Return value from read() */ if (pFile) { if (bctbx_file_seek(pFile, offset, SEEK_SET) == BCTBX_VFS_OK) { nRead = bctbx_read(pFile->fd, buf, count); /* Error while reading */ if (nRead < 0) { if (errno) return -errno; } return nRead; } } return BCTBX_VFS_ERROR; } /** * Writes directly to the open file given through the pFile argument. * Sets the error errno in the argument pErrSrvd after allocating it * if an error occurrred. * @param p bctbx_vfs_file_t File handle pointer. * @param buf Buffer containing data to write * @param count Size of data to write in bytes * @param offset File offset where to write to * @return number of bytes written (can be 0), negative value errno if an error occurred. */ static ssize_t bcWrite(bctbx_vfs_file_t *p, const void *buf, size_t count, off_t offset) { ssize_t nWrite = 0; /* Return value from write() */ if (p) { if ((bctbx_file_seek(p, offset, SEEK_SET)) == BCTBX_VFS_OK) { nWrite = bctbx_write(p->fd, buf, count); if (nWrite > 0) return nWrite; else if (nWrite <= 0) { if (errno) return -errno; return 0; } } } return BCTBX_VFS_ERROR; } /** * Returns the file size associated with the file handle pFile. * @param pFile File handle pointer. * @return -errno if an error occurred, file size otherwise (can be 0). */ static int64_t bcFileSize(bctbx_vfs_file_t *pFile) { int rc; /* Return code from fstat() call */ struct stat sStat; /* Output of fstat() call */ rc = fstat(pFile->fd, &sStat); if (rc != 0) { return -errno; } return sStat.st_size; } /* ** Truncate a file * @param pFile File handle pointer. * @param new_size Extends the file with null bytes if it is superiori to the file's size * truncates the file otherwise. * @return -errno if an error occurred, 0 otherwise. */ static int bcTruncate(bctbx_vfs_file_t *pFile, int64_t new_size){ int ret; #if _WIN32 ret = _chsize(pFile->fd, (long)new_size); #else ret = ftruncate(pFile->fd, new_size); #endif if (ret < 0) { return -errno; } return 0; } /** * Gets a line of max_len length and stores it to the allocaed buffer s. * Reads at most max_len characters from the file descriptor associated with the argument pFile * and looks for an end of line character (\r or \n). Stores the line found * into the buffer pointed by s. * Modifies the open file offset using pFile->offset. * * @param pFile File handle pointer. * @param s Buffer where to store the line. * @param max_len Maximum number of characters to read in one fetch. * @return size of line read, 0 if empty */ static int bcGetLine(bctbx_vfs_file_t *pFile, char *s, int max_len) { int64_t ret; int sizeofline; char *pNextLine = NULL; char *pNextLineR = NULL; char *pNextLineN = NULL; if (pFile->fd == -1) { return BCTBX_VFS_ERROR; } if (s == NULL || max_len < 1) { return BCTBX_VFS_ERROR; } sizeofline = 0; s[max_len-1] = '\0'; /* Read returns 0 if end of file is found */ ret = bctbx_file_read(pFile, s, max_len - 1, pFile->offset); if (ret > 0) { pNextLineR = strchr(s, '\r'); pNextLineN = strchr(s, '\n'); if ((pNextLineR != NULL) && (pNextLineN != NULL)) pNextLine = MIN(pNextLineR, pNextLineN); else if (pNextLineR != NULL) pNextLine = pNextLineR; else if (pNextLineN != NULL) pNextLine = pNextLineN; if (pNextLine) { /* Got a line! */ *pNextLine = '\0'; sizeofline = (int)(pNextLine - s + 1); if (pNextLine[1] == '\n') sizeofline += 1; /*take into account the \r\n" case*/ /* offset to next beginning of line*/ pFile->offset += sizeofline; } else { /*did not find end of line char, is EOF?*/ sizeofline = (int)ret; pFile->offset += sizeofline; s[ret] = '\0'; } } else if (ret < 0) { bctbx_error("bcGetLine error"); } return sizeofline; } /** * Create flags (int) from mode(char*). * @param mode Can be r, r+, w+, w * @return flags (integer). */ static int set_flags(const char* mode) { int flags = 0 ; /* flags to pass to open() call */ if (strcmp(mode, "r") == 0) { flags = O_RDONLY; } else if ((strcmp(mode, "r+") == 0) || (strcmp(mode, "w+") == 0)) { flags = O_RDWR; } else if(strcmp(mode, "w") == 0) { flags = O_WRONLY; } return flags | O_CREAT; } static const bctbx_io_methods_t bcio = { bcClose, /* pFuncClose */ bcRead, /* pFuncRead */ bcWrite, /* pFuncWrite */ bcTruncate, /* pFuncTruncate */ bcFileSize, /* pFuncFileSize */ bcGetLine, bcSeek, }; static int bcOpen(bctbx_vfs_t *pVfs, bctbx_vfs_file_t *pFile, const char *fName, int openFlags) { if (pFile == NULL || fName == NULL) { return BCTBX_VFS_ERROR; } #if _WIN32 openFlags |= O_BINARY; #endif pFile->fd = open(fName, openFlags, S_IRUSR | S_IWUSR); if (pFile->fd == -1) { return -errno; } pFile->pMethods = &bcio; return BCTBX_VFS_OK; } ssize_t bctbx_file_write(bctbx_vfs_file_t* pFile, const void *buf, size_t count, off_t offset) { ssize_t ret; if (pFile != NULL) { ret = pFile->pMethods->pFuncWrite(pFile, buf, count, offset); if (ret == BCTBX_VFS_ERROR) { bctbx_error("bctbx_file_write file error"); return BCTBX_VFS_ERROR; } else if (ret < 0) { bctbx_error("bctbx_file_write error %s", strerror(-(ret))); return BCTBX_VFS_ERROR; } return ret; } return BCTBX_VFS_ERROR; } static int file_open(bctbx_vfs_t* pVfs, bctbx_vfs_file_t* pFile, const char *fName, const int oflags) { int ret = BCTBX_VFS_ERROR; if (pVfs && pFile ) { ret = pVfs->pFuncOpen(pVfs, pFile, fName, oflags); if (ret == BCTBX_VFS_ERROR) { bctbx_error("bctbx_file_open: Error file handle"); } else if (ret < 0 ) { bctbx_error("bctbx_file_open: Error open %s", strerror(-(ret))); ret = BCTBX_VFS_ERROR; } } return ret; } bctbx_vfs_file_t* bctbx_file_open(bctbx_vfs_t *pVfs, const char *fName, const char *mode) { int ret; bctbx_vfs_file_t* p_ret = (bctbx_vfs_file_t*)bctbx_malloc(sizeof(bctbx_vfs_file_t)); int oflags = set_flags(mode); if (p_ret) { memset(p_ret, 0, sizeof(bctbx_vfs_file_t)); ret = file_open(pVfs, p_ret, fName, oflags); if (ret == BCTBX_VFS_OK) return p_ret; } if (p_ret) bctbx_free(p_ret); return NULL; } bctbx_vfs_file_t* bctbx_file_open2(bctbx_vfs_t *pVfs, const char *fName, const int openFlags) { int ret; bctbx_vfs_file_t *p_ret = (bctbx_vfs_file_t *)bctbx_malloc(sizeof(bctbx_vfs_file_t)); if (p_ret) { memset(p_ret, 0, sizeof(bctbx_vfs_file_t)); ret = file_open(pVfs, p_ret, fName, openFlags); if (ret == BCTBX_VFS_OK) return p_ret; } if (p_ret) bctbx_free(p_ret); return NULL; } ssize_t bctbx_file_read(bctbx_vfs_file_t *pFile, void *buf, size_t count, off_t offset) { int ret = BCTBX_VFS_ERROR; if (pFile) { ret = pFile->pMethods->pFuncRead(pFile, buf, count, offset); /*check if error : in this case pErrSvd is initialized*/ if (ret == BCTBX_VFS_ERROR) { bctbx_error("bctbx_file_read: error bctbx_vfs_file_t"); } else if (ret < 0) { bctbx_error("bctbx_file_read: Error read %s", strerror(-(ret))); ret = BCTBX_VFS_ERROR; } } return ret; } int bctbx_file_close(bctbx_vfs_file_t *pFile) { int ret = BCTBX_VFS_ERROR; if (pFile) { ret = pFile->pMethods->pFuncClose(pFile); if (ret != 0) { bctbx_error("bctbx_file_close: Error %s freeing file handle anyway", strerror(-(ret))); } } bctbx_free(pFile); return ret; } int64_t bctbx_file_size(bctbx_vfs_file_t *pFile) { int64_t ret = BCTBX_VFS_ERROR; if (pFile){ ret = pFile->pMethods->pFuncFileSize(pFile); if (ret < 0) bctbx_error("bctbx_file_size: Error file size %s", strerror((int)-(ret))); } return ret; } int bctbx_file_truncate(bctbx_vfs_file_t *pFile, int64_t size) { int ret = BCTBX_VFS_ERROR; if (pFile){ ret = pFile->pMethods->pFuncTruncate(pFile, size); if (ret < 0) bctbx_error("bctbx_file_truncate: Error truncate %s", strerror((int)-(ret))); } return ret; } ssize_t bctbx_file_fprintf(bctbx_vfs_file_t *pFile, off_t offset, const char *fmt, ...) { char *ret = NULL; va_list args; ssize_t r = BCTBX_VFS_ERROR; size_t count = 0; va_start(args, fmt); ret = bctbx_strdup_vprintf(fmt, args); if (ret != NULL) { va_end(args); count = strlen(ret); if (offset != 0) pFile->offset = offset; r = bctbx_file_write(pFile, ret, count, pFile->offset); bctbx_free(ret); if (r > 0) pFile->offset += r; } return r; } off_t bctbx_file_seek(bctbx_vfs_file_t *pFile, off_t offset, int whence) { off_t ret = BCTBX_VFS_ERROR; if (pFile) { ret = pFile->pMethods->pFuncSeek(pFile, offset, whence); if (ret < 0) { bctbx_error("bctbx_file_seek: Wrong offset %s", strerror((int)-(ret))); } else if (ret == offset) { ret = BCTBX_VFS_OK; } } return ret; } int bctbx_file_get_nxtline(bctbx_vfs_file_t *pFile, char *s, int maxlen) { if (pFile) return pFile->pMethods->pFuncGetLineFromFd(pFile, s, maxlen); return BCTBX_VFS_ERROR; } void bctbx_vfs_set_default(bctbx_vfs_t *my_vfs) { pDefaultVfs = my_vfs; } bctbx_vfs_t* bctbx_vfs_get_default(void) { return pDefaultVfs; } bctbx_vfs_t* bctbx_vfs_get_standard(void) { return &bcVfs; } bctoolbox-0.6.0/tester/000077500000000000000000000000001313410701300150075ustar00rootroot00000000000000bctoolbox-0.6.0/tester/CMakeLists.txt000066400000000000000000000041021313410701300175440ustar00rootroot00000000000000############################################################################ # CMakeLists.txt # Copyright (C) 2016 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################################################ if(ENABLE_SHARED) set(PROJECT_LIBS bctoolbox bctoolbox-tester) else() set(PROJECT_LIBS bctoolbox-static bctoolbox-tester-static) endif() if(BCUNIT_FOUND AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") set(TESTER_SOURCES bctoolbox_tester.c bctoolbox_tester.h containers.cc port.c parser.c ) string(REPLACE ";" " " LINK_FLAGS_STR "${LINK_FLAGS}") add_executable(bctoolbox_tester_exe ${TESTER_SOURCES}) if(NOT "${LINK_FLAGS_STR}" STREQUAL "") set_target_properties(bctoolbox_tester_exe PROPERTIES LINK_FLAGS "${LINK_FLAGS_STR}") endif() set_target_properties(bctoolbox_tester_exe PROPERTIES OUTPUT_NAME bctoolbox_tester) target_link_libraries(bctoolbox_tester_exe PRIVATE ${PROJECT_LIBS}) if(MBEDTLS_FOUND) target_link_libraries(bctoolbox_tester_exe PRIVATE ${MBEDTLS_LIBRARIES}) endif() if(POLARSSL_FOUND) target_link_libraries(bctoolbox_tester_exe PRIVATE ${POLARSSL_LIBRARIES}) endif() set_target_properties(bctoolbox_tester_exe PROPERTIES XCODE_ATTRIBUTE_WARNING_CFLAGS "") add_test(NAME bctoolbox_tester COMMAND bctoolbox_tester --verbose) endif() bctoolbox-0.6.0/tester/bctoolbox_tester.c000066400000000000000000000066431313410701300205450ustar00rootroot00000000000000/* bctoolbox Copyright (C) 2016 Belledonne Communications SARL 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, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "bctoolbox/logging.h" #include "bctoolbox_tester.h" static FILE * log_file = NULL; static const char *log_domain = "bctoolbox-tester"; static void log_handler(int lev, const char *fmt, va_list args) { #ifdef _WIN32 /* We must use stdio to avoid log formatting (for autocompletion etc.) */ vfprintf(lev == BCTBX_LOG_ERROR ? stderr : stdout, fmt, args); fprintf(lev == BCTBX_LOG_ERROR ? stderr : stdout, "\n"); #else va_list cap; va_copy(cap,args); vfprintf(lev == BCTBX_LOG_ERROR ? stderr : stdout, fmt, cap); fprintf(lev == BCTBX_LOG_ERROR ? stderr : stdout, "\n"); va_end(cap); #endif if (log_file){ bctbx_logv(log_domain,lev, fmt, args); } } void bctoolbox_tester_init(void(*ftester_printf)(int level, const char *fmt, va_list args)) { bc_tester_init(log_handler,BCTBX_LOG_ERROR, 0,NULL); bc_tester_add_suite(&containers_test_suite); bc_tester_add_suite(&utils_test_suite); bc_tester_add_suite(&parser_test_suite); } void bctoolbox_tester_uninit(void) { bc_tester_uninit(); } void bctoolbox_tester_before_each() { } int bctoolbox_tester_set_log_file(const char *filename) { bctbx_log_handler_t* filehandler; char* dir; char* base; if (log_file) { fclose(log_file); } log_file = fopen(filename, "a"); if (!log_file) { bctbx_error("Cannot open file [%s] for writing logs because [%s]", filename, strerror(errno)); return -1; } dir = bctbx_dirname(filename); base = bctbx_basename(filename); bctbx_message("Redirecting traces to file [%s]", filename); filehandler = bctbx_create_file_log_handler(0, dir, base, log_file); bctbx_add_log_handler(filehandler); if (dir) bctbx_free(dir); if (base) bctbx_free(base); return 0; } #if !defined(__ANDROID__) && !(defined(BCTBX_WINDOWS_PHONE) || defined(BCTBX_WINDOWS_UNIVERSAL)) static const char* bctoolbox_helper = "\t\t\t--verbose\n" "\t\t\t--silent\n" "\t\t\t--log-file \n"; int main (int argc, char *argv[]) { int i; int ret; bctbx_init_logger(TRUE); bctoolbox_tester_init(NULL); for(i=1;i0) { i += ret - 1; continue; } else if (ret<0) { bc_tester_helper(argv[0], bctoolbox_helper); } return ret; } } ret = bc_tester_start(argv[0]); bctoolbox_tester_uninit(); bctbx_uninit_logger(); return ret; } #endif bctoolbox-0.6.0/tester/bctoolbox_tester.h000066400000000000000000000023071313410701300205430ustar00rootroot00000000000000/* bctoolbox Copyright (C) 2016 Belledonne Communications SARL 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, see . */ #ifndef _BCTOOLBOX_TESTER_H #define _BCTOOLBOX_TESTER_H #include "bctoolbox/logging.h" #include "bctoolbox/tester.h" #ifdef __cplusplus #define SLOGD BCTBX_SLOGD("bctoolbox-tester") #define SLOGI BCTBX_SLOGI("bctoolbox-tester") #define SLOGW BCTBX_SLOGW("bctoolbox-tester") #define SLOGE BCTBX_SLOGE("bctoolbox-tester") extern "C" { #endif extern test_suite_t containers_test_suite; extern test_suite_t utils_test_suite; extern test_suite_t parser_test_suite; #ifdef __cplusplus }; #endif #endif /* _BCTOOLBOX_TESTER_H */ bctoolbox-0.6.0/tester/containers.cc000066400000000000000000000147151313410701300174730ustar00rootroot00000000000000/* bctoolbox Copyright (C) 2016 Belledonne Communications SARL 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, see . */ #include #include "bctoolbox_tester.h" #include "bctoolbox/map.h" #include "bctoolbox/list.h" static void multimap_insert(void) { bctbx_map_t *mmap = bctbx_mmap_ullong_new(); bctbx_list_t *head = NULL, *ref = NULL; bctbx_iterator_t *it,*end; long i=0; int N = 100; for(i=0;i. */ #include "bctoolbox_tester.h" #include "bctoolbox/parser.h" static void simple_escaping(void) { char * my_escaped_string; bctbx_noescape_rules_t my_rules = {0}; bctbx_noescape_rules_add_alfanums(my_rules); my_escaped_string = bctbx_escape("François",my_rules); BC_ASSERT_TRUE(strcmp("Fran%c3%a7ois",my_escaped_string)==0); bctbx_free(my_escaped_string); } static void simple_unescaping(void) { char * my_unescaped_string; my_unescaped_string = bctbx_unescaped_string("Fran%c3%a7ois"); BC_ASSERT_TRUE(strcmp("François",my_unescaped_string)==0); bctbx_free(my_unescaped_string); } static test_t container_tests[] = { TEST_NO_TAG("simple escaping", simple_escaping), TEST_NO_TAG("simple unescaping", simple_unescaping), }; test_suite_t parser_test_suite = {"Parsing", NULL, NULL, NULL, NULL, sizeof(container_tests) / sizeof(container_tests[0]), container_tests}; bctoolbox-0.6.0/tester/port.c000066400000000000000000000152541313410701300161460ustar00rootroot00000000000000/* bctoolbox Copyright (C) 2017 Belledonne Communications SARL 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, see . */ #include #include #include "bctoolbox_tester.h" #include "bctoolbox/port.h" static void bytes_to_from_hexa_strings(void) { const uint8_t a55aBytes[2] = {0xa5, 0x5a}; const uint8_t a55aString[5] = "a55a"; const uint8_t upBytes[8] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}; const uint8_t upString[17] = "0123456789abcdef"; const uint8_t downBytes[8] = {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}; const uint8_t downString[17] = "fedcba9876543210"; uint8_t outputBytes[16]; uint8_t outputString[16]; BC_ASSERT_EQUAL(bctbx_char_to_byte("1"[0]), 1, uint8_t, "%d"); BC_ASSERT_EQUAL(bctbx_char_to_byte("5"[0]), 5, uint8_t, "%d"); BC_ASSERT_EQUAL(bctbx_char_to_byte("a"[0]), 10, uint8_t, "%d"); BC_ASSERT_EQUAL(bctbx_char_to_byte("e"[0]), 14, uint8_t, "%d"); BC_ASSERT_EQUAL(bctbx_char_to_byte("B"[0]), 11, uint8_t, "%d"); BC_ASSERT_EQUAL(bctbx_char_to_byte("F"[0]), 15, uint8_t, "%d"); BC_ASSERT_EQUAL(bctbx_byte_to_char(0), "0"[0], char, "%c"); BC_ASSERT_EQUAL(bctbx_byte_to_char(2), "2"[0], char, "%c"); BC_ASSERT_EQUAL(bctbx_byte_to_char(5), "5"[0], char, "%c"); BC_ASSERT_EQUAL(bctbx_byte_to_char(0x0a), "a"[0], char, "%c"); BC_ASSERT_EQUAL(bctbx_byte_to_char(0x0c), "c"[0], char, "%c"); BC_ASSERT_EQUAL(bctbx_byte_to_char(0x0e), "e"[0], char, "%c"); bctbx_str_to_uint8(outputBytes, a55aString, 4); BC_ASSERT_NSTRING_EQUAL(outputBytes, a55aBytes, 2); bctbx_str_to_uint8(outputBytes, upString, 16); BC_ASSERT_NSTRING_EQUAL(outputBytes, upBytes, 8); bctbx_str_to_uint8(outputBytes, downString, 16); BC_ASSERT_NSTRING_EQUAL(outputBytes, downBytes, 8); bctbx_int8_to_str(outputString, a55aBytes, 2); BC_ASSERT_NSTRING_EQUAL(outputString, a55aString, 4); bctbx_int8_to_str(outputString, upBytes, 8); BC_ASSERT_NSTRING_EQUAL(outputString, upString, 16); bctbx_int8_to_str(outputString, downBytes, 8); BC_ASSERT_NSTRING_EQUAL(outputString, downString, 16); bctbx_uint32_to_str(outputString, 0x5aa5c376); BC_ASSERT_NSTRING_EQUAL(outputString, "5aa5c376", 8); bctbx_uint32_to_str(outputString, 0x01234567); BC_ASSERT_NSTRING_EQUAL(outputString, "01234567", 8); bctbx_uint32_to_str(outputString, 0xfedcba98); BC_ASSERT_NSTRING_EQUAL(outputString, "fedcba98", 8); BC_ASSERT_EQUAL(bctbx_str_to_uint32("5aa5c376"), 0x5aa5c376, uint32_t, "0x%08x"); BC_ASSERT_EQUAL(bctbx_str_to_uint32("01234567"), 0x01234567, uint32_t, "0x%08x"); BC_ASSERT_EQUAL(bctbx_str_to_uint32("fedcba98"), 0xfedcba98, uint32_t, "0x%08x"); bctbx_uint64_to_str(outputString, 0xfa5c37643cde8de0); BC_ASSERT_NSTRING_EQUAL(outputString, "fa5c37643cde8de0", 16); bctbx_uint64_to_str(outputString, 0x0123456789abcdef); BC_ASSERT_NSTRING_EQUAL(outputString, "0123456789abcdef", 16); bctbx_uint64_to_str(outputString, 0xfedcba9876543210); BC_ASSERT_NSTRING_EQUAL(outputString, "fedcba9876543210", 16); BC_ASSERT_EQUAL(bctbx_str_to_uint64("fa5c37643cde8de0"), 0xfa5c37643cde8de0, uint64_t, "0x%" PRIx64); BC_ASSERT_EQUAL(bctbx_str_to_uint64("0123456789abcdef"), 0x0123456789abcdef, uint64_t, "0x%" PRIx64); BC_ASSERT_EQUAL(bctbx_str_to_uint64("fedcba9876543210"), 0xfedcba9876543210, uint64_t, "0x%" PRIx64); } static void time_functions(void) { bctoolboxTimeSpec testTs; bctoolboxTimeSpec y2k,monday6Feb2017; y2k.tv_sec = 946684800; y2k.tv_nsec = 123456789; monday6Feb2017.tv_sec = 1486347823; monday6Feb2017.tv_nsec = 0; memcpy(&testTs, &y2k, sizeof(bctoolboxTimeSpec)); BC_ASSERT_EQUAL(bctbx_timespec_compare(&y2k, &testTs), 0, int, "%d"); bctbx_timespec_add(&testTs, 604800); BC_ASSERT_EQUAL(testTs.tv_sec, y2k.tv_sec+604800, int64_t, "%" PRIi64); BC_ASSERT_EQUAL(testTs.tv_nsec, y2k.tv_nsec, int64_t, "%" PRIi64); BC_ASSERT_TRUE(bctbx_timespec_compare(&y2k, &testTs)<0); memcpy(&testTs, &y2k, sizeof(bctoolboxTimeSpec)); bctbx_timespec_add(&testTs, -604800); BC_ASSERT_EQUAL(testTs.tv_sec, y2k.tv_sec-604800, int64_t, "%" PRIi64); BC_ASSERT_EQUAL(testTs.tv_nsec, y2k.tv_nsec, int64_t, "%" PRIi64); BC_ASSERT_TRUE(bctbx_timespec_compare(&y2k, &testTs)>0); memcpy(&testTs, &y2k, sizeof(bctoolboxTimeSpec)); bctbx_timespec_add(&testTs, -946684801); BC_ASSERT_EQUAL(testTs.tv_sec, 0, int64_t, "%" PRIi64); BC_ASSERT_EQUAL(testTs.tv_nsec, 0, int64_t, "%" PRIi64); /* test the get utc time function * there is no easy way to ensure we get the correct time, just check it is at least not the time from last boot, * check it is greater than the current time as this test was written(6feb2017) */ bctbx_get_utc_cur_time(&testTs); BC_ASSERT_TRUE(bctbx_timespec_compare(&testTs, &monday6Feb2017)>0); BC_ASSERT_EQUAL(bctbx_time_string_to_sec(NULL), 0, uint32_t, "%d"); BC_ASSERT_EQUAL(bctbx_time_string_to_sec(""), 0, uint32_t, "%d"); BC_ASSERT_EQUAL(bctbx_time_string_to_sec("0"), 0, uint32_t, "%d"); BC_ASSERT_EQUAL(bctbx_time_string_to_sec("1500"), 1500, uint32_t, "%d"); BC_ASSERT_EQUAL(bctbx_time_string_to_sec("2500s"), 2500, uint32_t, "%d"); BC_ASSERT_EQUAL(bctbx_time_string_to_sec("10m"), 600, uint32_t, "%d"); BC_ASSERT_EQUAL(bctbx_time_string_to_sec("5h"), 5*3600, uint32_t, "%d"); BC_ASSERT_EQUAL(bctbx_time_string_to_sec("2d"), 2*24*3600, uint32_t, "%d"); BC_ASSERT_EQUAL(bctbx_time_string_to_sec("3W"), 3*7*24*3600, uint32_t, "%d"); BC_ASSERT_EQUAL(bctbx_time_string_to_sec("6M"), 6*30*24*3600, uint32_t, "%d"); BC_ASSERT_EQUAL(bctbx_time_string_to_sec("7Y"), 7*365*24*3600, uint32_t, "%d"); BC_ASSERT_EQUAL(bctbx_time_string_to_sec("7Y6M2W"), (7*365+6*30+2*7)*24*3600, uint32_t, "%d"); BC_ASSERT_EQUAL(bctbx_time_string_to_sec("2m30"), 2*60+30, uint32_t, "%d"); BC_ASSERT_EQUAL(bctbx_time_string_to_sec("15d1M"), (15+1*30)*24*3600, uint32_t, "%d"); BC_ASSERT_EQUAL(bctbx_time_string_to_sec("15d5z"), 15*24*3600, uint32_t, "%d"); BC_ASSERT_EQUAL(bctbx_time_string_to_sec("15dM12h"), (15*24+12)*3600, uint32_t, "%d"); } static test_t utils_tests[] = { TEST_NO_TAG("Bytes to/from Hexa strings", bytes_to_from_hexa_strings), TEST_NO_TAG("Time", time_functions) }; test_suite_t utils_test_suite = {"Utils", NULL, NULL, NULL, NULL, sizeof(utils_tests) / sizeof(utils_tests[0]), utils_tests};