pax_global_header00006660000000000000000000000064137571730710014525gustar00rootroot0000000000000052 comment=50c26d8b586b53c00fc36fe89d071fddb2437c80 bctoolbox-4.4.13/000077500000000000000000000000001375717307100136115ustar00rootroot00000000000000bctoolbox-4.4.13/.gitignore000066400000000000000000000000171375717307100155770ustar00rootroot00000000000000bctoolbox.spec bctoolbox-4.4.13/CHANGELOG.md000066400000000000000000000020631375717307100154230ustar00rootroot00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ## [4.4.0] - 2020-6-09 ### Changed - Version number now follows linphone-sdk's versionning. ### Removed - Polarssl 1.2 support. ## [0.6.0] - 2017-07-20 ### Added - Add API to escape/unescape strings (SIP, VCARD). ## [0.5.1] - 2017-02-22 ### Added - "const char * to void *" map feature ### Fixed - security bugfix: TLS session could be successfully established whereas the common name did not match the server name. ## [0.2.0] - 2016-08-08 ### Added - 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. ## [0.0.1] - 2016-01-01 ### Added - Initial release. ### Changed ### Removed bctoolbox-4.4.13/CMakeLists.txt000066400000000000000000000157241375717307100163620ustar00rootroot00000000000000############################################################################ # CMakeLists.txt # Copyright (C) 2010-2019 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################################################ cmake_minimum_required(VERSION 3.2) 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 VERSION 4.4.0) set(BCTOOLBOX_VERSION "${PROJECT_VERSION}") set(BCTOOLBOX_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) set(BCTOOLBOX_VERSION_MINOR ${PROJECT_VERSION_MINOR}) set(BCTOOLBOX_VERSION_PATCH ${PROJECT_VERSION_PATCH}) set(BCTOOLBOX_SO_VERSION 1) set(BCTOOLBOXTESTER_SO_VERSION 1) 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_DECAF "Enable Elliptic Curve Cryptography 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) option(ENABLE_PACKAGE_SOURCE "Create 'package_source' target for source archive making (CMake >= 3.11)" OFF) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_EXTENSIONS NO) include(CheckLibraryExists) include(CheckSymbolExists) include(CheckCSourceCompiles) include(CMakePushCheckState) include(GNUInstallDirs) include(cmake/BcToolboxCMakeUtils.cmake) 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(APPLE) find_package(Iconv REQUIRED) endif() if(ENABLE_MBEDTLS) find_package(MbedTLS) if(MBEDTLS_FOUND) message(STATUS "Using mbedTLS") set(HAVE_MBEDTLS 1) endif() endif() if(ENABLE_DECAF) find_package(Decaf CONFIG) if(DECAF_FOUND) message(STATUS "Using Decaf") set(HAVE_DECAF 1) endif() endif() if(ENABLE_POLARSSL AND NOT MBEDTLS_FOUND) find_package(PolarSSL REQUIRED) if(POLARSSL_FOUND) message(STATUS "Using polarSSL") set(HAVE_POLARSSL 1) 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 CONFIG 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) 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() bc_init_compilation_flags(STRICT_OPTIONS_CPP STRICT_OPTIONS_C STRICT_OPTIONS_CXX ENABLE_STRICT) if(CMAKE_VERSION VERSION_LESS 3.1 AND NOT APPLE AND NOT MSVC) list(APPEND STRICT_OPTIONS_CXX "-std=c++11") endif() set(EXPORT_TARGETS_NAME "bctoolbox") check_library_exists("rt" "clock_gettime" "" HAVE_LIBRT) check_library_exists("dl" "dladdr" "" HAVE_LIBDL) check_include_file("execinfo.h" HAVE_EXECINFO) 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") add_subdirectory(include) add_subdirectory(src) if(ENABLE_TESTS AND ENABLE_TESTS_COMPONENT) add_subdirectory(tester) endif() if(ENABLE_PACKAGE_SOURCE) add_subdirectory(build) endif() include(CMakePackageConfigHelpers) set(CONFIG_PACKAGE_LOCATION "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/cmake") write_basic_package_version_file( "${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_TARGETS_NAME}ConfigVersion.cmake" VERSION ${PROJECT_VERSION} COMPATIBILITY AnyNewerVersion ) configure_package_config_file(cmake/BcToolboxConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_TARGETS_NAME}Config.cmake" INSTALL_DESTINATION ${CONFIG_PACKAGE_LOCATION} NO_SET_AND_CHECK_MACRO ) configure_file(cmake/BcToolboxCMakeUtils.cmake "${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_TARGETS_NAME}CMakeUtils.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) install(EXPORT ${EXPORT_TARGETS_NAME}Targets FILE "${EXPORT_TARGETS_NAME}Targets.cmake" DESTINATION ${CONFIG_PACKAGE_LOCATION} ) install(FILES "cmake/MakeArchive.cmake" "cmake/ConfigureSpecfile.cmake" "${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_TARGETS_NAME}Config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_TARGETS_NAME}ConfigVersion.cmake" "${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_TARGETS_NAME}CMakeUtils.cmake" "${CMAKE_CURRENT_BINARY_DIR}/BcGitVersion.cmake" "${CMAKE_CURRENT_BINARY_DIR}/gitversion.h.in" DESTINATION ${CONFIG_PACKAGE_LOCATION} ) bctoolbox-4.4.13/LICENSE.txt000066400000000000000000000773311375717307100154470ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. 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 them 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 prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. 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. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey 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; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU 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 that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. 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. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 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. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS bctoolbox-4.4.13/README.md000066400000000000000000000040051375717307100150670ustar00rootroot00000000000000[![pipeline status](https://gitlab.linphone.org/BC/public/bctoolbox/badges/master/pipeline.svg)](https://gitlab.linphone.org/BC/public/bctoolbox/commits/master) BcToolbox ========= Utilities library used by Belledonne Communications softwares like belle-sip, mediastreamer2 and liblinphone. 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-4.4.13/bctoolbox-tester.pc.in000066400000000000000000000005601375717307100200420ustar00rootroot00000000000000# 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-4.4.13/bctoolbox.pc.in000066400000000000000000000005111375717307100165320ustar00rootroot00000000000000# 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-4.4.13/build/000077500000000000000000000000001375717307100147105ustar00rootroot00000000000000bctoolbox-4.4.13/build/CMakeLists.txt000066400000000000000000000030021375717307100174430ustar00rootroot00000000000000############################################################################ # CMakeLists.txt # Copyright (C) 2010-2019 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################################################ cmake_minimum_required(VERSION 3.11) # we need CMake 3.11 for defining 'package_source' target as custom target set(BCTOOLBOX_CMAKE_DIR "${PROJECT_SOURCE_DIR}/cmake") set(BCTOOLBOX_CMAKE_UTILS "${BCTOOLBOX_CMAKE_DIR}/BcToolboxCMakeUtils.cmake") include("${BCTOOLBOX_CMAKE_DIR}/BcToolboxCMakeUtils.cmake") if(NOT CPACK_PACKAGE_NAME) set(CPACK_PACKAGE_NAME "${PROJECT_NAME}") endif() set(CPACK_SOURCE_IGNORE_FILES "^${CMAKE_BINARY_DIR}" "^${PROJECT_SOURCE_DIR}/.git*" ) bc_make_package_source_target() bctoolbox-4.4.13/build/android/000077500000000000000000000000001375717307100163305ustar00rootroot00000000000000bctoolbox-4.4.13/build/android/Android-mbedtls.mk000066400000000000000000000006021375717307100216670ustar00rootroot00000000000000 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-4.4.13/build/android/Android-polarssl.mk000066400000000000000000000006051375717307100220770ustar00rootroot00000000000000 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-4.4.13/build/android/Android-tester.mk000066400000000000000000000006241375717307100215470ustar00rootroot00000000000000LOCAL_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-4.4.13/build/osx/000077500000000000000000000000001375717307100155215ustar00rootroot00000000000000bctoolbox-4.4.13/build/osx/Info.plist.in000066400000000000000000000026111375717307100200760ustar00rootroot00000000000000 CFBundleDevelopmentRegion English CFBundleExecutable ${MACOSX_FRAMEWORK_NAME} 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-4.4.13/build/rpm/000077500000000000000000000000001375717307100155065ustar00rootroot00000000000000bctoolbox-4.4.13/build/rpm/bctoolbox.spec.cmake000077500000000000000000000055231375717307100214440ustar00rootroot00000000000000# -*- rpm-spec -*- %define _prefix @CMAKE_INSTALL_PREFIX@ %define pkg_prefix @BC_PACKAGE_NAME_PREFIX@ %define package_name @CPACK_PACKAGE_NAME@-${FULL_VERSION} # re-define some directories for older RPMBuild versions which don't. This messes up the doc/ dir # taken from https://fedoraproject.org/wiki/Packaging:RPMMacros?rd=Packaging/RPMMacros %define _datarootdir %{_prefix}/share %define _datadir %{_datarootdir} %define _docdir %{_datadir}/doc Name: @CPACK_PACKAGE_NAME@ Version: ${RPM_VERSION} Release: ${RPM_RELEASE}%{?dist} Summary: OS abstraction layer and utilities Group: Applications/Communications License: GPL URL: http://www.linphone.org Source0: %{package_name}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot Requires: %{pkg_prefix}bctoolbox %description Toolbox package used by Belledonne Communications projects %package devel Summary: Development libraries for bctoolbox Group: Development/Libraries Requires: %{name} = %{version}-%{release} %description devel Libraries and headers required to develop software with bctoolbox %if 0%{?rhel} && 0%{?rhel} <= 7 %global cmake_name cmake3 %define ctest_name ctest3 %else %global cmake_name cmake %define ctest_name ctest %endif # This is for debian builds where debug_package has to be manually specified, whereas in centos it does not %define custom_debug_package %{!?_enable_debug_packages:%debug_package}%{?_enable_debug_package:%{nil}} %custom_debug_package %prep %setup -n %{package_name} %build %{expand:%%%cmake_name} . -DCMAKE_BUILD_TYPE=@CMAKE_BUILD_TYPE@ -DCMAKE_PREFIX_PATH:PATH=%{_prefix} @RPM_ALL_CMAKE_OPTIONS@ make %{?_smp_mflags} %install make install DESTDIR=%{buildroot} # Dirty workaround to give exec rights for all shared libraries. Debian packaging needs this # TODO : set CMAKE_INSTALL_SO_NO_EXE for a cleaner workaround chmod +x `find %{buildroot} *.so.*` %check %{ctest_name} -V %{?_smp_mflags} %clean rm -rf $RPM_BUILD_ROOT %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %files %defattr(-,root,root) %doc LICENSE.txt CHANGELOG.md README.md %{_libdir}/*.so.* %files devel %defattr(-,root,root) %{_includedir}/bctoolbox %if @ENABLE_STATIC@ %{_libdir}/libbctoolbox.a %endif %if @ENABLE_SHARED@ %{_libdir}/libbctoolbox.so %endif %{_libdir}/pkgconfig/bctoolbox.pc %{_datadir}/bctoolbox/cmake/* %if @ENABLE_TESTS_COMPONENT@ %if @ENABLE_STATIC@ %{_libdir}/libbctoolbox-tester.a %endif %if @ENABLE_SHARED@ %{_libdir}/libbctoolbox-tester.so %endif %{_libdir}/pkgconfig/bctoolbox-tester.pc %endif %changelog * Tue Nov 27 2018 ronan.abhamon - Do not set CMAKE_INSTALL_LIBDIR and never with _libdir! * Tue Jan 16 2018 Ghislain MARY - Initial RPM release. bctoolbox-4.4.13/cmake/000077500000000000000000000000001375717307100146715ustar00rootroot00000000000000bctoolbox-4.4.13/cmake/BcGitVersion.cmake000066400000000000000000000041761375717307100202410ustar00rootroot00000000000000############################################################################ # 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-4.4.13/cmake/BcToolboxCMakeUtils.cmake000066400000000000000000000240731375717307100215160ustar00rootroot00000000000000############################################################################ # BcToolboxCMakeUtils.cmake # Copyright (C) 2010-2019 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_init_compilation_flags CPP_FLAGS C_FLAGS CXX_FLAGS STRICT_COMPILATION) set(${CPP_FLAGS} ) set(${C_FLAGS} ) set(${CXX_FLAGS} ) if(MSVC) if(${STRICT_COMPILATION}) list(APPEND ${CPP_FLAGS} "/WX") list(APPEND STRICT_OPTIONS_CPP "/wd4996") # Disable deprecated function warnings endif() else() list(APPEND ${CPP_FLAGS} "-Wall" "-Wuninitialized") if(CMAKE_C_COMPILER_ID MATCHES "Clang") list(APPEND ${CPP_FLAGS} "-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 ${CPP_FLAGS} "-Wno-error=pragmas") endif() if(APPLE) list(APPEND ${CPP_FLAGS} "-Wno-error=unknown-warning-option" "-Qunused-arguments" "-Wno-tautological-compare" "-Wno-unused-function" "-Wno-array-bounds") endif() if(ENABLE_STRICT) list(APPEND ${CPP_FLAGS} "-Werror" "-Wextra" "-Wno-unused-parameter" "-Wno-error=unknown-pragmas" "-Wuninitialized" "-Wno-missing-field-initializers" "-fno-strict-aliasing" "-Wno-error=deprecated" "-Wno-error=deprecated-declarations") list(APPEND ${C_FLAGS} "-Werror" "-Wstrict-prototypes") endif() endif() endmacro() 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() # TODO remove this macro macro(bc_project_build_version PROJECT_VERSION PROJECT_BUILD_VERSION) find_program (WC wc) if(WC) set(GIT_MINIMUM_VERSION 1.7.1) #might be even lower else() set(GIT_MINIMUM_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_MINIMUM_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 ${CMAKE_CURRENT_SOURCE_DIR} ) endif() if (NOT PROJECT_VERSION_BUILD) set(PROJECT_VERSION_BUILD 0) endif() endmacro() macro(bc_generate_rpm_specfile SOURCE DEST) if(UNIX AND NOT APPLE AND NOT ANDROID) set(BC_PACKAGE_NAME_PREFIX "" CACHE STRING "Prefix for name of package.") get_cmake_property(_variableNames VARIABLES) set(RPM_ALL_CMAKE_OPTIONS "") foreach(_variableName ${_variableNames}) if(_variableName MATCHES "^ENABLE_") if(${_variableName}) set(${_variableName} 1) else() set(${_variableName} 0) endif() set(RPM_ALL_CMAKE_OPTIONS "${RPM_ALL_CMAKE_OPTIONS} -D${_variableName}=${${_variableName}}") endif() endforeach() configure_file(${SOURCE} ${DEST} @ONLY) unset(RPM_ALL_CMAKE_OPTIONS) unset(_variableNames) endif() endmacro() function(bc_parse_full_version version major minor patch) if ("${version}" MATCHES "^(0|[1-9][0-9]*)[.](0|[1-9][0-9]*)[.](0|[1-9][0-9]*)(-[.0-9A-Za-z-]+)?([+][.0-9A-Za-z-]+)?$") set(${major} "${CMAKE_MATCH_1}" PARENT_SCOPE) set(${minor} "${CMAKE_MATCH_2}" PARENT_SCOPE) set(${patch} "${CMAKE_MATCH_3}" PARENT_SCOPE) if (ARGC GREATER 4) set(${ARGV4} "${CMAKE_MATCH_4}" PARENT_SCOPE) endif() if (ARGC GREATER 5) set(${ARGV5} "${CMAKE_MATCH_5}" PARENT_SCOPE) endif() else() message(FATAL_ERROR "invalid full version '${version}'") endif() endfunction() function(bc_compute_lib_version OUTPUT_VERSION default_version) find_program(GIT_EXECUTABLE git NAMES Git CMAKE_FIND_ROOT_PATH_BOTH) if(GIT_EXECUTABLE) execute_process( COMMAND "${GIT_EXECUTABLE}" "describe" OUTPUT_VARIABLE GIT_DESCRIBE_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" ) # parse git describe version if (NOT (GIT_DESCRIBE_VERSION MATCHES "^([0-9]+)[.]([0-9]+)[.]([0-9]+)(-alpha|-beta)?(-[0-9]+)?(-g[0-9a-f]+)?$")) message(FATAL_ERROR "invalid git describe version: '${GIT_DESCRIBE_VERSION}'") endif() set(version_major ${CMAKE_MATCH_1}) set(version_minor ${CMAKE_MATCH_2}) set(version_patch ${CMAKE_MATCH_3}) # format lib version set(${OUTPUT_VERSION} "${version_major}.${version_minor}.${version_patch}" CACHE STRING "") else() set(${OUTPUT_VERSION} "${default_version}" CACHE STRING "") endif() endfunction() function(bc_compute_full_version OUTPUT_VERSION) find_program(GIT_EXECUTABLE git NAMES Git CMAKE_FIND_ROOT_PATH_BOTH) if(GIT_EXECUTABLE) execute_process( COMMAND "${GIT_EXECUTABLE}" "describe" OUTPUT_VARIABLE GIT_DESCRIBE_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" ) # parse git describe version if (NOT (GIT_DESCRIBE_VERSION MATCHES "^([0-9]+)[.]([0-9]+)[.]([0-9]+)(-alpha|-beta)?(-[0-9]+)?(-g[0-9a-f]+)?$")) message(FATAL_ERROR "invalid git describe version: '${GIT_DESCRIBE_VERSION}'") endif() set(version_major ${CMAKE_MATCH_1}) set(version_minor ${CMAKE_MATCH_2}) set(version_patch ${CMAKE_MATCH_3}) if (CMAKE_MATCH_4) string(SUBSTRING "${CMAKE_MATCH_4}" 1 -1 version_prerelease) endif() if (CMAKE_MATCH_5) string(SUBSTRING "${CMAKE_MATCH_5}" 1 -1 version_commit) endif() if (CMAKE_MATCH_6) string(SUBSTRING "${CMAKE_MATCH_6}" 2 -1 version_hash) endif() # interpret untagged hotfixes as pre-releases of the next "patch" release if (NOT version_prerelease AND version_commit) math(EXPR version_patch "${version_patch} + 1") set(version_prerelease "pre") endif() # format full version set(full_version "${version_major}.${version_minor}.${version_patch}") if (version_prerelease) string(APPEND full_version "-${version_prerelease}") if (version_commit) string(APPEND full_version ".${version_commit}+${version_hash}") endif() endif() # check that the major and minor versions declared by the `project()` command are equal to the ones # that have been found out while parsing `git describe` result. if (PROJECT_VERSION) set(short_git_version "${version_major}.${version_minor}") set(short_project_version "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}") if(NOT (short_project_version VERSION_EQUAL short_git_version)) message(FATAL_ERROR "project and git version are not compatible (project: '${PROJECT_VERSION}', git: '${full_version}'): " "major and minor version are not equal !" ) endif() endif() set(${OUTPUT_VERSION} "${full_version}" CACHE STRING "") endif() endfunction() function(bc_make_package_source_target) set(basename "") string(TOLOWER "${CMAKE_PROJECT_NAME}" basename) if (DEFINED BC_SPECFILE_NAME) set(specfile_name "${BC_SPECFILE_NAME}") else() set(specfile_name "${basename}.spec") endif() set(specfile_target "${basename}-rpm-spec") bc_generate_rpm_specfile("rpm/${specfile_name}.cmake" "rpm/${specfile_name}.cmake") add_custom_target(${specfile_target} COMMAND ${CMAKE_COMMAND} "-DPROJECT_VERSION=${PROJECT_VERSION}" "-DPROJECT_VERSION_MAJOR=${PROJECT_VERSION_MAJOR}" "-DPROJECT_VERSION_MINOR=${PROJECT_VERSION_MINOR}" "-DBCTOOLBOX_CMAKE_UTILS=${BCTOOLBOX_CMAKE_UTILS}" "-DSRC=${CMAKE_CURRENT_BINARY_DIR}/rpm/${specfile_name}.cmake" "-DDEST=${PROJECT_SOURCE_DIR}/${specfile_name}" -P "${BCTOOLBOX_CMAKE_DIR}/ConfigureSpecfile.cmake" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} BYPRODUCTS "${PROJECT_SOURCE_DIR}/${specfile_name}" ) add_custom_target(package_source COMMAND ${CMAKE_COMMAND} "-DBCTOOLBOX_CMAKE_UTILS=${BCTOOLBOX_CMAKE_UTILS}" "-DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR}" "-DPROJECT_BINARY_DIR=${PROJECT_BINARY_DIR}" "-DPROJECT_VERSION=${PROJECT_VERSION}" "-DPROJECT_VERSION_MAJOR=${PROJECT_VERSION_MAJOR}" "-DPROJECT_VERSION_MINOR=${PROJECT_VERSION_MINOR}" "-DCPACK_PACKAGE_NAME=${CPACK_PACKAGE_NAME}" "-DEXCLUDE_PATTERNS='${CPACK_SOURCE_IGNORE_FILES}'" -P "${BCTOOLBOX_CMAKE_DIR}/MakeArchive.cmake" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" DEPENDS ${specfile_target} ) endfunction() bctoolbox-4.4.13/cmake/BcToolboxConfig.cmake.in000066400000000000000000000073701375717307100213300ustar00rootroot00000000000000############################################################################ # BcToolboxConfig.cmake # Copyright (C) 2010-2019 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 @PACKAGE_INIT@ include("${CMAKE_CURRENT_LIST_DIR}/bctoolboxTargets.cmake") list(APPEND bctoolbox_FIND_COMPONENTS core) if (ENABLE_TESTS_COMPONENT) list(APPEND bctoolbox_FIND_COMPONENTS tester) endif() 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() if(NOT BCTOOLBOX_${uppercomp}_LIBRARIES) set(BCTOOLBOX_${uppercomp}_LIBRARIES) 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(NOT BCTOOLBOX_${uppercomp}_INCLUDE_DIRS) set(BCTOOLBOX_${uppercomp}_INCLUDE_DIRS) endif() 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() set(BCTOOLBOX_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}") set(BCTOOLBOX_CMAKE_UTILS "${CMAKE_CURRENT_LIST_DIR}/bctoolboxCMakeUtils.cmake") include("${BCTOOLBOX_CMAKE_UTILS}") bctoolbox-4.4.13/cmake/ConfigureSpecfile.cmake000066400000000000000000000030731375717307100212720ustar00rootroot00000000000000############################################################################ # ConfigureSpecfile.cmake # Copyright (C) 2010-2019 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################################################ include("${BCTOOLBOX_CMAKE_UTILS}") set(FULL_VERSION ) bc_compute_full_version(FULL_VERSION) set(version_major ) set(version_minor ) set(version_patch ) set(identifiers ) set(metadata ) bc_parse_full_version("${FULL_VERSION}" version_major version_minor version_patch identifiers metadata) set(RPM_VERSION ${version_major}.${version_minor}.${version_patch}) if (NOT identifiers) set(RPM_RELEASE 1) else() string(SUBSTRING "${identifiers}" 1 -1 identifiers) set(RPM_RELEASE "0.${identifiers}${metadata}") endif() configure_file("${SRC}" "${DEST}") bctoolbox-4.4.13/cmake/FindDecaf.cmake000066400000000000000000000031041375717307100174740ustar00rootroot00000000000000############################################################################ # FindDecaf.txt # 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. # ############################################################################ # # - Find the decaf include files and library # # DECAF_FOUND - system has lib decaf # DECAF_INCLUDE_DIRS - the decaf include directory # DECAF_LIBRARY - The library needed to use decaf include(CMakePushCheckState) include(CheckIncludeFile) find_path(DECAF_INCLUDE_DIRS NAMES decaf.h PATH_SUFFIXES include/decaf ) # find the three mbedtls library find_library(DECAF_LIBRARY NAMES decaf ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Decaf DEFAULT_MSG DECAF_INCLUDE_DIRS DECAF_LIBRARY ) mark_as_advanced(DECAF_INCLUDE_DIRS DECAF_LIBRARY) bctoolbox-4.4.13/cmake/FindIconv.cmake000066400000000000000000000034311375717307100175530ustar00rootroot00000000000000############################################################################ # FindIconv.cmake # Copyright (C) 2014 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################################################ # # - Find the iconv include file and library # # ICONV_FOUND - system has libiconv # ICONV_INCLUDE_DIRS - the libiconv include directory # ICONV_LIBRARIES - The libraries needed to use libiconv if(APPLE AND NOT IOS) set(ICONV_HINTS "${CMAKE_OSX_SYSROOT}/usr" "/usr") endif() if(ICONV_HINTS) set(ICONV_LIBRARIES_HINTS "${ICONV_HINTS}/lib") endif() find_path(ICONV_INCLUDE_DIRS NAMES iconv.h HINTS "${ICONV_HINTS}" PATH_SUFFIXES include ) if(ICONV_INCLUDE_DIRS) set(HAVE_ICONV_H 1) endif() find_library(ICONV_LIBRARIES NAMES iconv HINTS "${ICONV_LIBRARIES_HINTS}" ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Iconv DEFAULT_MSG ICONV_INCLUDE_DIRS ICONV_LIBRARIES HAVE_ICONV_H ) mark_as_advanced(ICONV_INCLUDE_DIRS ICONV_LIBRARIES HAVE_ICONV_H) bctoolbox-4.4.13/cmake/FindMbedTLS.cmake000066400000000000000000000054341375717307100177340ustar00rootroot00000000000000############################################################################ # 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 ) cmake_push_check_state(RESET) set(CMAKE_REQUIRED_INCLUDES ${MBEDTLS_INCLUDE_DIRS} ${CMAKE_REQUIRED_INCLUDES_${BUILD_TYPE}}) list(APPEND CMAKE_REQUIRED_LIBRARIES ${MBEDTLS_LIBRARY} ${MBEDX509_LIBRARY} ${MBEDCRYPTO_LIBRARY}) # check we have a mbedTLS version 2 or above(all functions are prefixed mbedtls_) if(MBEDTLS_LIBRARY AND MBEDX509_LIBRARY AND MBEDCRYPTO_LIBRARY) check_symbol_exists(mbedtls_ssl_init "mbedtls/ssl.h" MBEDTLS_V2) if(MBEDTLS_V2) set (MBEDTLS_LIBRARIES ${MBEDTLS_LIBRARY} ${MBEDX509_LIBRARY} ${MBEDCRYPTO_LIBRARY} ) else() message ("MESSAGE: NO MBEDTLS_V2") message ("MESSAGE: MBEDTLS_LIBRARY=" ${MBEDTLS_LIBRARY}) message ("MESSAGE: MBEDX509_LIBRARY=" ${MBEDX509_LIBRARY}) message ("MESSAGE: MBEDCRYPTO_LIBRARY=" ${MBEDCRYPTO_LIBRARY}) endif() endif() if(MBEDTLS_LIBRARIES) check_symbol_exists(mbedtls_ssl_get_dtls_srtp_protection_profile "mbedtls/ssl.h" HAVE_SSL_GET_DTLS_SRTP_PROTECTION_PROFILE) endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(MbedTLS DEFAULT_MSG MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARIES ) cmake_pop_check_state() mark_as_advanced(MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARIES HAVE_SSL_GET_DTLS_SRTP_PROTECTION_PROFILE) bctoolbox-4.4.13/cmake/FindPolarSSL.cmake000066400000000000000000000045111375717307100201340ustar00rootroot00000000000000############################################################################ # 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_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-4.4.13/cmake/MakeArchive.cmake000066400000000000000000000027441375717307100200610ustar00rootroot00000000000000############################################################################ # MakeArchive.cmake # Copyright (C) 2010-2019 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################################################ include("${BCTOOLBOX_CMAKE_UTILS}") bc_compute_full_version(version) set(archive_name "${CPACK_PACKAGE_NAME}-${version}") set(archive_path "${PROJECT_BINARY_DIR}/${archive_name}.tar.gz") find_program(TAR tar) set(EXCLUDE_ARGS ) foreach (pattern ${EXCLUDE_PATTERNS}) list(APPEND EXCLUDE_ARGS "--exclude=${pattern}") endforeach() execute_process(COMMAND ${TAR} -C "${PROJECT_SOURCE_DIR}" -cz -f "${archive_path}" "--transform" "s,^\\.,${archive_name}," ${EXCLUDE_ARGS} .) bctoolbox-4.4.13/cmake/gitversion.h.in000066400000000000000000000014641375717307100176450ustar00rootroot00000000000000/* 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-4.4.13/config.h.cmake000066400000000000000000000025201375717307100163050ustar00rootroot00000000000000/*************************************************************************** * 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_DECAF 1 #cmakedefine HAVE_MBEDTLS 1 #cmakedefine HAVE_POLARSSL 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 #cmakedefine HAVE_EXECINFO bctoolbox-4.4.13/include/000077500000000000000000000000001375717307100152345ustar00rootroot00000000000000bctoolbox-4.4.13/include/CMakeLists.txt000066400000000000000000000033441375717307100200000ustar00rootroot00000000000000############################################################################ # 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 charconv.h compiler.h defs.h exception.hh list.h logging.h map.h parser.h port.h regex.h vconnect.h vfs.h ) if(APPLE) list(APPEND HEADER_FILES ios_utils.hh) endif() if(MBEDTLS_FOUND OR POLARSSL_FOUND) list(APPEND HEADER_FILES crypto.h) endif() if(ENABLE_TESTS_COMPONENT) list(APPEND HEADER_FILES tester.h) 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-4.4.13/include/bctoolbox/000077500000000000000000000000001375717307100172275ustar00rootroot00000000000000bctoolbox-4.4.13/include/bctoolbox/charconv.h000066400000000000000000000047041375717307100212100ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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_CHARCONV_H #define BCTBX_CHARCONV_H #include "bctoolbox/port.h" #ifdef __cplusplus extern "C" { #endif /** * @brief Set the default encoding for the application. * * @param[in] encoding default encoding, "locale" to set it to the system's locale */ BCTBX_PUBLIC void bctbx_set_default_encoding (const char *encoding); /** * @brief Return the default encoding for the application. * * @return a pointer to a null-terminated string containing the default encoding. */ BCTBX_PUBLIC const char *bctbx_get_default_encoding (); /** * @brief Convert the given string from system locale to UTF8. * * @param[in] str string to convert * * @return a pointer to a null-terminated string containing the converted string. This buffer must then be freed * by caller. NULL on failure. */ BCTBX_PUBLIC char *bctbx_locale_to_utf8 (const char *str); /** * @brief Convert the given string from UTF8 to system locale. * * @param[in] str string to convert * * @return a pointer to a null-terminated string containing the converted string. This buffer must then be freed * by caller. NULL on failure. */ BCTBX_PUBLIC char *bctbx_utf8_to_locale (const char *str); /** * @brief Convert the given string. * * @param[in] str string to convert * @param[in] encoding charset of the string * * @return a pointer to a null-terminated string containing the converted string. This buffer must then be freed * by caller. NULL on failure. * * @note If encoding is equal to "locale" then it will use the system's locale * @note If encoding is UTF-8 then it returns a copy of str */ BCTBX_PUBLIC char *bctbx_convert_any_to_utf8 (const char *str, const char *encoding); #ifdef __cplusplus } #endif #endif /* BCTBX_CHARCONV_H */ bctoolbox-4.4.13/include/bctoolbox/compiler.h000066400000000000000000000031311375717307100212100ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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 COMPILER_H #define COMPILER_H #ifdef __has_feature #if __has_feature(address_sanitizer) #define BCTBX_ASAN_ENABLED #endif // if __has_feature(address_sanitizer) #elif defined(__SANITIZE_ADDRESS__) #define BCTBX_ASAN_ENABLED #endif // ifdef __has_feature #ifdef BCTBX_ASAN_ENABLED #define BCTBX_DISABLE_ASAN __attribute__((no_sanitize_address)) #else #define BCTBX_DISABLE_ASAN #endif // ifdef BCTBX_ASAN_ENABLED #ifdef __has_attribute #if __has_attribute(no_sanitize) #define BCTBX_DISABLE_UBSAN __attribute__((no_sanitize("undefined"))) #else #define BCTBX_DISABLE_UBSAN #endif // __has_attribute(no_sanitize) #elif defined(__GNUC__) && !defined(__MINGW32__) && GCC_VERSION >= 40900 #define BCTBX_DISABLE_UBSAN __attribute__((no_sanitize_undefined)) #else #define BCTBX_DISABLE_UBSAN #endif // ifdef __has_attribute #endif // ifdef COMPILER_H bctoolbox-4.4.13/include/bctoolbox/crypto.h000066400000000000000000001507301375717307100207260ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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_CRYPTO_H #define BCTBX_CRYPTO_H #include "bctoolbox/port.h" #include "bctoolbox/list.h" /* key agreements settings defines */ /* Each algo is defined as a bit toggled in a 32 bits integer, * so we can easily ask for all availables ones */ #define BCTBX_DHM_UNSET 0x00000000 #define BCTBX_DHM_2048 0x00000001 #define BCTBX_DHM_3072 0x00000002 #define BCTBX_ECDH_X25519 0x00000004 #define BCTBX_ECDH_X448 0x00000008 /* EdDSA defines */ #define BCTBX_EDDSA_UNSET 0 #define BCTBX_EDDSA_25519 1 #define BCTBX_EDDSA_448 2 #define BCTBX_VERIFY_SUCCESS 0 #define BCTBX_VERIFY_FAILED -1 /* Elliptic Curves Key lengths defines: theses are redefines of the values defined in decaf headers made available to bctoolbox library users bctoolbox will fail to compile if these values are not in sync with the decaf ones */ #define BCTBX_ECDH_X25519_PUBLIC_SIZE 32 #define BCTBX_ECDH_X25519_PRIVATE_SIZE BCTBX_ECDH_X25519_PUBLIC_SIZE #define BCTBX_ECDH_X448_PUBLIC_SIZE 56 #define BCTBX_ECDH_X448_PRIVATE_SIZE BCTBX_ECDH_X448_PUBLIC_SIZE #define BCTBX_EDDSA_25519_PUBLIC_SIZE 32 #define BCTBX_EDDSA_25519_PRIVATE_SIZE BCTBX_EDDSA_25519_PUBLIC_SIZE #define BCTBX_EDDSA_25519_SIGNATURE_SIZE (BCTBX_EDDSA_25519_PUBLIC_SIZE + BCTBX_EDDSA_25519_PRIVATE_SIZE) #define BCTBX_EDDSA_448_PUBLIC_SIZE 57 #define BCTBX_EDDSA_448_PRIVATE_SIZE BCTBX_EDDSA_448_PUBLIC_SIZE #define BCTBX_EDDSA_448_SIGNATURE_SIZE (BCTBX_EDDSA_448_PUBLIC_SIZE + BCTBX_EDDSA_448_PRIVATE_SIZE) /* 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; typedef enum bctbx_type_implementation { BCTBX_POLARSSL, BCTBX_POLARSSL1_2, BCTBX_MBEDTLS } bctbx_type_implementation_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(const bctbx_x509_certificate_t *cert, char *dn, size_t dn_length); /** * @brief Obtain the certificate subjects (all subjectAltName URIS and DNS + subject CN) * * @param[in] cert The x509 certificate * @return a list of allocated strings (char*), to be freed with bctbx_free() */ BCTBX_PUBLIC bctbx_list_t *bctbx_x509_certificate_get_subjects(const bctbx_x509_certificate_t *cert); /** * @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_type_implementation_t bctbx_ssl_get_implementation_type(void); 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 int bctbx_ssl_get_ciphersuite_id(const char* ciphersuite); 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 void *bctbx_ssl_config_get_private_config(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); BCTBX_PUBLIC int32_t bctbx_ssl_config_set_ciphersuites(bctbx_ssl_config_t *ssl_config,const int *ciphersuites); /***** 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); BCTBX_PUBLIC void bctbx_ssl_set_mtu(bctbx_ssl_context_t *ssl_ctx, uint16_t mtu); /*****************************************************************************/ /***** Key exchanges defined algorithms *****/ /*****************************************************************************/ /** * @brief Return a 32 bits unsigned integer, each bit set to one matches an * available key agreement algorithm as defined in bctoolbox/include/crypto.h * * @return An unsigned integer of 32 flags matching key agreement algos */ BCTBX_PUBLIC uint32_t bctbx_key_agreement_algo_list(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); /*****************************************************************************/ /***** Elliptic Curve Diffie-Hellman-Merkle key exchange *****/ /*****************************************************************************/ /** * * @brief return TRUE if the Elliptic Curve Cryptography is available */ BCTBX_PUBLIC int bctbx_crypto_have_ecc(void); /** * @brief Context for the EC Diffie-Hellman-Merkle key exchange on curve 25519 and 448 * Use RFC7748 for base points values */ typedef struct bctbx_ECDHContext_struct { uint8_t algo; /**< Algorithm used for the key exchange mapped to an int: BCTBX_ECDH_X25519, BCTBX_ECDH_X448 */ uint16_t pointCoordinateLength; /**< length in bytes of the point u-coordinate, can be 32 or 56 */ uint8_t *secret; /**< the random secret (scalar) used to compute public key and shared secret */ uint8_t secretLength; /**< in bytes, usually the same than pointCoordinateLength */ uint8_t *sharedSecret; /**< the key exchanged scalar multiplation of MULT(Self Secret, MULT(Peer Secret, BasePoint)), u-coordinate */ uint8_t *selfPublic; /**< this side of the public exchange: MULT(self secret, BasePoint), u-coordinate */ uint8_t *peerPublic; /**< the other side of the public exchange: MULT(peer secret, BasePoint), u-coordinate */ void *cryptoModuleData; /**< a context needed by the underlying crypto implementation - note if in use, most of the previous buffers could be store in it actually */ }bctbx_ECDHContext_t; /** * * @brief Create a context for the ECDH key exchange * * @param[in] ECDHAlgo The algorithm type(BCTBX_ECDH_X25519 or BCTBX_ECDH_X448) * * @return The initialised context for the ECDH calculation(must then be freed calling the destroyECDHContext function), NULL on error * */ BCTBX_PUBLIC bctbx_ECDHContext_t *bctbx_CreateECDHContext(const uint8_t ECDHAlgo); /** * * @brief Generate the private secret scalar and compute the public key MULT(scalar, BasePoint) * * @param[in/out] context ECDH context, will store the public value in ->selfPublic after this call, and secret in ->secret * @param[in] rngFunction pointer to a random number generator used to create the secret * @param[in] rngContext pointer to the rng context if neeeded * */ BCTBX_PUBLIC void bctbx_ECDHCreateKeyPair(bctbx_ECDHContext_t *context, int (*rngFunction)(void *, uint8_t *, size_t), void *rngContext); /** * * @brief Set the given secret key in the ECDH context * * @param[in/out] context ECDH context, will store the given secret key if length is matching the pre-setted algo for this context * @param[in] secret The buffer holding the secret, is duplicated in the ECDH context * @param[in] secretLength Length of previous buffer, must match the algo type setted at context creation */ BCTBX_PUBLIC void bctbx_ECDHSetSecretKey(bctbx_ECDHContext_t *context, const uint8_t *secret, const size_t secretLength); /** * * @brief Set the given self public key in the ECDH context * Warning: no check if it matches the private key value * * @param[in/out] context ECDH context, will store the given self public key if length is matching the pre-setted algo for this context * @param[in] selfPublic The buffer holding the self public key, is duplicated in the ECDH context * @param[in] selfPublicLength Length of previous buffer, must match the algo type setted at context creation */ BCTBX_PUBLIC void bctbx_ECDHSetSelfPublicKey(bctbx_ECDHContext_t *context, const uint8_t *selfPublic, const size_t selfPublicLength); /** * * @brief Set the given peer public key in the ECDH context * * @param[in/out] context ECDH context, will store the given peer public key if length is matching the pre-setted algo for this context * @param[in] peerPublic The buffer holding the peer public key, is duplicated in the ECDH context * @param[in] peerPublicLength Length of previous buffer, must match the algo type setted at context creation */ BCTBX_PUBLIC void bctbx_ECDHSetPeerPublicKey(bctbx_ECDHContext_t *context, const uint8_t *peerPublic, const size_t peerPublicLength); /** * * @brief Derive the public key from the secret setted in context and using preselected algo, following RFC7748 * * @param[in/out] context The context holding algo setting and secret, used to store public key */ BCTBX_PUBLIC void bctbx_ECDHDerivePublicKey(bctbx_ECDHContext_t *context); /** * * @brief Compute the shared secret MULT(secret, peer Public) * ->peerPublic, containing MULT(peerSecret, basePoint) must have been set before this call in context * * @param[in/out] context Read the public values from context, export the key to context->sharedSecret * @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_ECDHComputeSecret(bctbx_ECDHContext_t *context, int (*rngFunction)(void *, uint8_t *, size_t), void *rngContext); /** * * @brief Clean ECDH context. Secret and key, if present, are erased from memory(set to 0) * * @param context The context to deallocate * */ BCTBX_PUBLIC void bctbx_DestroyECDHContext(bctbx_ECDHContext_t *context); /*****************************************************************************/ /***** EdDSA: signature and verify using Elliptic curves *****/ /*****************************************************************************/ /** * @brief Context for the EdDSA using curves 25519 and 448 */ typedef struct bctbx_EDDSAContext_struct { uint8_t algo; /**< Algorithm used for the key exchange mapped to an int: BCTBX_EDDSA_25519, BCTBX_EDDSA_448 */ uint16_t pointCoordinateLength; /**< length in bytes of a serialised point coordinate, can be 32 or 57 */ uint8_t *secretKey; /**< the random secret (scalar) used to compute public key and message signature, is the same length than a serialised point coordinate */ uint8_t secretLength; /**< in bytes, usually the same than pointCoordinateLength */ uint8_t *publicKey; /**< MULT(HASH(secretKey), BasePoint), serialised coordinate */ void *cryptoModuleData; /**< a context needed by the underlying crypto implementation - note if in use, most of the previous buffers could be store in it actually */ }bctbx_EDDSAContext_t; /** * * @brief Create a context for the EdDSA sign/verify * * @param[in] EDDSAAlgo The algorithm type(BCTBX_EDDSA_25519 or BCTBX_EDDSA_448) * * @return The initialised context for the EDDSA calculation(must then be freed calling the destroyEDDSAContext function), NULL on error * */ BCTBX_PUBLIC bctbx_EDDSAContext_t *bctbx_CreateEDDSAContext(uint8_t EDDSAAlgo); /** * * @brief Generate the private secret scalar and compute the public MULT(scalar, BasePoint) * * @param[in/out] context EDDSA context, will store the public value in ->publicKey after this call, and secret in ->secretKey * @param[in] rngFunction pointer to a random number generator used to create the secret * @param[in] rngContext pointer to the rng context if neeeded * */ BCTBX_PUBLIC void bctbx_EDDSACreateKeyPair(bctbx_EDDSAContext_t *context, int (*rngFunction)(void *, uint8_t *, size_t), void *rngContext); /** * * @brief Using the private secret scalar already set in context, compute the public MULT(scalar, BasePoint) * * @param[in/out] context EDDSA context, will store the public value in ->publicKey after this call, already have secret in ->secretKey * */ BCTBX_PUBLIC void bctbx_EDDSADerivePublicKey(bctbx_EDDSAContext_t *context); /** * * @brief Clean ECDH context. Secret and key, if present, are erased from memory(set to 0) * * @param context The context to deallocate * */ BCTBX_PUBLIC void bctbx_DestroyEDDSAContext(bctbx_EDDSAContext_t *context); /** * * @brief Sign the message given using private key and EdDSA algo set in context * * @param[in] context EDDSA context storing the algorithm to use(ed448 or ed25519) and the private key to use * @param[in] message The message to be signed * @param[in] messageLength Length of the message buffer * @param [in] associatedData A "context" for this signature of up to 255 bytes. * @param [in] associatedDataLength Length of the context. * @param[out] signature The signature * @param[in/out] signatureLength The size of the signature buffer as input, the size of the actual signature as output * */ BCTBX_PUBLIC void bctbx_EDDSA_sign(bctbx_EDDSAContext_t *context, const uint8_t *message, const size_t messageLength, const uint8_t *AssociatedData, const uint8_t associatedDataLength, uint8_t *signature, size_t *signatureLength); /** * * @brief Set a public key in a EDDSA context to be used to verify messages signature * * @param[in/out] context EDDSA context storing the algorithm to use(ed448 or ed25519) * @param[in] publicKey The public to store in context * @param[in] publicKeyLength The length of previous buffer */ BCTBX_PUBLIC void bctbx_EDDSA_setPublicKey(bctbx_EDDSAContext_t *context, const uint8_t *publicKey, const size_t publicKeyLength); /** * * @brief Set a private key in a EDDSA context to be used to sign message * * @param[in/out] context EDDSA context storing the algorithm to use(ed448 or ed25519) * @param[in] secretKey The secret to store in context * @param[in] secretKeyLength The length of previous buffer */ BCTBX_PUBLIC void bctbx_EDDSA_setSecretKey(bctbx_EDDSAContext_t *context, const uint8_t *secretKey, const size_t secretKeyLength); /** * * @brief Use the public key set in context to verify the given signature and message * * @param[in/out] context EDDSA context storing the algorithm to use(ed448 or ed25519) and public key * @param[in] message Message to verify * @param[in] messageLength Length of the message buffer * @param [in] associatedData A "context" for this signature of up to 255 bytes. * @param [in] associatedDataLength Length of the context. * @param[in] signature The signature * @param[in] signatureLength The size of the signature buffer * * @return BCTBX_VERIFY_SUCCESS or BCTBX_VERIFY_FAILED */ BCTBX_PUBLIC int bctbx_EDDSA_verify(bctbx_EDDSAContext_t *context, const uint8_t *message, size_t messageLength, const uint8_t *associatedData, const uint8_t associatedDataLength, const uint8_t *signature, size_t signatureLength); /** * * @brief Convert a EDDSA private key to a ECDH private key * pass the EDDSA private key through the hash function used in EdDSA * * @param[in] ed Context holding the current private key to convert * @param[out] x Context to store the private key for x25519 key exchange */ BCTBX_PUBLIC void bctbx_EDDSA_ECDH_privateKeyConversion(const bctbx_EDDSAContext_t *ed, bctbx_ECDHContext_t *x); #define BCTBX_ECDH_ISPEER 0 #define BCTBX_ECDH_ISSELF 1 /** * * @brief Convert a EDDSA public key to a ECDH public key * point conversion : montgomeryX = (edwardsY + 1)*inverse(1 - edwardsY) mod p * * @param[in] ed Context holding the current public key to convert * @param[out] x Context to store the public key for x25519 key exchange * @param[in] isSelf Flag to decide where to store the public key in context: BCTBX_ECDH_ISPEER or BCTBX_ECDH_ISPEER */ BCTBX_PUBLIC void bctbx_EDDSA_ECDH_publicKeyConversion(const bctbx_EDDSAContext_t *ed, bctbx_ECDHContext_t *x, uint8_t isSelf); /*****************************************************************************/ /***** Hashing *****/ /*****************************************************************************/ /* * @brief SHA512 wrapper * @param[in] input Input data buffer * @param[in] inputLength Input data length in bytes * @param[in] hashLength Length of output required in bytes, Output is truncated to the hashLength left bytes. 64 bytes maximum * @param[out] output Output data buffer. * */ BCTBX_PUBLIC void bctbx_sha512(const uint8_t *input, size_t inputLength, uint8_t hashLength, uint8_t *output); /* * @brief SHA384 wrapper * @param[in] input Input data buffer * @param[in] inputLength Input data length in bytes * @param[in] hashLength Length of output required in bytes, Output is truncated to the hashLength left bytes. 48 bytes maximum * @param[out] output Output data buffer. * */ BCTBX_PUBLIC void bctbx_sha384(const uint8_t *input, size_t inputLength, uint8_t hashLength, 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-SHA512 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. 64 bytes maximum * @param[out] output Output data buffer. * */ BCTBX_PUBLIC void bctbx_hmacSha512(const uint8_t *key, size_t keyLength, const uint8_t *input, size_t inputLength, uint8_t hmacLength, uint8_t *output); /** * @brief HMAC-SHA384 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. 48 bytes maximum * @param[out] output Output data buffer. * */ BCTBX_PUBLIC void bctbx_hmacSha384(const uint8_t *key, size_t keyLength, const uint8_t *input, size_t inputLength, uint8_t hmacLength, uint8_t *output); /** * @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 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 length 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 requested 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); /** * @brief encrypt the file in input buffer for linphone encrypted file transfer * * This function must be called with NULL in the plain text to conclude the encryption. * At this last call, if a cipher buffer is provided with non 0 length, it will get an authentication tag of the requested size (max 16) * * @param[in/out] cryptoContext a context already initialized using bctbx_aes_gcm_context_new (created if NULL) * @param[in] key encryption key * @param[in] length buffer size * @param[in] plain buffer holding the input data * @param[out] cipher buffer to store the output data (cipher or authentication tag) */ BCTBX_PUBLIC int bctbx_aes_gcm_encryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher); /** * @brief decrypt the file in input buffer for linphone encrypted file transfer * * This function must be called with NULL in the cipher text to conclude the encryption. * At this last call, if a plain buffer is provided with non 0 length, it will get the authentication tag of length bytes (max 16) * * @param[in/out] cryptoContext a context already initialized using bctbx_aes_gcm_context_new * @param[in] key encryption key * @param[in] length input buffer size * @param[out] plain buffer holding the output data (plain text or tag) * @param[in] cipher buffer to store the input data. WARNING: size must be a multiple of 16 bytes */ BCTBX_PUBLIC int bctbx_aes_gcm_decryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher); /*****************************************************************************/ /***** Cleaning *****/ /*****************************************************************************/ /** * @brief force a buffer values to zero in a way that shall prevent the compiler from optimizing it out * * @param[in/out] buffer the buffer to be cleared * @param[in] size buffer size */ BCTBX_PUBLIC void bctbx_clean(void *buffer, size_t size); #ifdef __cplusplus } #endif #endif /* BCTBX_CRYPTO_H */ bctoolbox-4.4.13/include/bctoolbox/defs.h000066400000000000000000000021301375717307100203150ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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_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-4.4.13/include/bctoolbox/exception.hh000066400000000000000000000041251375717307100215500ustar00rootroot00000000000000/* 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 "bctoolbox/port.h" #ifdef _WIN32 #pragma warning (push) #pragma warning (disable : 4275 4251) #endif /** * @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 BCTBX_PUBLIC BctbxException : public std::exception { public: BctbxException(const std::string &message = ""); BctbxException(const BctbxException &other); virtual ~BctbxException() = default; /** * print stack strace to stderr * */ void printStackTrace() const; void printStackTrace(std::ostream &os) const; const char *what() const noexcept override; 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; } private: void *mArray[20]; size_t mSize; std::ostringstream mOs; mutable std::string mMessage; }; BCTBX_PUBLIC std::ostream &operator<<(std::ostream &__os, const BctbxException &e); #define BCTBX_EXCEPTION BctbxException() << " " << __FILE__ << ":" << __LINE__ << " " #ifdef _WIN32 #pragma warning (pop) #endif #endif /* exception_h */ bctoolbox-4.4.13/include/bctoolbox/ios_utils.hh000066400000000000000000000032471375717307100215700ustar00rootroot00000000000000/* * Copyright (c) 2010-2019 Belledonne Communications SARL. * * This file is part of Liblinphone. * * 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 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 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 . */ #pragma once #include #include namespace bctoolbox { class IOSUtilsInterface { public: virtual unsigned long beginBackgroundTask(const char *name, std::function cb) = 0; virtual void endBackgroundTask(unsigned long id) = 0; virtual bool isApplicationStateActive() = 0; virtual ~IOSUtilsInterface() = default; }; class IOSUtils { public: unsigned long beginBackgroundTask(const char *name, std::function cb); void endBackgroundTask(unsigned long id); bool isApplicationStateActive(); static IOSUtils& getUtils(); IOSUtils(const IOSUtils&) = delete; IOSUtils& operator=(const IOSUtils&) = delete; ~IOSUtils(); private: void *mHandle; IOSUtilsInterface *mUtils; static std::unique_ptr sInstance; IOSUtils(); bool isApp(); void openDynamicLib(); void *loadSymbol(const char *symbol); }; } //namespace bctoolbox bctoolbox-4.4.13/include/bctoolbox/list.h000066400000000000000000000107271375717307100203620ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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-4.4.13/include/bctoolbox/logging.h000066400000000000000000000267761375717307100210500ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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 . */ /** * \file logging.h * \brief Logging API. * **/ #ifndef BCTBX_LOGGING_H #define BCTBX_LOGGING_H #include #include "bctoolbox/list.h" /** * The BCTBX_LOG_DOMAIN macro should be defined with a preprocessor directive (ex: -DBCTBX_LOG_DOMAIN="my-component") in every * software entity (application, library, sub-parts of software etc) using the bctoolbox log facility, so that all invocations of the * bctbx_message(), bctbx_warning(), bctbx_error(), bctbx_fatal() outputs their log within the domain title of the software part there are compiled in. * It SHALL not be defined in any public header, otherwise it will conflict with upper layer using the logging facility for their own domain. * As a special exception, bctoolbox defines the log domain to be "bctbx" if no preprocessor directive defines it. * As a result, bctboolbox owns logs will be output into the "bctbx" domain. **/ #ifndef BCTBX_LOG_DOMAIN #define BCTBX_LOG_DOMAIN "bctbx" #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 : No longer used, always created with a default logger to stdout. */ 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_data); /* 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); /** * @brief Request reopening of the log file. * @param[in] file_log_handler The log handler whose file will be reopened. * @note This function is thread-safe and reopening is done asynchronously. */ BCTBX_PUBLIC void bctbx_file_log_handler_reopen(bctbx_log_handler_t *file_log_handler); /* set domain the handler is limited to. NULL for ALL*/ BCTBX_PUBLIC void bctbx_log_handler_set_domain(bctbx_log_handler_t * log_handler,const char *domain); BCTBX_PUBLIC void bctbx_log_handler_set_user_data(bctbx_log_handler_t*, void* user_data); BCTBX_PUBLIC void *bctbx_log_handler_get_user_data(const bctbx_log_handler_t* log_handler); BCTBX_PUBLIC void bctbx_add_log_handler(bctbx_log_handler_t* handler); BCTBX_PUBLIC void bctbx_remove_log_handler(bctbx_log_handler_t* handler); /* * Set a callback function to render logs for the default handler. */ BCTBX_PUBLIC void bctbx_set_log_handler(BctbxLogFunc func); /* * Same as bctbx_set_log_handler but only for a domain. NULL for all. * Be careful that if domain is specified, the default log handler will no longer output logs for other domains. */ BCTBX_PUBLIC void bctbx_set_log_handler_for_domain(BctbxLogFunc func, const char* domain); /*Convenient function that creates a static log handler logging into supplied FILE argument. Despite it is not recommended to use it in libraries, it can be useful for simple test programs.*/ BCTBX_PUBLIC void bctbx_set_log_file(FILE* f); BCTBX_PUBLIC bctbx_list_t* bctbx_get_log_handlers(void); BCTBX_PUBLIC void bctbx_logv_out(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); /* * Returns 1 if the log level 'level' is enabled for the calling thread, otherwise 0. * This gives the condition to decide to output a log. */ BCTBX_PUBLIC int bctbx_log_level_enabled(const char *domain, BctbxLogLevel 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); /** * Set a specific log level for the calling thread for domain. * When domain is NULL, the log level applies to all domains. */ BCTBX_PUBLIC void bctbx_set_thread_log_level(const char *domain, BctbxLogLevel level); /** * Clears the specific log level set for the calling thread by bctbx_set_thread_log_level(). * After calling this function, the global (not per thread) log level will apply to * logs printed by this thread. */ BCTBX_PUBLIC void bctbx_clear_thread_log_level(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 class pumpstream : public std::ostringstream { public: /*contructor used to disable logging*/ pumpstream():mDomain(""),mLevel(BCTBX_LOG_DEBUG),mTraceEnabled(false){} pumpstream(const char *domain, BctbxLogLevel level) : mDomain(domain ? domain : ""), mLevel(level),mTraceEnabled(true) {} ~pumpstream() { const char *domain = mDomain.empty() ? NULL : mDomain.c_str(); if (mTraceEnabled && bctbx_log_level_enabled(domain, mLevel)) bctbx_log(domain, mLevel, "%s", str().c_str()); } private: const std::string mDomain; const BctbxLogLevel mLevel; const bool mTraceEnabled; }; #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) pumpstream(domain, thelevel) #ifndef BCTBX_DEBUG_MODE #define BCTBX_SLOGD BCTBX_SLOG(BCTBX_LOG_DOMAIN, BCTBX_LOG_DEBUG) #else #define BCTBX_SLOGD pumpstream() #endif #define BCTBX_SLOGI BCTBX_SLOG(BCTBX_LOG_DOMAIN, BCTBX_LOG_MESSAGE) #define BCTBX_SLOGW BCTBX_SLOG(BCTBX_LOG_DOMAIN, BCTBX_LOG_WARNING) #define BCTBX_SLOGE BCTBX_SLOG(BCTBX_LOG_DOMAIN, BCTBX_LOG_ERROR) #endif #endif bctoolbox-4.4.13/include/bctoolbox/map.h000066400000000000000000000140361375717307100201610ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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(const bctbx_map_t *map, bctbx_compare_func compare_func, const void *user_data); BCTBX_PUBLIC bctbx_iterator_t * bctbx_map_cchar_find_custom(const 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(const bctbx_map_t *map, unsigned long long key); BCTBX_PUBLIC bctbx_iterator_t * bctbx_map_cchar_find_key(const 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-4.4.13/include/bctoolbox/parser.h000066400000000000000000000066461375717307100207100ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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 "bctoolbox/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-4.4.13/include/bctoolbox/port.h000066400000000000000000000621751375717307100203770ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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 . */ /* 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 #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 getSocketErrorWithCode(code) strerror(code) #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 #ifdef __cplusplus extern "C" { #endif BCTBX_PUBLIC const char *__bctbx_getWinSocketError(int error); #ifdef __cplusplus } #endif #ifndef getSocketErrorCode #define getSocketErrorCode() WSAGetLastError() #endif #ifndef getSocketError #define getSocketError() __bctbx_getWinSocketError(WSAGetLastError()) #endif #ifndef getSocketErrorWithCode #define getSocketErrorWithCode(code) __bctbx_getWinSocketError(code) #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); #ifdef __GNUC__ # define BCTBX_PRINTF_LIKE(format_pos, args_pos) __attribute__ ((format (printf, format_pos, args_pos))) #else # define BCTBX_PRINTF_LIKE(format_pos, args_pos) #endif BCTBX_PUBLIC char *bctbx_strndup(const char *str,int n); BCTBX_PUBLIC char *bctbx_strdup_printf(const char *fmt,...) BCTBX_PRINTF_LIKE(1, 2); BCTBX_PUBLIC char *bctbx_strdup_vprintf(const char *fmt, va_list ap); BCTBX_PUBLIC char *bctbx_strcat_printf(char *dst, const char *fmt,...) BCTBX_PRINTF_LIKE(2, 3); BCTBX_PUBLIC char *bctbx_strcat_vprintf(char *dst, const char *fmt, va_list ap); BCTBX_PUBLIC char *bctbx_concat(const char *str, ...); BCTBX_PUBLIC char *bctbx_replace(char *str, char c, char n); /** * @brief Return the directory part of a file path. * * Find the last delimiting character ('/' or '\') and return a * copy of the substring before. If no delimiter has been found, * then "." string is returned. * * @param[in] path A string containing a file path. The behaviour * is undefined if the string contains a path to a directoy. MUST be non-NULL. * @return An allocated string containing the directory name. * * @warning This funciton isn't equivalent to libgen.h dirname(). */ BCTBX_PUBLIC char *bctbx_dirname(const char *path); /** * @brief Return the name of a file from its path. * * Find the last delimiting character ('/' or '\') and return a * copy of the substring after. If no delimiter has been found, * then a copy of 'path' is returned. * * @param[in] path A string containing a file path. The behaviour * is undefined if the string contains a path to a directoy. MUST be non-NULL. * @return An allocated string containing the file name. * * @warning This funciton isn't equivalent to libgen.h basename(). */ BCTBX_PUBLIC char *bctbx_basename(const char *path); /** * Tests if a file with given pathname exists. Return 0 if yes, -1 otherwise. **/ BCTBX_PUBLIC int bctbx_file_exist(const char *pathname); /** * Tests if a directory with given pathname exists. Return 0 if yes, -1 otherwise. **/ BCTBX_PUBLIC bool_t bctbx_directory_exists(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); /** Sort a list of addrinfo with the following rules: -IPV6 including NAT64. -V4 MAPPED IPV6. -V4. **/ BCTBX_PUBLIC struct addrinfo *bctbx_addrinfo_sort(struct addrinfo *ai); /** * 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 #if defined(__ANDROID__) int mblen(const char* s, size_t n); int wctomb(char *s, wchar_t wc); #endif bctoolbox-4.4.13/include/bctoolbox/regex.h000066400000000000000000000017221375717307100205140ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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_REGEX_H #define BCTBX_REGEX_H #ifdef __cplusplus extern "C" { #endif BCTBX_PUBLIC bool_t bctbx_is_matching_regex(const char *entry, const char* regex); #ifdef __cplusplus } #endif #endif /* BCTBX_REGEX_H */ bctoolbox-4.4.13/include/bctoolbox/tester.h000066400000000000000000000236441375717307100207170ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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 int bc_tester_register_suites(void); BCTBX_PUBLIC int bc_tester_register_suite_by_name(const char *suite_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 void bc_tester_set_silent_func(int (*func)(const char*)); BCTBX_PUBLIC void bc_tester_set_verbose_func(int (*func)(const char*)); BCTBX_PUBLIC void bc_tester_set_logfile_func(int (*func)(const char*)); 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 char * bc_tester_get_failed_asserts(void); 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-4.4.13/include/bctoolbox/vconnect.h000066400000000000000000000165141375717307100212260ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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_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-4.4.13/include/bctoolbox/vfs.h000066400000000000000000000170671375717307100202110ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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_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 #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-4.4.13/src/000077500000000000000000000000001375717307100144005ustar00rootroot00000000000000bctoolbox-4.4.13/src/CMakeLists.txt000066400000000000000000000265211375717307100171460ustar00rootroot00000000000000############################################################################ # 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 parser.c utils/port.c vconnect.c vfs.c ) set(BCTOOLBOX_CXX_SOURCE_FILES containers/map.cc conversion/charconv_encoding.cc utils/exception.cc utils/regex.cc ) if(APPLE) set(BCTOOLBOX_OBJC_SOURCE_FILES utils/ios_utils.mm ) set(BCTOOLBOX_IOS_OBJC_SOURCE_FILES utils/ios_utils_app.mm ) endif() if(ANDROID) list(APPEND BCTOOLBOX_CXX_SOURCE_FILES conversion/charconv_android.cc) elseif(WIN32) list(APPEND BCTOOLBOX_CXX_SOURCE_FILES conversion/charconv_windows.cc) else() list(APPEND BCTOOLBOX_CXX_SOURCE_FILES conversion/charconv.cc) endif() if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") list(APPEND STRICT_OPTIONS_CXX "-x c++") endif() if(MBEDTLS_FOUND OR POLARSSL_FOUND) list(APPEND BCTOOLBOX_C_SOURCE_FILES crypto/crypto.c) list(APPEND BCTOOLBOX_CXX_SOURCE_FILES crypto/ecc.cc) endif() if(MBEDTLS_FOUND) list(APPEND BCTOOLBOX_C_SOURCE_FILES crypto/mbedtls.c) endif() if(POLARSSL_FOUND) list(APPEND BCTOOLBOX_C_SOURCE_FILES crypto/polarssl.c) endif() if(ENABLE_TESTS_COMPONENT) set(BCTOOLBOX_C_TESTER_SOURCE_FILES tester.c) endif() set(BCTOOLBOX_SOURCE_FILES ${BCTOOLBOX_C_SOURCE_FILES} ${BCTOOLBOX_CXX_SOURCE_FILES} ${BCTOOLBOX_OBJC_SOURCE_FILES}) set(BCTOOLBOX_IOS_SOURCE_FILES ${BCTOOLBOX_IOS_OBJC_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) bc_apply_compile_flags(BCTOOLBOX_OBJC_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_OBJC) bc_apply_compile_flags(BCTOOLBOX_IOS_OBJC_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_OBJC) 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(APPLE) target_link_libraries(bctoolbox-static INTERFACE "-framework Foundation" "-framework AVFoundation") target_include_directories(bctoolbox-static SYSTEM PRIVATE ${ICONV_INCLUDE_DIRS}) target_link_libraries(bctoolbox-static INTERFACE ${ICONV_LIBRARIES}) endif() 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(ANDROID) target_link_libraries(bctoolbox-static INTERFACE log) endif() if(ENABLE_TESTS_COMPONENT) 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(APPLE) if(IOS) set(MIN_OS ${LINPHONE_IOS_DEPLOYMENT_TARGET}) else() set(MIN_OS ${CMAKE_OSX_DEPLOYMENT_TARGET}) endif() set_target_properties(bctoolbox PROPERTIES FRAMEWORK TRUE MACOSX_FRAMEWORK_IDENTIFIER org.linphone.bctoolbox MACOSX_FRAMEWORK_INFO_PLIST "${CMAKE_SOURCE_DIR}/build/osx/Info.plist.in" PUBLIC_HEADER "${BCTOOLBOX_HEADER_FILES}" ) endif() if(APPLE) target_link_libraries(bctoolbox PRIVATE "-framework Foundation" "-framework AVFoundation") target_include_directories(bctoolbox SYSTEM PRIVATE ${ICONV_INCLUDE_DIRS}) target_link_libraries(bctoolbox PRIVATE ${ICONV_LIBRARIES}) 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(ANDROID) target_link_libraries(bctoolbox PRIVATE log) endif() if(ENABLE_TESTS_COMPONENT) add_library(bctoolbox-tester SHARED ${BCTOOLBOX_TESTER_SOURCE_FILES}) set_target_properties(bctoolbox-tester PROPERTIES LINKER_LANGUAGE "CXX") target_link_libraries(bctoolbox-tester PUBLIC bctoolbox PRIVATE ${BCUNIT_TARGETNAME}) 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(ENABLE_STATIC) target_include_directories(bctoolbox-static PUBLIC $ $ ) endif() if(ENABLE_SHARED) target_include_directories(bctoolbox PUBLIC $ $ ) endif() if(APPLE) if(IOS) add_library(bctoolbox-ios SHARED ${BCTOOLBOX_IOS_SOURCE_FILES}) target_link_libraries(bctoolbox-ios PRIVATE bctoolbox) set_target_properties(bctoolbox-ios PROPERTIES FRAMEWORK TRUE MACOSX_FRAMEWORK_IDENTIFIER org.linphone.bctoolbox-ios MACOSX_FRAMEWORK_INFO_PLIST "${CMAKE_SOURCE_DIR}/build/osx/Info.plist.in" LINK_FLAGS "-framework UIKit -framework Foundation -framework CoreFoundation" ) endif() endif() if(MBEDTLS_FOUND) if(ENABLE_STATIC) target_include_directories(bctoolbox-static SYSTEM PRIVATE ${MBEDTLS_INCLUDE_DIRS}) target_link_libraries(bctoolbox-static INTERFACE ${MBEDTLS_LIBRARIES}) endif() if(ENABLE_SHARED) target_include_directories(bctoolbox SYSTEM PRIVATE ${MBEDTLS_INCLUDE_DIRS}) target_link_libraries(bctoolbox PRIVATE ${MBEDTLS_LIBRARIES}) endif() endif() if(POLARSSL_FOUND) if(ENABLE_STATIC) target_include_directories(bctoolbox-static SYSTEM PRIVATE ${POLARSSL_INCLUDE_DIRS}) target_link_libraries(bctoolbox-static INTERFACE ${POLARSSL_LIBRARIES}) endif() if(ENABLE_SHARED) target_include_directories(bctoolbox PRIVATE ${POLARSSL_INCLUDE_DIRS}) target_link_libraries(bctoolbox PRIVATE ${POLARSSL_LIBRARIES}) endif() endif() if(DECAF_FOUND) if(ENABLE_STATIC) target_include_directories(bctoolbox-static PRIVATE ${DECAF_INCLUDE_DIRS}) target_link_libraries(bctoolbox-static PUBLIC decaf-static) endif() if(ENABLE_SHARED) target_include_directories(bctoolbox PRIVATE ${DECAF_INCLUDE_DIRS}) target_link_libraries(bctoolbox PRIVATE ${DECAF_TARGETNAME}) endif() endif() if(ENABLE_TESTS_COMPONENT) if(ENABLE_STATIC) target_link_libraries(bctoolbox-tester-static PUBLIC bctoolbox-static ${BCUNIT_TARGETNAME}) endif() if(ENABLE_SHARED) if(APPLE) set_target_properties(bctoolbox-tester PROPERTIES FRAMEWORK TRUE MACOSX_FRAMEWORK_IDENTIFIER com.belledonne-communications.bctoolbox-tester MACOSX_FRAMEWORK_INFO_PLIST "${CMAKE_SOURCE_DIR}/build/osx/Info.plist.in" 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(ENABLE_TESTS_COMPONENT) 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(ENABLE_TESTS_COMPONENT) 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(APPLE) if(IOS) install(TARGETS bctoolbox-ios 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 ) endif() endif() if(MSVC) # Disable "was deprecated" warnings of windows compiler (typically using strcpy_s instead of strcpy and stupid things like this). if(ENABLE_SHARED) target_compile_options(bctoolbox PRIVATE "/wd4996") endif() if(ENABLE_STATIC) target_compile_options(bctoolbox-static PRIVATE "/wd4996") endif() if(ENABLE_TESTS_COMPONENT) target_compile_options(bctoolbox-tester PRIVATE "/wd4996") endif() endif() bctoolbox-4.4.13/src/containers/000077500000000000000000000000001375717307100165455ustar00rootroot00000000000000bctoolbox-4.4.13/src/containers/list.c000066400000000000000000000206731375717307100176740ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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-4.4.13/src/containers/map.cc000066400000000000000000000272631375717307100176430ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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(const 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(const 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(const 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(const 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(const 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 const 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-4.4.13/src/conversion/000077500000000000000000000000001375717307100165655ustar00rootroot00000000000000bctoolbox-4.4.13/src/conversion/charconv.cc000066400000000000000000000060601375717307100207010ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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 #include #include "bctoolbox/charconv.h" #include "bctoolbox/logging.h" #include "bctoolbox/port.h" static char *convert_from_to (const char *str, const char *from, const char *to) { if (!from || !to) return NULL; if (strcasecmp(from, to) == 0) return bctbx_strdup(str); char *in_buf = (char *) str; char *out_buf, *ptr; size_t in_left = strlen(str) + 1; size_t out_left = in_left + in_left/10; // leave a marge of 10% iconv_t cd; setlocale(LC_CTYPE, ""); const char* r_from = strcasecmp("locale", from) == 0 ? nl_langinfo(CODESET) : from; const char* r_to = strcasecmp("locale", to) == 0 ? nl_langinfo(CODESET) : to; if (strcasecmp(r_from, r_to) == 0) { return bctbx_strdup(str); } cd = iconv_open(r_to, r_from); if (cd != (iconv_t)-1) { size_t ret; size_t out_len = out_left; out_buf = (char *) bctbx_malloc(out_left); ptr = out_buf; // Keep a pointer to the beginning of this buffer to be able to realloc ret = iconv(cd, &in_buf, &in_left, &out_buf, &out_left); while (ret == (size_t)-1 && errno == E2BIG) { ptr = (char *) bctbx_realloc(ptr, out_len*2); out_left = out_len; out_buf = ptr + out_left; out_len *= 2; ret = iconv(cd, &in_buf, &in_left, &out_buf, &out_left); } iconv_close(cd); if (ret == (size_t)-1 && errno != E2BIG) { bctbx_error("Error while converting a string from '%s' to '%s': %s", from, to, strerror(errno)); bctbx_free(ptr); return bctbx_strdup(str); } } else { bctbx_error("Unable to open iconv content descriptor from '%s' to '%s': %s", from, to, strerror(errno)); return bctbx_strdup(str); } return ptr; } char *bctbx_locale_to_utf8 (const char *str) { const char *default_encoding = bctbx_get_default_encoding(); if (!strcmp(default_encoding, "UTF-8")) return bctbx_strdup(str); return convert_from_to(str, default_encoding, "UTF-8"); } char *bctbx_utf8_to_locale (const char *str) { const char *default_encoding = bctbx_get_default_encoding(); if (!strcmp(default_encoding, "UTF-8")) return bctbx_strdup(str); return convert_from_to(str, "UTF-8", default_encoding); } char *bctbx_convert_any_to_utf8 (const char *str, const char *encoding) { return convert_from_to(str, encoding, "UTF-8"); } bctoolbox-4.4.13/src/conversion/charconv_android.cc000066400000000000000000000025501375717307100224010ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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/charconv.h" #include "bctoolbox/logging.h" #include "bctoolbox/port.h" char *bctbx_locale_to_utf8 (const char *str) { // TODO remove this part when the NDK will contain a usable iconv return bctbx_strdup(str); } char *bctbx_utf8_to_locale (const char *str) { // TODO remove this part when the NDK will contain a usable iconv return bctbx_strdup(str); } char *bctbx_convert_any_to_utf8 (const char *str, const char *encoding) { if (!encoding) return NULL; // TODO change this part when the NDK will contain a usable iconv return bctbx_strdup(str); } bctoolbox-4.4.13/src/conversion/charconv_encoding.cc000066400000000000000000000025031375717307100225450ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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 #ifdef __APPLE__ #include "TargetConditionals.h" #endif #include "bctoolbox/charconv.h" #include "bctoolbox/logging.h" #include "bctoolbox/port.h" namespace { std::string defaultEncoding = ""; } void bctbx_set_default_encoding (const char *encoding) { defaultEncoding = encoding; } const char *bctbx_get_default_encoding () { if (!defaultEncoding.empty()) return defaultEncoding.c_str(); #if defined(__ANDROID__) || TARGET_OS_IPHONE return "UTF-8"; #else return "locale"; #endif } bctoolbox-4.4.13/src/conversion/charconv_windows.cc000066400000000000000000000112521375717307100224520ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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 "bctoolbox/charconv.h" #include "bctoolbox/logging.h" #include "bctoolbox/port.h" static std::unordered_map windowsCharset { { "LOCALE", CP_ACP }, { "IBM037", 037 }, { "IBM437", 437 }, { "IBM500", 500 }, { "ASMO-708", 708 }, { "IBM775", 775 }, { "IBM850", 850 }, { "IBM852", 852 }, { "IBM855", 855 }, { "IBM857", 857 }, { "IBM860", 860 }, { "IBM861", 861 }, { "IBM863", 863 }, { "IBM864", 864 }, { "IBM865", 865 }, { "CP866", 866 }, { "IBM869", 869 }, { "IBM870", 870 }, { "WINDOWS-874", 874 }, { "CP875", 875 }, { "SHIFT_JIS", 932 }, { "GB2312", 936 }, { "BIG5", 950 }, { "IBM1026", 1026 }, { "UTF-16", 1200 }, { "WINDOWS-1250", 1250 }, { "WINDOWS-1251", 1251 }, { "WINDOWS-1252", 1252 }, { "WINDOWS-1253", 1253 }, { "WINDOWS-1254", 1254 }, { "WINDOWS-1255", 1255 }, { "WINDOWS-1256", 1256 }, { "WINDOWS-1257", 1257 }, { "WINDOWS-1258", 1258 }, { "JOHAB", 1361 }, { "MACINTOSH", 10000 }, { "UTF-32", 12000 }, { "UTF-32BE", 12001 }, { "US-ASCII", 20127 }, { "IBM273", 20273 }, { "IBM277", 20277 }, { "IBM278", 20278 }, { "IBM280", 20280 }, { "IBM284", 20284 }, { "IBM285", 20285 }, { "IBM290", 20290 }, { "IBM297", 20297 }, { "IBM420", 20420 }, { "IBM423", 20423 }, { "IBM424", 20424 }, { "KOI8-R", 20866 }, { "IBM871", 20871 }, { "IBM880", 20880 }, { "IBM905", 20905 }, { "EUC-JP", 20932 }, { "CP1025", 21025 }, { "KOI8-U", 21866 }, { "ISO-8859-1", 28591 }, { "ISO-8859-2", 28592 }, { "ISO-8859-3", 28593 }, { "ISO-8859-4", 28594 }, { "ISO-8859-5", 28595 }, { "ISO-8859-6", 28596 }, { "ISO-8859-7", 28597 }, { "ISO-8859-8", 28598 }, { "ISO-8859-9", 28599 }, { "ISO-8859-13", 28603 }, { "ISO-8859-15", 28605 }, { "ISO-2022-JP", 50222 }, { "CSISO2022JP", 50221 }, { "ISO-2022-KR", 50225 }, { "EUC-JP", 51932 }, { "EUC-CN", 51936 }, { "EUC-KR", 51949 }, { "GB18030", 54936 }, { "UTF-7", 65000 }, { "UTF-8", 65001 } }; static std::string stringToUpper (const std::string &str) { std::string result(str.size(), ' '); std::transform(str.cbegin(), str.cend(), result.begin(), ::toupper); return result; } static char *convertFromTo (const char *str, const char *from, const char *to) { if (!from || !to) return NULL; if (strcasecmp(from, to) == 0) return bctbx_strdup(str); char* convertedStr; int nChar, nbByte; LPWSTR wideStr; UINT rFrom, rTo; try { rFrom = windowsCharset.at(stringToUpper(std::string(from))); rTo = windowsCharset.at(stringToUpper(std::string(to))); } catch (const std::out_of_range&) { bctbx_error("Error while converting a string from '%s' to '%s': unknown charset", from, to); return NULL; } nChar = MultiByteToWideChar(rFrom, 0, str, -1, NULL, 0); if (nChar == 0) return NULL; wideStr = (LPWSTR) bctbx_malloc(nChar*sizeof(wideStr[0])); if (wideStr == NULL) return NULL; nChar = MultiByteToWideChar(rFrom, 0, str, -1, wideStr, nChar); if (nChar == 0) { bctbx_free(wideStr); wideStr = 0; } nbByte = WideCharToMultiByte(rTo, 0, wideStr, -1, 0, 0, 0, 0); if (nbByte == 0) return NULL; convertedStr = (char *) bctbx_malloc(nbByte); if (convertedStr == NULL) return NULL; nbByte = WideCharToMultiByte(rTo, 0, wideStr, -1, convertedStr, nbByte, 0, 0); if (nbByte == 0) { bctbx_free(convertedStr); convertedStr = 0; } bctbx_free(wideStr); return convertedStr; } char *bctbx_locale_to_utf8 (const char *str) { const char *defaultEncoding = bctbx_get_default_encoding(); if (!strcmp(defaultEncoding, "UTF-8")) return bctbx_strdup(str); return convertFromTo(str, defaultEncoding, "UTF-8"); } char *bctbx_utf8_to_locale (const char *str) { const char *defaultEncoding = bctbx_get_default_encoding(); if (!strcmp(defaultEncoding, "UTF-8")) return bctbx_strdup(str); return convertFromTo(str, "UTF-8", defaultEncoding); } char *bctbx_convert_any_to_utf8 (const char *str, const char *encoding) { return convertFromTo(str, encoding, "UTF-8"); } bctoolbox-4.4.13/src/crypto/000077500000000000000000000000001375717307100157205ustar00rootroot00000000000000bctoolbox-4.4.13/src/crypto/crypto.c000066400000000000000000000100571375717307100174070ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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 /*****************************************************************************/ /***** AES GCM encrypt/decrypt chunk by chunk, needed for file encryption ****/ /*****************************************************************************/ /** * @brief encrypt the file in input buffer for linphone encrypted file transfer * * @param[in/out] cryptoContext a context already initialized using bctbx_aes_gcm_context_new * @param[in] key encryption key * @param[in] length buffer size * @param[in] plain buffer holding the input data * @param[out] cipher buffer to store the output data */ int bctbx_aes_gcm_encryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher) { bctbx_aes_gcm_context_t *gcmContext; if (*cryptoContext == NULL && key == NULL) return -1; // we need the key, at least at first call if (*cryptoContext == NULL) { /* first call to the function, allocate a crypto context and initialise it */ /* key contains 192bits of key || 64 bits of Initialisation Vector, no additional data */ gcmContext = bctbx_aes_gcm_context_new(key, 24, NULL, 0, key+24, 8, BCTBX_GCM_ENCRYPT); if (gcmContext == NULL) { return -1; } *cryptoContext = gcmContext; } else { /* this is not the first call, get the context */ gcmContext = (bctbx_aes_gcm_context_t *)*cryptoContext; } if (plain != NULL) { bctbx_aes_gcm_process_chunk(gcmContext, (const uint8_t *)plain, length, (uint8_t *)cipher); } else { /* plain is NULL, finish the stream, if cipher is not null, generate a tag in it */ if (cipher != NULL && length > 0) { bctbx_aes_gcm_finish(gcmContext, (uint8_t *)cipher, length); } else { bctbx_aes_gcm_finish(gcmContext, NULL, 0); } *cryptoContext = NULL; } return 0; } /** * @brief decrypt the file in input buffer for linphone encrypted file transfer * * @param[in/out] cryptoContext a context already initialized using bctbx_aes_gcm_context_new * @param[in] key encryption key * @param[in] length buffer size * @param[out] plain buffer holding the output data * @param[int] cipher buffer to store the input data */ int bctbx_aes_gcm_decryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher) { bctbx_aes_gcm_context_t *gcmContext; if (*cryptoContext == NULL && key == NULL) return -1; // we need the key, at least at first call if (*cryptoContext == NULL) { /* first call to the function, allocate a crypto context and initialise it */ /* key contains 192bits of key || 64 bits of Initialisation Vector, no additional data */ gcmContext = bctbx_aes_gcm_context_new(key, 24, NULL, 0, key+24, 8, BCTBX_GCM_DECRYPT); if (gcmContext == NULL) { return -1; } *cryptoContext = gcmContext; } else { /* this is not the first call, get the context */ gcmContext = (bctbx_aes_gcm_context_t *)*cryptoContext; } if (cipher != NULL) { bctbx_aes_gcm_process_chunk(gcmContext, (const uint8_t *)cipher, length, (uint8_t *)plain); } else { /* cipher is NULL, finish the stream, if plain is not null and we have a length, compute the authentication tag*/ if (plain != NULL && length > 0) { bctbx_aes_gcm_finish(gcmContext, (uint8_t *)plain, length); } else { bctbx_aes_gcm_finish(gcmContext, NULL, 0); } *cryptoContext = NULL; } return 0; } bctoolbox-4.4.13/src/crypto/ecc.cc000066400000000000000000000551531375717307100167720ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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 #ifdef HAVE_DECAF #include "decaf.h" #include "decaf/ed255.h" #include "decaf/ed448.h" int bctbx_crypto_have_ecc(void) { /* Check our re-defines of key length are matching the decaf ones */ static_assert(BCTBX_ECDH_X25519_PUBLIC_SIZE == DECAF_X25519_PUBLIC_BYTES, "forwarding DECAF defines mismatch"); static_assert(BCTBX_ECDH_X25519_PRIVATE_SIZE == DECAF_X25519_PRIVATE_BYTES, "forwarding DECAF defines mismatch"); static_assert(BCTBX_ECDH_X448_PUBLIC_SIZE == DECAF_X448_PUBLIC_BYTES, "forwarding DECAF defines mismatch"); static_assert(BCTBX_ECDH_X448_PRIVATE_SIZE == DECAF_X448_PRIVATE_BYTES, "forwarding DECAF defines mismatch"); static_assert(BCTBX_EDDSA_25519_PUBLIC_SIZE == DECAF_EDDSA_25519_PUBLIC_BYTES, "forwarding DECAF defines mismatch"); static_assert(BCTBX_EDDSA_25519_PRIVATE_SIZE == DECAF_EDDSA_25519_PRIVATE_BYTES, "forwarding DECAF defines mismatch"); static_assert(BCTBX_EDDSA_25519_SIGNATURE_SIZE == DECAF_EDDSA_25519_SIGNATURE_BYTES, "forwarding DECAF defines mismatch"); static_assert(BCTBX_EDDSA_448_PUBLIC_SIZE == DECAF_EDDSA_448_PUBLIC_BYTES, "forwarding DECAF defines mismatch"); static_assert(BCTBX_EDDSA_448_PRIVATE_SIZE == DECAF_EDDSA_448_PRIVATE_BYTES, "forwarding DECAF defines mismatch"); static_assert(BCTBX_EDDSA_448_SIGNATURE_SIZE == DECAF_EDDSA_448_SIGNATURE_BYTES, "forwarding DECAF defines mismatch"); return TRUE; } /** * @brief Return a 32 bits unsigned integer, each bit set to one matches an * available key agreement algorithm as defined in bctoolbox/include/crypto.h * * This function is implemented in ecc.c as all other backend crypto libraries * (polarssl-1.2, polarssl-1.3/1.4, mbedtls implement DHM2048 and DHM3072 * * @return An unsigned integer of 32 flags matching key agreement algos */ uint32_t bctbx_key_agreement_algo_list(void) { return BCTBX_DHM_2048|BCTBX_DHM_3072|BCTBX_ECDH_X25519|BCTBX_ECDH_X448; } /*****************************************************************************/ /*** Elliptic Curve Diffie-Hellman - ECDH ***/ /*****************************************************************************/ /* Create and initialise the ECDH Context */ bctbx_ECDHContext_t *bctbx_CreateECDHContext(const uint8_t ECDHAlgo) { /* create the context */ bctbx_ECDHContext_t *context = (bctbx_ECDHContext_t *)bctbx_malloc(sizeof(bctbx_ECDHContext_t)); memset (context, 0, sizeof(bctbx_ECDHContext_t)); /* initialise pointer to NULL to ensure safe call to free() when destroying context */ context->secret = NULL; context->sharedSecret = NULL; context->selfPublic = NULL; context->peerPublic = NULL; context->cryptoModuleData = NULL; /* decaf do not use any context for these operations */ /* set parameters in the context */ context->algo=ECDHAlgo; switch (ECDHAlgo) { case BCTBX_ECDH_X25519: context->pointCoordinateLength = DECAF_X25519_PUBLIC_BYTES; context->secretLength = DECAF_X25519_PRIVATE_BYTES; break; case BCTBX_ECDH_X448: context->pointCoordinateLength = DECAF_X448_PUBLIC_BYTES; context->secretLength = DECAF_X448_PRIVATE_BYTES; break; default: bctbx_free(context); return NULL; break; } return context; } /** * * @brief Set the given secret key in the ECDH context * * @param[in/out] context ECDH context, will store the given secret key if length is matching the pre-setted algo for this context * @param[in] secret The buffer holding the secret, is duplicated in the ECDH context * @param[in] secretLength Length of previous buffer, must match the algo type setted at context creation */ void bctbx_ECDHSetSecretKey(bctbx_ECDHContext_t *context, const uint8_t *secret, const size_t secretLength) { if (context!=NULL && context->secretLength==secretLength) { if (context->secret == NULL) { /* allocate a new buffer */ context->secret = (uint8_t *)bctbx_malloc(context->secretLength); } else { /* or make sure we wipe out the existing one */ bctbx_clean(context->secret, context->secretLength); } memcpy(context->secret, secret, secretLength); } } /** * * @brief Set the given self public key in the ECDH context * Warning: no check if it matches the private key value * * @param[in/out] context ECDH context, will store the given self public key if length is matching the pre-setted algo for this context * @param[in] selfPublic The buffer holding the self public key, is duplicated in the ECDH context * @param[in] selfPublicLength Length of previous buffer, must match the algo type setted at context creation */ void bctbx_ECDHSetSelfPublicKey(bctbx_ECDHContext_t *context, const uint8_t *selfPublic, const size_t selfPublicLength) { if (context!=NULL && context->pointCoordinateLength==selfPublicLength) { if (context->selfPublic == NULL) { context->selfPublic = (uint8_t *)bctbx_malloc(selfPublicLength); } memcpy(context->selfPublic, selfPublic, selfPublicLength); } } /** * * @brief Set the given peer public key in the ECDH context * * @param[in/out] context ECDH context, will store the given peer public key if length is matching the pre-setted algo for this context * @param[in] peerPublic The buffer holding the peer public key, is duplicated in the ECDH context * @param[in] peerPublicLength Length of previous buffer, must match the algo type setted at context creation */ BCTBX_PUBLIC void bctbx_ECDHSetPeerPublicKey(bctbx_ECDHContext_t *context, const uint8_t *peerPublic, const size_t peerPublicLength) { if (context!=NULL && context->pointCoordinateLength==peerPublicLength) { /* allocate public key buffer if needed */ if (context->peerPublic == NULL) { context->peerPublic = (uint8_t *)bctbx_malloc(peerPublicLength); } memcpy(context->peerPublic, peerPublic, peerPublicLength); } } /** * * @brief Derive the public key from the secret setted in context and using preselected algo, following RFC7748 * * @param[in/out] context The context holding algo setting and secret, used to store public key */ void bctbx_ECDHDerivePublicKey(bctbx_ECDHContext_t *context) { if (context!=NULL && context->secret!=NULL) { /* allocate public key buffer if needed */ if (context->selfPublic == NULL) { context->selfPublic = (uint8_t *)bctbx_malloc(context->pointCoordinateLength); } /* then generate the public value */ switch (context->algo) { case BCTBX_ECDH_X25519: decaf_x25519_derive_public_key(context->selfPublic, context->secret); break; case BCTBX_ECDH_X448: decaf_x448_derive_public_key(context->selfPublic, context->secret); break; default: break; } } } /* generate the random secret and compute the public value */ void bctbx_ECDHCreateKeyPair(bctbx_ECDHContext_t *context, int (*rngFunction)(void *, uint8_t *, size_t), void *rngContext) { if (context!=NULL) { /* first generate the random bytes of self secret and store it in context(do it directly instead of creating a temp buffer and calling SetSecretKey) */ if (context->secret == NULL) { /* allocate buffer if needed */ context->secret = (uint8_t *)bctbx_malloc(context->secretLength); } else { /* otherwise make sure we wipe out previous secret */ bctbx_clean(context->secret, context->secretLength); } rngFunction(rngContext, context->secret, context->secretLength); /* Then derive the public key */ bctbx_ECDHDerivePublicKey(context); } } /* compute secret - the ->peerPublic field of context must have been set before calling this function */ void bctbx_ECDHComputeSecret(bctbx_ECDHContext_t *context, int (*rngFunction)(void *, uint8_t *, size_t), void *rngContext) { if (context != NULL && context->secret!=NULL && context->peerPublic!=NULL) { if (context->sharedSecret == NULL) { /* allocate buffer if needed */ context->sharedSecret = (uint8_t *)bctbx_malloc(context->pointCoordinateLength); } else { /* otherwise make sure we wipe out previous secret */ bctbx_clean(context->sharedSecret, context->pointCoordinateLength); } switch (context->algo) { case BCTBX_ECDH_X25519: if (decaf_x25519(context->sharedSecret, context->peerPublic, context->secret)==DECAF_FAILURE) { bctbx_free(context->sharedSecret); bctbx_clean(context->sharedSecret, context->pointCoordinateLength); context->sharedSecret=NULL; } break; case BCTBX_ECDH_X448: if (decaf_x448(context->sharedSecret, context->peerPublic, context->secret)==DECAF_FAILURE) { bctbx_free(context->sharedSecret); bctbx_clean(context->sharedSecret, context->pointCoordinateLength); context->sharedSecret=NULL; } break; default: break; } } } /* clean DHM context */ void bctbx_DestroyECDHContext(bctbx_ECDHContext_t *context) { if (context!= NULL) { /* key and secret must be erased from memory and not just freed */ if (context->secret != NULL) { bctbx_clean(context->secret, context->secretLength); free(context->secret); context->secret=NULL; } free(context->selfPublic); context->selfPublic=NULL; if (context->sharedSecret != NULL) { bctbx_clean(context->sharedSecret, context->pointCoordinateLength); free(context->sharedSecret); context->sharedSecret=NULL; } free(context->peerPublic); context->peerPublic=NULL; free(context); } } /*****************************************************************************/ /*** Edwards Curve Digital Signature Algorithm - EdDSA ***/ /*****************************************************************************/ /* Create and initialise the EDDSA Context */ bctbx_EDDSAContext_t *bctbx_CreateEDDSAContext(uint8_t EDDSAAlgo) { /* create the context */ bctbx_EDDSAContext_t *context = (bctbx_EDDSAContext_t *)bctbx_malloc(sizeof(bctbx_EDDSAContext_t)); memset (context, 0, sizeof(bctbx_EDDSAContext_t)); /* initialise pointer to NULL to ensure safe call to free() when destroying context */ context->secretKey = NULL; context->publicKey = NULL; context->cryptoModuleData = NULL; /* decaf do not use any context for these operations */ /* set parameters in the context */ context->algo=EDDSAAlgo; switch (EDDSAAlgo) { case BCTBX_EDDSA_25519: context->pointCoordinateLength = DECAF_EDDSA_25519_PUBLIC_BYTES; context->secretLength = DECAF_EDDSA_25519_PRIVATE_BYTES; break; case BCTBX_EDDSA_448: context->pointCoordinateLength = DECAF_EDDSA_448_PUBLIC_BYTES; context->secretLength = DECAF_EDDSA_448_PRIVATE_BYTES; break; default: bctbx_free(context); return NULL; break; } return context; } /* generate the random secret and compute the public value */ void bctbx_EDDSACreateKeyPair(bctbx_EDDSAContext_t *context, int (*rngFunction)(void *, uint8_t *, size_t), void *rngContext) { /* first generate the random bytes of self secret and store it in context */ if (context->secretKey==NULL) { context->secretKey = (uint8_t *)bctbx_malloc(context->secretLength); } rngFunction(rngContext, context->secretKey, context->secretLength); /* then generate the public value */ bctbx_EDDSADerivePublicKey(context); } /* using the secret key present in context, derive the public one */ void bctbx_EDDSADerivePublicKey(bctbx_EDDSAContext_t *context) { /* check we have a context and it was set to get a public key matching the length of the given one */ if (context != NULL) { if (context->secretKey != NULL) { /* don't go further if we have no secret key in context */ if (context->publicKey == NULL) { /* delete existing key if any */ context->publicKey = (uint8_t *)bctbx_malloc(context->pointCoordinateLength); } /* then generate the public value */ switch (context->algo) { case BCTBX_EDDSA_25519: decaf_ed25519_derive_public_key(context->publicKey, context->secretKey); break; case BCTBX_EDDSA_448: decaf_ed448_derive_public_key(context->publicKey, context->secretKey); break; default: break; } } } } /* clean EDDSA context */ void bctbx_DestroyEDDSAContext(bctbx_EDDSAContext_t *context) { if (context!= NULL) { /* secretKey must be erased from memory and not just freed */ if (context->secretKey != NULL) { bctbx_clean(context->secretKey, context->secretLength); free(context->secretKey); } free(context->publicKey); free(context); } } /** * * @brief Sign the message given using private key and EdDSA algo set in context * * @param[in] context EDDSA context storing the algorithm to use(ed448 or ed25519) and the private key to use * @param[in] message The message to be signed * @param[in] messageLength Length of the message buffer * @param [in] associatedData A "context" for this signature of up to 255 bytes. * @param [in] associatedDataLength Length of the context. * @param[out] signature The signature * @param[in/out] signatureLength The size of the signature buffer as input, the size of the actual signature as output * */ void bctbx_EDDSA_sign(bctbx_EDDSAContext_t *context, const uint8_t *message, const size_t messageLength, const uint8_t *associatedData, const uint8_t associatedDataLength, uint8_t *signature, size_t *signatureLength) { if (context!=NULL) { switch (context->algo) { case BCTBX_EDDSA_25519: if (*signatureLength>=DECAF_EDDSA_25519_SIGNATURE_BYTES) { /* check the buffer is large enough to hold the signature */ decaf_ed25519_sign ( signature, context->secretKey, context->publicKey, message, messageLength, 0, associatedData, associatedDataLength); *signatureLength=DECAF_EDDSA_25519_SIGNATURE_BYTES; return; } break; case BCTBX_EDDSA_448: if (*signatureLength>=DECAF_EDDSA_448_SIGNATURE_BYTES) { /* check the buffer is large enough to hold the signature */ decaf_ed448_sign ( signature, context->secretKey, context->publicKey, message, messageLength, 0, associatedData, associatedDataLength); *signatureLength=DECAF_EDDSA_448_SIGNATURE_BYTES; return; } break; default: break; } } *signatureLength=0; } /** * * @brief Set a public key in a EDDSA context to be used to verify messages signature * * @param[in/out] context EDDSA context storing the algorithm to use(ed448 or ed25519) * @param[in] publicKey The public to store in context * @param[in] publicKeyLength The length of previous buffer */ void bctbx_EDDSA_setPublicKey(bctbx_EDDSAContext_t *context, const uint8_t *publicKey, size_t publicKeyLength) { /* check we have a context and it was set to get a public key matching the length of the given one */ if (context != NULL) { if (context->pointCoordinateLength == publicKeyLength) { /* allocate key buffer if needed */ if (context->publicKey == NULL) { context->publicKey = (uint8_t *)bctbx_malloc(publicKeyLength); } memcpy(context->publicKey, publicKey, publicKeyLength); } } } /** * * @brief Set a private key in a EDDSA context to be used to sign message * * @param[in/out] context EDDSA context storing the algorithm to use(ed448 or ed25519) * @param[in] secretKey The secret to store in context * @param[in] secretKeyLength The length of previous buffer */ void bctbx_EDDSA_setSecretKey(bctbx_EDDSAContext_t *context, const uint8_t *secretKey, size_t secretKeyLength) { /* check we have a context and it was set to get a public key matching the length of the given one */ if (context != NULL) { if (context->secretLength == secretKeyLength) { /* allocate key buffer if needed */ if (context->secretKey == NULL) { context->secretKey = (uint8_t *)bctbx_malloc(secretKeyLength); } memcpy(context->secretKey, secretKey, secretKeyLength); } } } /** * * @brief Use the public key set in context to verify the given signature and message * * @param[in/out] context EDDSA context storing the algorithm to use(ed448 or ed25519) and public key * @param[in] message Message to verify * @param[in] messageLength Length of the message buffer * @param [in] associatedData A "context" for this signature of up to 255 bytes. * @param [in] associatedDataLength Length of the context. * @param[in] signature The signature * @param[in] signatureLength The size of the signature buffer * * @return BCTBX_VERIFY_SUCCESS or BCTBX_VERIFY_FAILED */ int bctbx_EDDSA_verify(bctbx_EDDSAContext_t *context, const uint8_t *message, size_t messageLength, const uint8_t *associatedData, const uint8_t associatedDataLength, const uint8_t *signature, size_t signatureLength) { int ret = BCTBX_VERIFY_FAILED; if (context!=NULL) { decaf_error_t retDecaf = DECAF_FAILURE; switch (context->algo) { case BCTBX_EDDSA_25519: if (signatureLength==DECAF_EDDSA_25519_SIGNATURE_BYTES) { /* check length of given signature */ retDecaf = decaf_ed25519_verify (signature, context->publicKey, message, messageLength, 0, associatedData, associatedDataLength); } break; case BCTBX_EDDSA_448: if (signatureLength==DECAF_EDDSA_448_SIGNATURE_BYTES) { /* check lenght of given signature */ retDecaf = decaf_ed448_verify (signature, context->publicKey, message, messageLength, 0, associatedData, associatedDataLength); } break; default: break; } if (retDecaf == DECAF_SUCCESS) { ret = BCTBX_VERIFY_SUCCESS; } } return ret; } /** * * @brief Convert a EDDSA private key to a ECDH private key * pass the EDDSA private key through the hash function used in EdDSA * * @param[in] ed Context holding the current private key to convert * @param[out] x Context to store the private key for x25519 key exchange */ void bctbx_EDDSA_ECDH_privateKeyConversion(const bctbx_EDDSAContext_t *ed, bctbx_ECDHContext_t *x) { if (ed!=NULL && x!=NULL && ed->secretKey!=NULL) { if (ed->algo == BCTBX_EDDSA_25519 && x->algo == BCTBX_ECDH_X25519) { /* allocate key buffer if needed */ if (x->secret==NULL) { x->secret = (uint8_t *)bctbx_malloc(x->secretLength); } decaf_ed25519_convert_private_key_to_x25519(x->secret, ed->secretKey); } else if (ed->algo == BCTBX_EDDSA_448 && x->algo == BCTBX_ECDH_X448) { /* allocate key buffer if needed */ if (x->secret==NULL) { x->secret = (uint8_t *)bctbx_malloc(x->secretLength); } decaf_ed448_convert_private_key_to_x448(x->secret, ed->secretKey); } } } /** * * @brief Convert a EDDSA public key to a ECDH public key * point conversion : montgomeryX = (edwardsY + 1)*inverse(1 - edwardsY) mod p * * @param[in] ed Context holding the current public key to convert * @param[out] x Context to store the public key for x25519 key exchange * @param[in] isSelf Flag to decide where to store the public key in context: BCTBX_ECDH_ISPEER or BCTBX_ECDH_ISSELF */ void bctbx_EDDSA_ECDH_publicKeyConversion(const bctbx_EDDSAContext_t *ed, bctbx_ECDHContext_t *x, uint8_t isSelf) { if (ed!=NULL && x!=NULL && ed->publicKey!=NULL) { if (ed->algo == BCTBX_EDDSA_25519 && x->algo == BCTBX_ECDH_X25519) { if (isSelf==BCTBX_ECDH_ISPEER) { if (x->peerPublic==NULL) { x->peerPublic = (uint8_t *)bctbx_malloc(x->pointCoordinateLength); } decaf_ed25519_convert_public_key_to_x25519(x->peerPublic, ed->publicKey); } else { if (x->selfPublic==NULL) { x->selfPublic = (uint8_t *)bctbx_malloc(x->pointCoordinateLength); } decaf_ed25519_convert_public_key_to_x25519(x->selfPublic, ed->publicKey); } } else if (ed->algo == BCTBX_EDDSA_448 && x->algo == BCTBX_ECDH_X448) { if (isSelf==BCTBX_ECDH_ISPEER) { if (x->peerPublic==NULL) { x->peerPublic = (uint8_t *)bctbx_malloc(x->pointCoordinateLength); } decaf_ed448_convert_public_key_to_x448(x->peerPublic, ed->publicKey); } else { if (x->selfPublic==NULL) { x->selfPublic = (uint8_t *)bctbx_malloc(x->pointCoordinateLength); } decaf_ed448_convert_public_key_to_x448(x->selfPublic, ed->publicKey); } } } } #else /* HAVE_DECAF */ /* This function is implemented in ecc.c as all other backend crypto libraries * (polarssl-1.2, polarssl-1.3/1.4, mbedtls implement DHM2048 and DHM3072 */ uint32_t bctbx_key_agreement_algo_list(void) { return BCTBX_DHM_2048|BCTBX_DHM_3072; } /* We do not have lib decaf, implement empty stubs */ int bctbx_crypto_have_ecc(void) { return FALSE;} bctbx_ECDHContext_t *bctbx_CreateECDHContext(const uint8_t ECDHAlgo) {return NULL;} void bctbx_ECDHCreateKeyPair(bctbx_ECDHContext_t *context, int (*rngFunction)(void *, uint8_t *, size_t), void *rngContext) {return;} void bctbx_ECDHSetSecretKey(bctbx_ECDHContext_t *context, const uint8_t *secret, const size_t secretLength){return;} void bctbx_ECDHSetSelfPublicKey(bctbx_ECDHContext_t *context, const uint8_t *selfPublic, const size_t selfPublicLength){return;} void bctbx_ECDHSetPeerPublicKey(bctbx_ECDHContext_t *context, const uint8_t *peerPublic, const size_t peerPublicLength){return;} void bctbx_ECDHDerivePublicKey(bctbx_ECDHContext_t *context){return;} void bctbx_ECDHComputeSecret(bctbx_ECDHContext_t *context, int (*rngFunction)(void *, uint8_t *, size_t), void *rngContext){return;} void bctbx_DestroyECDHContext(bctbx_ECDHContext_t *context){return;} bctbx_EDDSAContext_t *bctbx_CreateEDDSAContext(uint8_t EDDSAAlgo) {return NULL;} void bctbx_EDDSACreateKeyPair(bctbx_EDDSAContext_t *context, int (*rngFunction)(void *, uint8_t *, size_t), void *rngContext) {return;} void bctbx_EDDSADerivePublicKey(bctbx_EDDSAContext_t *context) {return;} void bctbx_DestroyEDDSAContext(bctbx_EDDSAContext_t *context) {return;} void bctbx_EDDSA_sign(bctbx_EDDSAContext_t *context, const uint8_t *message, const size_t messageLength, const uint8_t *associatedData, const uint8_t associatedDataLength, uint8_t *signature, size_t *signatureLength) {return;} void bctbx_EDDSA_setPublicKey(bctbx_EDDSAContext_t *context, const uint8_t *publicKey, const size_t publicKeyLength) {return;} void bctbx_EDDSA_setSecretKey(bctbx_EDDSAContext_t *context, const uint8_t *secretKey, const size_t secretKeyLength) {return;} int bctbx_EDDSA_verify(bctbx_EDDSAContext_t *context, const uint8_t *message, size_t messageLength, const uint8_t *associatedData, const uint8_t associatedDataLength, const uint8_t *signature, size_t signatureLength) {return BCTBX_VERIFY_FAILED;} void bctbx_EDDSA_ECDH_privateKeyConversion(const bctbx_EDDSAContext_t *ed, bctbx_ECDHContext_t *x) {return;} void bctbx_EDDSA_ECDH_publicKeyConversion(const bctbx_EDDSAContext_t *ed, bctbx_ECDHContext_t *x, uint8_t isSelf) {return;} #endif bctoolbox-4.4.13/src/crypto/mbedtls.c000066400000000000000000002043131375717307100175210ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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 "utils.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if MBEDTLS_VERSION_NUMBER >= 0x02040000 // v2.4.0 #include #else #include #endif #include "bctoolbox/crypto.h" #include "bctoolbox/logging.h" /*** Cleaning ***/ /** * @brief force a buffer value to zero in a way that shall prevent the compiler from optimizing it out * * @param[in/out] buffer the buffer to be cleared * @param[in] size buffer size */ void bctbx_clean(void *buffer, size_t size) { mbedtls_platform_zeroize(buffer, size); } /*** Error code translation ***/ 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; } /*** base64 ***/ 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) { 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) { 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(const 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)); } bctbx_list_t *bctbx_x509_certificate_get_subjects(const bctbx_x509_certificate_t *cert){ bctbx_list_t *ret = NULL; char subject[1024]={0}; const mbedtls_x509_sequence *subjectAltNames = &((mbedtls_x509_crt *)cert)->subject_alt_names; for (; subjectAltNames != NULL; subjectAltNames = subjectAltNames->next){ const mbedtls_asn1_buf *buf = &subjectAltNames->buf; if (buf->tag == ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2 ) ){ if (buf->p){ ret = bctbx_list_append(ret, bctbx_strndup((char*)buf->p, buf->len)); } } } if (bctbx_x509_certificate_get_subject_dn(cert, subject, sizeof(subject)-1) > 0){ char *cn = strstr(subject, "CN="); if (cn){ char *end; cn += 3; end = strchr(cn, ','); if (end) *end = '\0'; ret = bctbx_list_append(ret, bctbx_strdup(cn)); } } return ret; } 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, 0); /* 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); bctbx_clean(sharedSecretBuffer, 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) { bctbx_clean(context->secret, context->secretLength); free(context->secret); } free(context->self); if (context->key != NULL) { bctbx_clean(context->key, context->primeLength); free(context->key); } free(context->peer); mbedtls_dhm_free((mbedtls_dhm_context *)context->cryptoModuleData); free(context->cryptoModuleData); free(context); } } /*** SSL Client ***/ 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; } } /* * 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)); } int bctbx_ssl_get_ciphersuite_id(const char *ciphersuite){ return mbedtls_ssl_get_ciphersuite_id(ciphersuite); } 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; } void bctbx_ssl_set_mtu(bctbx_ssl_context_t *ssl_ctx, uint16_t mtu) { // remove the record expansion to the given MTU mbedtls_ssl_set_mtu(&(ssl_ctx->ssl_ctx), mtu - mbedtls_ssl_get_record_expansion(&(ssl_ctx->ssl_ctx))); } static bctbx_dtls_srtp_profile_t bctbx_srtp_profile_mbedtls2bctoolbox(mbedtls_ssl_srtp_profile 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 mbedtls_ssl_srtp_profile 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; } void bctbx_ssl_set_mtu(bctbx_ssl_context_t *ssl_ctx, uint16_t mtu) { } 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; } bctbx_type_implementation_t bctbx_ssl_get_implementation_type(void) { return BCTBX_MBEDTLS; } 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_ciphersuites(bctbx_ssl_config_t *ssl_config, const int *ciphersuites) { if (ssl_config == NULL) { return BCTBX_ERROR_INVALID_SSL_CONFIG; } /* remap input arguments */ if (ciphersuites == NULL) { return BCTBX_ERROR_INVALID_INPUT_DATA; } mbedtls_ssl_conf_ciphersuites(ssl_config->ssl_config, ciphersuites); return 0; } void *bctbx_ssl_config_get_private_config(bctbx_ssl_config_t *ssl_config) { return (void *)ssl_config->ssl_config; } 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; mbedtls_ssl_srtp_profile 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 *****/ /*****************************************************************************/ /* * @brief HMAC-SHA512 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. 64 bytes maximum * @param[out] output Output data buffer. * */ void bctbx_hmacSha512(const uint8_t *key, size_t keyLength, const uint8_t *input, size_t inputLength, uint8_t hmacLength, uint8_t *output) { uint8_t hmacOutput[64]; mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA512), key, keyLength, input, inputLength, hmacOutput); /* check output length, can't be>64 */ if (hmacLength>64) { memcpy(output, hmacOutput, 64); } else { memcpy(output, hmacOutput, hmacLength); } } /* * @brief HMAC-SHA384 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. 48 bytes maximum * @param[out] output Output data buffer. * */ void bctbx_hmacSha384(const uint8_t *key, size_t keyLength, const uint8_t *input, size_t inputLength, uint8_t hmacLength, uint8_t *output) { uint8_t hmacOutput[48]; mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA384), key, keyLength, input, inputLength, hmacOutput); /* check output length, can't be>48 */ if (hmacLength>48) { memcpy(output, hmacOutput, 48); } else { memcpy(output, hmacOutput, hmacLength); } } /* * brief HMAC-SHA256 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 SHA512 wrapper * @param[in] input Input data buffer * @param[in] inputLength Input data length in bytes * @param[in] hashLength Length of output required in bytes, Output is truncated to the hashLength left bytes. 64 bytes maximum * @param[out] output Output data buffer. * */ void bctbx_sha512(const uint8_t *input, size_t inputLength, uint8_t hashLength, uint8_t *output) { uint8_t hashOutput[64]; mbedtls_sha512(input, inputLength, hashOutput, 0); /* last param to zero to select SHA512 and not SHA384 */ /* check output length, can't be>64 */ if (hashLength>64) { memcpy(output, hashOutput, 64); } else { memcpy(output, hashOutput, hashLength); } } /* * @brief SHA384 wrapper * @param[in] input Input data buffer * @param[in] inputLength Input data length in bytes * @param[in] hashLength Length of output required in bytes, Output is truncated to the hashLength left bytes. 48 bytes maximum * @param[out] output Output data buffer. * */ void bctbx_sha384(const uint8_t *input, size_t inputLength, uint8_t hashLength, uint8_t *output) { uint8_t hashOutput[48]; mbedtls_sha512(input, inputLength, hashOutput, 1); /* last param to one to select SHA384 and not SHA512 */ /* check output length, can't be>48 */ if (hashLength>48) { memcpy(output, hashOutput, 48); } else { memcpy(output, hashOutput, hashLength); } } /* * @brief SHA256 wrapper * @param[in] input Input data buffer * @param[in] inputLength Input data length in bytes * @param[in] hashLength Length of output required in bytes, 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]; 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-4.4.13/src/crypto/polarssl.c000066400000000000000000001616661375717307100177430ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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 #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 /*** Cleaning ***/ /** * @brief force a buffer value to zero in a way that shall prevent the compiler from optimizing it out * * @param[in/out] buffer the buffer to be cleared * @param[in] size buffer size */ void bctbx_clean(void *buffer, size_t size) { volatile uint8_t *p = buffer; while(size--) *p++ = 0; } 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; } } bctbx_type_implementation_t bctbx_ssl_get_implementation_type(void) { return BCTBX_POLARSSL; } 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(const 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)); } bctbx_list_t *bctbx_x509_certificate_get_subjects(const bctbx_x509_certificate_t *cert){ bctbx_error("bctbx_x509_certificate_get_subjects(): not implemented for polarssl."); return NULL; } 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, 0); /* 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)); } int bctbx_ssl_get_ciphersuite_id(const char *ciphersuite){ return BCTBX_ERROR_UNAVAILABLE_FUNCTION; } 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 **/ /* used for DTLS SRTP but not implemented on polarssl, available on mbedtls only */ void bctbx_ssl_set_mtu(bctbx_ssl_context_t *ssl_ctx, uint16_t mtu) { }; #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_ciphersuites(bctbx_ssl_config_t *ssl_config, const int *ciphersuites) { return BCTBX_ERROR_INVALID_SSL_CONFIG; } /* unavailable function */ void *bctbx_ssl_config_get_private_config(bctbx_ssl_config_t *ssl_config) { return NULL; } 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-SHA512 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. 48 bytes maximum * @param[out] output Output data buffer. * */ void bctbx_hmacSha512(const uint8_t *key, size_t keyLength, const uint8_t *input, size_t inputLength, uint8_t hmacLength, uint8_t *output) { uint8_t hmacOutput[64]; sha512_hmac(key, keyLength, input, inputLength, hmacOutput, 0); /* last param to one to select SHA512 and not SHA384 */ /* check output length, can't be>64 */ if (hmacLength>64) { memcpy(output, hmacOutput, 64); } else { memcpy(output, hmacOutput, hmacLength); } } /** * @brief HMAC-SHA384 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. 48 bytes maximum * @param[out] output Output data buffer. * */ void bctbx_hmacSha384(const uint8_t *key, size_t keyLength, const uint8_t *input, size_t inputLength, uint8_t hmacLength, uint8_t *output) { uint8_t hmacOutput[48]; sha512_hmac(key, keyLength, input, inputLength, hmacOutput, 1); /* last param to one to select SHA384 and not SHA512 */ /* check output length, can't be>48 */ if (hmacLength>48) { memcpy(output, hmacOutput, 48); } else { memcpy(output, hmacOutput, hmacLength); } } /** * @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 SHA512 wrapper * @param[in] input Input data buffer * @param[in] inputLength Input data length in bytes * @param[in] hashLength Length of output required in bytes, Output is truncated to the hashLength left bytes. 64 bytes maximum * @param[out] output Output data buffer. * */ void bctbx_sha512(const uint8_t *input, size_t inputLength, uint8_t hashLength, uint8_t *output) { uint8_t hashOutput[64]; sha512(input, inputLength, hashOutput, 0); /* last param to zero to select SHA512 and not SHA384 */ /* check output length, can't be>64 */ if (hashLength>64) { memcpy(output, hashOutput, 64); } else { memcpy(output, hashOutput, hashLength); } } /* * @brief SHA384 wrapper * @param[in] input Input data buffer * @param[in] inputLength Input data length in bytes * @param[in] hashLength Length of output required in bytes, Output is truncated to the hashLength left bytes. 48 bytes maximum * @param[out] output Output data buffer. * */ void bctbx_sha384(const uint8_t *input, size_t inputLength, uint8_t hashLength, uint8_t *output) { uint8_t hashOutput[48]; sha512(input, inputLength, hashOutput, 1); /* last param to one to select SHA384 and not SHA512 */ /* check output length, can't be>48 */ if (hashLength>48) { memcpy(output, hashOutput, 48); } else { memcpy(output, hashOutput, hashLength); } } /** * @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-4.4.13/src/logging/000077500000000000000000000000001375717307100160265ustar00rootroot00000000000000bctoolbox-4.4.13/src/logging/logging.c000066400000000000000000000615561375717307100176350ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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 #include #include #include #ifdef _MSC_VER #ifndef access #define access _access #endif #ifndef fileno #define fileno _fileno #endif #endif /* * Exclude windows and android for bctbx_set_thread_log_level() implementation. * Android has lots of bugs around thread local storage and JVM. */ #if !defined(_WIN32) && !defined(__ANDROID__) #define THREAD_LOG_LEVEL_ENABLED 1 #endif #ifdef __ANDROID__ #include #endif /* __ANDROID__ */ typedef struct{ char *domain; unsigned int logmask; #ifdef THREAD_LOG_LEVEL_ENABLED int thread_level_set; /* Set to 1 if a thread specific log level has been set. This enables an optimisation only for the case of an app that never uses per-thread log levels.*/ pthread_key_t thread_level_key; /* The key to access the thread specific level. */ #endif }BctoolboxLogDomain; #ifdef THREAD_LOG_LEVEL_ENABLED static void thread_level_key_destroy(void *ptr){ bctbx_free(ptr); } #endif static BctoolboxLogDomain * bctbx_log_domain_new(const char *domain, unsigned int logmask){ BctoolboxLogDomain *ld = bctbx_new0(BctoolboxLogDomain, 1); ld->domain = domain ? bctbx_strdup(domain) : NULL; ld->logmask = logmask; #ifdef THREAD_LOG_LEVEL_ENABLED ld->thread_level_set = FALSE; pthread_key_create(&ld->thread_level_key, thread_level_key_destroy); #endif return ld; } void bctbx_log_domain_destroy(BctoolboxLogDomain *obj){ #if THREAD_LOG_LEVEL_ENABLED pthread_key_delete(obj->thread_level_key); #endif if (obj->domain) bctbx_free(obj->domain); bctbx_free(obj); } #if THREAD_LOG_LEVEL_ENABLED unsigned int bctbx_log_domain_get_thread_log_level_mask(BctoolboxLogDomain *ld){ unsigned int *specific = (unsigned int*)pthread_getspecific(ld->thread_level_key); if (!specific) return 0; return *specific; } #endif typedef struct _bctbx_logger_t { BctoolboxLogDomain *default_log_domain; bctbx_list_t *logv_outs; 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_log_handler_t * default_handler; } bctbx_logger_t; struct _bctbx_log_handler_t { BctbxLogHandlerFunc func; BctbxLogHandlerDestroyFunc destroy; char *domain; /*domain this log handler is limited to. NULL for all*/ void* user_info; }; typedef struct _bctbx_file_log_handler_t { char* path; char* name; uint64_t max_size; uint64_t size; FILE* file; bool_t reopen_requested; } bctbx_file_log_handler_t; void bctbx_logv_out_cb(void* user_info, const char *domain, BctbxLogLevel lev, const char *fmt, va_list args); static void wrapper(void* info,const char *domain, BctbxLogLevel lev, const char *fmt, va_list args) { BctbxLogFunc func = (BctbxLogFunc)info; if (func) func(domain, lev, fmt, args); } static bctbx_logger_t main_logger = {0}; static bctbx_log_handler_t static_handler = {0}; static bctbx_logger_t * bctbx_get_logger(void){ if (main_logger.default_log_domain == NULL){ main_logger.default_log_domain = bctbx_log_domain_new(NULL, BCTBX_LOG_WARNING | BCTBX_LOG_ERROR | BCTBX_LOG_FATAL); bctbx_mutex_init(&main_logger.domains_mutex, NULL); bctbx_mutex_init(&main_logger.log_mutex, NULL); main_logger.default_handler = &static_handler; static_handler.func=wrapper; static_handler.destroy=(BctbxLogHandlerDestroyFunc)bctbx_logv_out_destroy; static_handler.user_info=(void*)bctbx_logv_out; bctbx_add_log_handler(&static_handler); } return &main_logger; } void bctbx_init_logger(bool_t create){ bctbx_get_logger(); } void bctbx_log_handlers_free(void) { bctbx_list_t *handlers = bctbx_list_first_elem(bctbx_get_logger()->logv_outs); while (handlers) { bctbx_log_handler_t* handler = (bctbx_log_handler_t*)handlers->data; handler->destroy(handler); handlers = handlers->next; } } void bctbx_uninit_logger(void){ /* Calling bctbx_uninit_logger() from a component is dangerous as it will reset the default logger. * it is safer that this function does nothing.*/ #if 0 bctbx_logger_t * logger = bctbx_get_logger(); bctbx_logv_flush(); bctbx_mutex_destroy(&logger->domains_mutex); bctbx_mutex_destroy(&logger->log_mutex); bctbx_log_handlers_free(); logger->logv_outs = bctbx_list_free(logger->logv_outs); logger->log_domains = bctbx_list_free_with_data(logger->log_domains, (void (*)(void*))bctbx_log_domain_destroy); bctbx_log_domain_destroy(logger->default_log_domain); logger->default_log_domain = NULL; #endif } 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_malloc0(sizeof(bctbx_log_handler_t)); handler->func = func; handler->destroy = destroy; handler->user_info = user_info; return handler; } void bctbx_log_handler_set_user_data(bctbx_log_handler_t* log_handler, void* user_data) { log_handler->user_info = user_data; } void *bctbx_log_handler_get_user_data(const bctbx_log_handler_t* log_handler) { return log_handler->user_info; } void bctbx_log_handler_set_domain(bctbx_log_handler_t * log_handler, const char *domain) { if (log_handler->domain) bctbx_free(log_handler->domain); if (domain) { log_handler->domain = bctbx_strdup(domain); } else { log_handler->domain = NULL ; } } bctbx_log_handler_t* bctbx_create_file_log_handler(uint64_t max_size, const char* path, const char* name) { bctbx_log_handler_t *handler = NULL; bctbx_file_log_handler_t *filehandler = NULL; char *full_name = bctbx_strdup_printf("%s/%s", path, name); struct stat buf = {0}; FILE *f = fopen(full_name, "a"); if (f == NULL) { fprintf(stderr, "error while opening '%s': %s\n", full_name, strerror(errno)); goto end; } if (stat(full_name, &buf) != 0) { fprintf(stderr, "error while gathering info about '%s': %s", full_name, strerror(errno)); goto end; } filehandler = bctbx_new0(bctbx_file_log_handler_t, 1); filehandler->max_size = max_size; filehandler->size = buf.st_size; filehandler->path = bctbx_strdup(path); filehandler->name = bctbx_strdup(name); filehandler->file = f; handler = bctbx_new0(bctbx_log_handler_t, 1); handler->func = bctbx_logv_file; handler->destroy = bctbx_logv_file_destroy; handler->user_info = filehandler; end: bctbx_free(full_name); return handler; } void bctbx_file_log_handler_reopen(bctbx_log_handler_t *file_log_handler) { bctbx_file_log_handler_t *filehandler = (bctbx_file_log_handler_t *)file_log_handler->user_info; bctbx_logger_t *logger = bctbx_get_logger(); bctbx_mutex_lock(&logger->log_mutex); filehandler->reopen_requested = TRUE; bctbx_mutex_unlock(&logger->log_mutex); } /** *@param func: your logging function, compatible with the BctoolboxLogFunc prototype. * **/ void bctbx_add_log_handler(bctbx_log_handler_t* handler){ bctbx_logger_t *logger = bctbx_get_logger(); if (handler && !bctbx_list_find(logger->logv_outs, handler)) logger->logv_outs = bctbx_list_append(logger->logv_outs, (void*)handler); /*else, already in*/ } void bctbx_remove_log_handler(bctbx_log_handler_t* handler){ bctbx_logger_t *logger = bctbx_get_logger(); logger->logv_outs = bctbx_list_remove(logger->logv_outs, handler); handler->destroy(handler); return; } void bctbx_set_log_handler(BctbxLogFunc func){ bctbx_set_log_handler_for_domain(func,NULL); } void bctbx_set_log_handler_for_domain(BctbxLogFunc func, const char* domain){ bctbx_log_handler_t *h = bctbx_get_logger()->default_handler; h->user_info=(void*)func; bctbx_log_handler_set_domain(h, domain); } 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_get_logger()->logv_outs; } static BctoolboxLogDomain * get_log_domain(const char *domain){ bctbx_list_t *it; bctbx_logger_t *logger = bctbx_get_logger(); if (domain == NULL) return logger->default_log_domain; for (it = 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; bctbx_logger_t *logger = bctbx_get_logger(); ret = get_log_domain(domain); if (ret) return ret; /*it does not exist, hence create it by taking the mutex*/ bctbx_mutex_lock(&logger->domains_mutex); ret = get_log_domain(domain); if (!ret){ ret = bctbx_log_domain_new(domain, logger->default_log_domain->logmask); logger->log_domains = bctbx_list_prepend(logger->log_domains, ret); } bctbx_mutex_unlock(&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){ get_log_domain_rw(domain)->logmask = levelmask; } static unsigned int level_to_mask(BctbxLogLevel level){ unsigned 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; } return levelmask; } void bctbx_set_log_level(const char *domain, BctbxLogLevel level){ bctbx_set_log_level_mask(domain, level_to_mask(level)); } unsigned int bctbx_get_log_level_mask(const char *domain) { BctoolboxLogDomain *ld = get_log_domain(domain); if (!ld) ld = bctbx_get_logger()->default_log_domain; return ld->logmask; } int bctbx_log_level_enabled(const char *domain, BctbxLogLevel level){ unsigned int logmask = 0; BctoolboxLogDomain *ld = get_log_domain(domain); if (!ld) ld = bctbx_get_logger()->default_log_domain; #ifdef THREAD_LOG_LEVEL_ENABLED if (ld->thread_level_set) logmask = bctbx_log_domain_get_thread_log_level_mask(ld); #endif if (logmask == 0) logmask = ld->logmask; /* if there is no thread specific log level, revert to global log level.*/ return (logmask & (unsigned int)level) != 0; } void bctbx_set_log_thread_id(unsigned long thread_id) { bctbx_logger_t *logger = bctbx_get_logger(); if (thread_id == 0) { bctbx_logv_flush(); bctbx_mutex_destroy(&logger->log_stored_messages_mutex); } else { bctbx_mutex_init(&logger->log_stored_messages_mutex, NULL); } 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){ strcat(dst,ret); 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_logger_t *logger = bctbx_get_logger(); bctbx_mutex_lock(&logger->log_stored_messages_mutex); msglist = logger->log_stored_messages_list; logger->log_stored_messages_list = NULL; bctbx_mutex_unlock(&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 *handlers = bctbx_list_first_elem(logger->logv_outs); #ifdef _WIN32 while (handlers) { bctbx_log_handler_t* handler = (bctbx_log_handler_t*)handlers->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); } handlers = handlers->next; } #else while (handlers) { bctbx_log_handler_t* handler = (bctbx_log_handler_t*)handlers->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); } handlers = handlers->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) { bctbx_logger_t *logger = bctbx_get_logger(); if ((logger->logv_outs != NULL) && bctbx_log_level_enabled(domain, level)) { if (logger->log_thread_id == 0) { bctbx_list_t *handlers = bctbx_list_first_elem(logger->logv_outs); while (handlers) { bctbx_log_handler_t* handler = (bctbx_log_handler_t*)handlers->data; if(handler && (!handler->domain || !domain || strcmp(handler->domain,domain)==0)) { va_list tmp; va_copy(tmp, args); handler->func(handler->user_info, domain, level, fmt, tmp); va_end(tmp); } handlers = handlers->next; } } else if (logger->log_thread_id == bctbx_thread_self()) { bctbx_list_t *handlers; bctbx_logv_flush(); handlers = bctbx_list_first_elem(logger->logv_outs); while (handlers) { bctbx_log_handler_t* handler = (bctbx_log_handler_t*)handlers->data; if(handler && (!handler->domain || !domain || strcmp(handler->domain,domain)==0)) { va_list tmp; va_copy(tmp, args); handler->func(handler->user_info, domain, level, fmt, tmp); va_end(tmp); } handlers = handlers->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(&logger->log_stored_messages_mutex); logger->log_stored_messages_list = bctbx_list_append(logger->log_stored_messages_list, l); bctbx_mutex_unlock(&logger->log_stored_messages_mutex); } } #if !defined(_WIN32_WCE) if (level == BCTBX_LOG_FATAL) { bctbx_logv_flush(); #ifdef __ANDROID__ //Act as a flush + abort __android_log_assert(NULL, NULL, "%s", "Aborting"); #else abort(); #endif } #endif } void bctbx_logv_out( const char *domain, BctbxLogLevel lev, const char *fmt, va_list args){ bctbx_logv_out_cb(NULL, domain, lev, fmt, args); } /*This function does the default formatting and output to file*/ void bctbx_logv_out_cb(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++; bctbx_free(log_filename); log_filename = bctbx_strdup_printf("%s/%s_%d%s", filehandler->path, file_no_extension, n, extension2); } while(n > 1) { bctbx_free(log_filename); 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); bctbx_free(log_filename2); } bctbx_free(log_filename); 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 = NULL; 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; bctbx_logger_t *logger = bctbx_get_logger(); bctbx_mutex_lock(&logger->log_mutex); FILE *f = filehandler ? filehandler->file : stdout; bctbx_gettimeofday(&tp,NULL); tt = (time_t)tp.tv_sec; #ifdef _WIN32 lt = localtime(&tt); #else lt = localtime_r(&tt,&tmbuf); #endif if(!f) goto end; 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); /* reopen the log file when either the size limit has been exceeded, or reopen has been required by the user. Reopening a log file that has reached the size limit automatically trigger log rotation while opening. */ if (filehandler) { bool_t reopen_requested = filehandler->reopen_requested; if (filehandler->max_size > 0 && ret > 0) { filehandler->size += ret; reopen_requested = reopen_requested || filehandler->size > filehandler->max_size; } if (reopen_requested) { _close_log_collection_file(filehandler); _open_log_collection_file(filehandler); filehandler->reopen_requested = FALSE; } } end: bctbx_mutex_unlock(&logger->log_mutex); if (msg) 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); } void bctbx_set_thread_log_level(const char *domain, BctbxLogLevel level){ #ifdef THREAD_LOG_LEVEL_ENABLED BctoolboxLogDomain * ld = get_log_domain(domain); unsigned int *specific = (unsigned int*)pthread_getspecific(ld->thread_level_key); if (!specific) specific = bctbx_new0(unsigned int, 1); *specific = level_to_mask(level); pthread_setspecific(ld->thread_level_key, specific); ld->thread_level_set = TRUE; #endif } void bctbx_clear_thread_log_level(const char *domain){ #ifdef THREAD_LOG_LEVEL_ENABLED BctoolboxLogDomain * ld = get_log_domain(domain); unsigned int *specific = (unsigned int*)pthread_getspecific(ld->thread_level_key); if (specific) *specific = 0; #endif } #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-4.4.13/src/parser.c000066400000000000000000000054051375717307100160440ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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/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-4.4.13/src/tester.c000066400000000000000000001256321375717307100160630ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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 #include #include #ifndef _WIN32 #include #include #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; static char *log_file_name = NULL; static int bc_printf_verbosity_info; static 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 static const char default_xml_file[] = "BCUnitAutomated"; static const char * xml_file = default_xml_file; static int xml_enabled = 0; static char * suite_name = NULL; static char * test_name = NULL; static char * tag_name = NULL; static char * expected_res = NULL; static size_t max_vm_kb = 0; static int run_skipped_tests = 0; //0 if deactivated, or > 0, representing the maximum number of subprocesses to launch static int parallel_suites = 0; static uint64_t globalTimeout = 0; //To keep record of the process name who started and args static char **origin_argv = NULL; static int origin_argc = 0; //Custom cli arguments handlers for end tests implementations static int (*verbose_arg_func)(const char *arg) = NULL; static int (*silent_arg_func)(const char *arg) = NULL; static int (*logfile_arg_func)(const char *arg) = NULL; void bc_tester_set_silent_func(int (*func)(const char*)) { if (func) { silent_arg_func = func; } } void bc_tester_set_verbose_func(int (*func)(const char*)) { if (func) { verbose_arg_func = func; } } void bc_tester_set_logfile_func(int (*func)(const char*)) { if (func) { logfile_arg_func = func; } } 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_register_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; } //Allows to register directly to BCUnit by name. Wrap bc_tester_register_suite int bc_tester_register_suite_by_name(const char *suite_name) { int suiteIdx = -1; suiteIdx = bc_tester_suite_index(suite_name); if (suiteIdx != -1) { if (!CU_registry_initialized()) { if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error(); } return bc_tester_register_suite(test_suite[suiteIdx], NULL); } return -1; } 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 (strcasecmp(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 (strcasecmp(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;jpNext, i++) { tmp = bc_sprintf("%s\n %d. %s:%u - %s", buffer, i, (NULL != pFailure->strFileName) ? pFailure->strFileName : "", pFailure->uiLineNumber, (NULL != pFailure->strCondition) ? pFailure->strCondition : ""); if (i != 1) { bctbx_free(buffer); } buffer = tmp; } } return buffer; } #ifdef _WIN32 void write_suite_result_file(char *suite_name, char *results_string) { (void)suite_name; (void)results_string; //TODO Windows support } void merge_and_print_results_files(void) { //TODO Windows support } #else void write_suite_result_file(char *suite_name, char *results_string) { bctbx_vfs_file_t* bctbx_file; char *suite_name_wo_spaces, *file_name; suite_name_wo_spaces = bctbx_replace(bctbx_strdup(suite_name), ' ', '_'); file_name = bc_sprintf("%s.result", suite_name_wo_spaces); bctbx_file = bctbx_file_open(bctbx_vfs_get_default(), file_name, "w+"); if (bctbx_file) { bctbx_file_truncate(bctbx_file, 0); bctbx_file_fprintf(bctbx_file, 0, results_string); bctbx_file_close(bctbx_file); } bctbx_free(suite_name_wo_spaces); bctbx_free(file_name); } void merge_and_print_results_files(void) { bctbx_vfs_file_t* bctbx_file; int i; ssize_t file_size, read_bytes; char *buffer, *tmp; char *suite_name_wo_spaces, *file_name; char *results = NULL; for (i = 0; i < nb_test_suites; i++) { suite_name_wo_spaces = bctbx_replace(bctbx_strdup(test_suite[i]->name), ' ', '_'); file_name = bc_sprintf("%s.result", suite_name_wo_spaces); bctbx_file = bctbx_file_open2(bctbx_vfs_get_default(), file_name, O_RDONLY); if (bctbx_file) { file_size = (int64_t) bctbx_file_size(bctbx_file); if (file_size > 0) { buffer = malloc(file_size + 1); read_bytes = bctbx_file_read(bctbx_file, (void *)buffer, file_size, 0); if (read_bytes == file_size) { buffer[read_bytes] = '\0'; if (results == NULL) { results = bctbx_concat("Suite '", test_suite[i]->name, "' results:\n", buffer, NULL); } else { tmp = bctbx_concat(results, "\nSuite '", test_suite[i]->name, "' results:\n", buffer, NULL); bctbx_free(results); results = tmp; } } else { bc_tester_printf(bc_printf_verbosity_error, "Failed to read suite results file '%s'", file_name); } bctbx_free(buffer); } else { bc_tester_printf(bc_printf_verbosity_error, "Empty suite results file '%s'", file_name); } remove(file_name); } else { bc_tester_printf(bc_printf_verbosity_error, "Failed to open suite results file '%s'", file_name); //Assume suite crash and report it. if (results == NULL) { results = bctbx_concat("Suite '", test_suite[i]->name, "' results: CRASH\n", NULL); } else { tmp = bctbx_concat(results, "\nSuite '", test_suite[i]->name, "' results: CRASH\n", NULL); bctbx_free(results); results = tmp; } } bctbx_free(suite_name_wo_spaces); bctbx_free(file_name); } if (results) { bc_tester_printf(bc_printf_verbosity_info, "Tests suites results: \n%s", results); bctbx_free(results); } } #endif static void all_complete_message_handler(const CU_pFailureRecord pFailure) { #ifdef HAVE_CU_GET_SUITE if (parallel_suites != 0) { if (suite_name) { char *results = CU_get_run_results_string(); write_suite_result_file(suite_name, results); CU_FREE(results); } else { merge_and_print_results_files(); } } else { char *results = CU_get_run_results_string(); bc_tester_printf(bc_printf_verbosity_info,"\n%s", results); CU_FREE(results); } #endif } static void suite_init_failure_message_handler(const CU_pSuite pSuite) { bc_tester_printf(bc_printf_verbosity_error,"Suite initialization failed for [%s]", pSuite->pName); } 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 : ""); bctbx_free(result); result = buffer; } } bc_tester_printf(bc_printf_verbosity_info,"%s", result); bctbx_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 // char *get_logfile_name(const char *base_name, const char *suite_name) { if (suite_name) { char *name_wo_spaces = bctbx_replace(bctbx_strdup(suite_name), ' ', '_'); char *ret = bc_sprintf("%s_%s.log", base_name, name_wo_spaces); bctbx_free(name_wo_spaces); return ret; } else { return strdup(base_name); } } //Get the junit xml file name for a specific suite or the global one //If passed to BCUnit, it will append "-Results.xml" to the name //Use `suffix` to match the resulting name if needed char *get_junit_xml_file_name(const char *suite_name, const char *suffix) { char *xml_tmp_file; if (suite_name) { int suiteIdx = bc_tester_suite_index(suite_name); if (suffix) { xml_tmp_file = bc_sprintf("%s_%d%s", xml_file, suiteIdx, suffix); } else { xml_tmp_file = bc_sprintf("%s_%d", xml_file, suiteIdx); } } else { if (suffix) { xml_tmp_file = bc_sprintf("%s%s", xml_file, suffix); } else { xml_tmp_file = bc_sprintf("%s", xml_file); } } return xml_tmp_file; } //In case tests are started in parallel. //Merge partial JUnit suites reports into the final XML file void merge_junit_xml_files(const char *dst_file_name) { char **suite_junit_xml_results; ssize_t total_size = 0; char *file_name; bctbx_vfs_file_t* bctbx_file; ssize_t read_bytes = 0, file_size = 0, offset = 0; int i; suite_junit_xml_results = malloc(sizeof(char *) * nb_test_suites); for (i = 0; i < nb_test_suites; i++) { file_name = get_junit_xml_file_name(test_suite[i]->name, "-Results.xml"); bctbx_file = bctbx_file_open2(bctbx_vfs_get_default(), file_name, O_RDONLY); if (bctbx_file != NULL) { file_size = (ssize_t)bctbx_file_size(bctbx_file); suite_junit_xml_results[i] = malloc(file_size + 1); read_bytes = bctbx_file_read(bctbx_file, (void *)suite_junit_xml_results[i], file_size, 0); if (read_bytes == file_size) { total_size += file_size; suite_junit_xml_results[i][file_size] = '\0'; } else { bc_tester_printf(bc_printf_verbosity_error, "Could not read JUnit XML file '%s' to merge", file_name); bctbx_free(suite_junit_xml_results[i]); suite_junit_xml_results[i] = NULL; } } else { bc_tester_printf(bc_printf_verbosity_error, "Could not open JUnit XML file '%s' to merge", file_name); } bctbx_file_close(bctbx_file); //Also remove the file remove(file_name); bctbx_free(file_name); } //Empty the destination file bctbx_file = bctbx_file_open(bctbx_vfs_get_default(), dst_file_name, "w+"); bctbx_file_truncate(bctbx_file, 0); offset = bctbx_file_fprintf(bctbx_file, 0, "\n\n"); for (i = 0; i < nb_test_suites; i++) { if (suite_junit_xml_results[i] != NULL) { offset += bctbx_file_fprintf(bctbx_file, offset, suite_junit_xml_results[i]); bctbx_free(suite_junit_xml_results[i]); } } bctbx_file_fprintf(bctbx_file, offset, "\n"); bctbx_file_close(bctbx_file); bctbx_free(suite_junit_xml_results); } //In case tests are started in parallel AND --log-file was given //Merge individual suite log file into a global one void merge_log_files(const char *base_logfile_name) { bctbx_vfs_file_t* dst_file; bctbx_vfs_file_t* bctbx_file; void *buf; ssize_t offset = 0, file_size = 0, read_bytes = 0; int i; dst_file = bctbx_file_open(bctbx_vfs_get_default(), base_logfile_name, "w+"); if (!dst_file) { bc_tester_printf(bc_printf_verbosity_error, "Failed to create target log file '%s'", base_logfile_name); return; } for (i = 0; i < nb_test_suites; ++i) { char *suite_logfile_name = get_logfile_name(log_file_name, test_suite[i]->name); bctbx_file = bctbx_file_open2(bctbx_vfs_get_default(), suite_logfile_name, O_RDONLY); if (!bctbx_file) { bc_tester_printf(bc_printf_verbosity_error, "Could not open log file '%s' to merge into '%s'", suite_logfile_name, base_logfile_name); continue; } file_size = (ssize_t)bctbx_file_size(bctbx_file); buf = malloc(file_size); read_bytes = bctbx_file_read(bctbx_file, buf, file_size, 0); if (read_bytes == file_size) { offset += bctbx_file_write(dst_file, buf, file_size, offset); } else { bc_tester_printf(bc_printf_verbosity_error, "Could not read log file '%s' to merge into '%s'", suite_logfile_name, base_logfile_name); } bctbx_file_close(bctbx_file); bctbx_free(suite_logfile_name); bctbx_free(buf); } bctbx_file_close(dst_file); } //Number of test suites to run concurrently //TODO better default or add cli option ? int bc_tester_get_max_parallel_processes(void) { return (nb_test_suites / 2) + 1; } #ifdef _WIN32 void kill_sub_processes(int *pids) { // TODO: Windows support } #else //If there was an error, kill zombies void kill_sub_processes(int *pids) { int i; for (i = 0; i < nb_test_suites; ++i) { if (pids[i] > 0) { kill(pids[i], SIGTERM); } } } #endif #ifdef _WIN32 int start_sub_process(const char *suite_name) { //TODO Windows support return 0; } #else //Start test subprocess for the given suite int start_sub_process(const char *suite_name) { int argc = 0; int i; const char *argv[origin_argc + 10]; //Assume safey 10 more parameters argv[argc++] = origin_argv[0]; for (i = 1; origin_argv[i]; ++i) { if (strcmp(origin_argv[i], "--verbose") == 0) { argv[argc++] = origin_argv[i]; } else if (strcmp(origin_argv[i], "--silent") == 0) { argv[argc++] = origin_argv[i]; } else if (strcmp(origin_argv[i], "--log-file") == 0) { //Create a specific log file for this suite argv[argc++] = origin_argv[i++]; argv[argc++] = get_logfile_name(log_file_name, suite_name); } else if (strcmp(origin_argv[i], "--xml-file") == 0) { argv[argc++] = origin_argv[i++]; argv[argc++] = origin_argv[i]; } else if (strcmp(origin_argv[i], "--parallel") == 0) { argv[argc++] = origin_argv[i]; } else { //Keep unknown parameters argv[argc++] = origin_argv[i]; } } argv[argc++] = "--xml"; argv[argc++] = "--suite"; argv[argc++] = suite_name; argv[argc] = NULL; return execv(argv[0], (char **) argv); } #endif //For parallel tests only - handle anormally exited test suites //Remove previously generated XML suite file if exited anormally (could cause unusable final JUnit XML) //And mark all tests for the suite as failed int handle_sub_process_error(int pid, int exitStatus, int *suitesPids) { if (abs(exitStatus) > 1) { int i, j; for (i = 0; i < nb_test_suites; ++i) { if (suitesPids[i] == pid) { ssize_t offset; char *suite_file_name = get_junit_xml_file_name(test_suite[i]->name, "-Results.xml"); bctbx_vfs_file_t* bctbx_file = bctbx_file_open(bctbx_vfs_get_default(), suite_file_name, "w+"); bctbx_file_truncate(bctbx_file, 0); offset = bctbx_file_fprintf(bctbx_file, 0, "\n\n", test_suite[i]->name, test_suite[i]->nb_tests, test_suite[i]->nb_tests); for (j=0; j < test_suite[i]->nb_tests; ++j) { offset += bctbx_file_fprintf(bctbx_file, offset, "\t\n", test_suite[i]->name, test_suite[i]->tests[j].name); offset += bctbx_file_fprintf(bctbx_file, offset, "\t\t\n\t\tGlobal suite failure\n"); offset += bctbx_file_fprintf(bctbx_file, offset, "\t\t\n\t\n"); } bctbx_file_fprintf(bctbx_file, offset, "\n\n"); bc_tester_printf(bc_printf_verbosity_info, "Suite '%s' ended in error. Marking all tests as failed", test_suite[i]->name); bctbx_file_close(bctbx_file); bctbx_free(suite_file_name); } } } return exitStatus; } #ifdef _WIN32 //TODO Windows support int bc_tester_run_parallel(void) { return 0; } #else int bc_tester_run_parallel(void) { int suitesPids[nb_test_suites]; uint64_t time_start = bctbx_get_cur_time_ms(), elapsed = time_start, print_timer = time_start; //Assume there is a problem if a suite is still running 60mn after the start of the tester. TODO make timeout a cli parameter ? uint64_t timeout = 0; if (globalTimeout <= 0) { globalTimeout = 60; } timeout = time_start + (globalTimeout * 60 * 1000); int maxProcess = bc_tester_get_max_parallel_processes(); int nextSuite = 0; //Next suite id to be exec'd int runningSuites = 0; //Number of currently running suites int testsFinished = 0; int ret = 0; //Global return status; memset(suitesPids, 0, sizeof(suitesPids)); do { if (nextSuite < nb_test_suites && runningSuites < maxProcess) { int pid = fork(); if (pid == -1) { bc_tester_printf(bc_printf_verbosity_error, "Error during fork() while starting child process. Aborting."); return -1; } else if (pid > 0) { suitesPids[nextSuite] = pid; runningSuites++; nextSuite++; } else { if (start_sub_process(test_suite[nextSuite]->name) == -1) { bc_tester_printf(bc_printf_verbosity_error, "Error while starting suite sub-process. Aborting."); return -1; } } } if (runningSuites > 0) { int wstatus, childPid, childRet; if ((childPid = waitpid(-1, &wstatus, WNOHANG)) == -1) { bc_tester_printf(bc_printf_verbosity_error, "Error during waitpid() while waiting for child process. Aborting."); return -1; } if (childPid != 0) { if (WIFEXITED(wstatus) || WIFSIGNALED(wstatus)) { --runningSuites; ++testsFinished; } if (WIFSIGNALED(wstatus)) { childRet = WTERMSIG(wstatus); } else { childRet = WEXITSTATUS(wstatus); } handle_sub_process_error(childPid, childRet, suitesPids); if (ret == 0 && childRet != 0) { ret = childRet; } bc_tester_printf(bc_printf_verbosity_error, "Suite sub process (pid %d) terminated with return code %d.", childPid, childRet); } } bctbx_sleep_ms(50); if (elapsed - print_timer > 10000) { //print message only every ~10s... bc_tester_printf(bc_printf_verbosity_error, "Waiting for test suites to finish... Total Suites(%d). Suites running(%d), Finished(%d)", nb_test_suites, runningSuites, testsFinished); print_timer = bctbx_get_cur_time_ms(); } elapsed = bctbx_get_cur_time_ms(); } while (testsFinished < nb_test_suites && elapsed < timeout); if (elapsed >= timeout) { bc_tester_printf(bc_printf_verbosity_error, "Stopped waiting for all test suites to execute as we reach timeout. Killing running suites."); kill_sub_processes(suitesPids); } bc_tester_printf(bc_printf_verbosity_info, "All suites ended."); all_complete_message_handler(NULL); { int seconds = (int)(elapsed - time_start)/1000; bc_tester_printf(bc_printf_verbosity_info, "Full parallel run completed in %2i mn %2i s.\n", seconds/60, seconds % 60); } return ret; } #endif int bc_tester_run_tests(const char *suite_name, const char *test_name, const char *tag_name) { int ret = 0; if ((ret = bc_tester_register_suites()) != 0) { return ret; } #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) { char *xml_file_name; CU_automated_enable_junit_xml(TRUE); /* this requires 3.0.1 because previous versions crash automated.c */ if (parallel_suites != 0) { //Sub-process started by parent in bc_tester_run_parallel if (suite_name) { CU_automated_enable_partial_junit(TRUE); xml_file_name = get_junit_xml_file_name(suite_name, NULL); CU_set_output_filename(xml_file_name); bctbx_free(xml_file_name); CU_automated_run_tests(); } else { //Starting registered suites in parallel ret = bc_tester_run_parallel(); xml_file_name = get_junit_xml_file_name(NULL, "-Results.xml"); merge_junit_xml_files(xml_file_name); bctbx_free(xml_file_name); if (log_file_name) { merge_log_files(log_file_name); } return ret; } } else { //Classic, non-parallel run xml_file_name = get_junit_xml_file_name(NULL, NULL); CU_set_output_filename(xml_file_name); CU_automated_run_tests(); bctbx_free(xml_file_name); } return CU_get_number_of_tests_failed() != 0; } #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); bctbx_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); } bctbx_free(progpath2); } if (installed_resources_path != NULL) bctbx_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); bctbx_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); } bctbx_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); } bctbx_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) { bctbx_free(progpath); } if(progname) { bctbx_free(progname); } } //Default function for the `--verbose`cli option int bc_tester_verbose_handler(const char *arg) { bctbx_set_log_level(BCTBX_LOG_DOMAIN, BCTBX_LOG_DEBUG); return 0; } //Default function for the `--silent` cli option int bc_tester_silent_handler(const char *arg) { bctbx_set_log_level(BCTBX_LOG_DOMAIN, BCTBX_LOG_FATAL); return 0; } //Default function for the `--log-file`cli option int bc_tester_logfile_handler(const char *arg) { int res = 0; char *dir = bctbx_dirname(arg); char *base = bctbx_basename(arg); bctbx_log_handler_t *filehandler = bctbx_create_file_log_handler(0, dir, base); if (filehandler == NULL) { res = -1; goto end; } bctbx_add_log_handler(filehandler); end: bctbx_free(dir); bctbx_free(base); return res; } 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) { //Set default cli arguments handlers for --silent, --verbose, --log-file if undefined if (silent_arg_func == NULL) { silent_arg_func = bc_tester_silent_handler; } if (verbose_arg_func == NULL) { verbose_arg_func = bc_tester_verbose_handler; } if (logfile_arg_func == NULL) { logfile_arg_func = bc_tester_logfile_handler; } 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--verbose\n" "\t\t\t--silent\n" "\t\t\t--log-file \n" "\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" "\t\t\t--max-alloc (maximum amount of memory obtained via malloc allocator)\n" "\t\t\t--parallel (Execute tests concurrently and with JUnit report)\n" "\t\t\t--timeout (sets the global timeout when used alongside to the parallel option, the default value is 60)\n" "And additionally:\n" "%s", name, additionnal_helper); } int bc_tester_parse_args(int argc, char **argv, int argid) { int ret = 0; int i = argid; if (strcmp(argv[i],"--help")==0){ return -1; } else if (strcmp(argv[i],"--log-file")==0) { CHECK_ARG("--log-file", ++i, argc); ret = logfile_arg_func(argv[i]); if (ret < 0) return ret; log_file_name = argv[i]; } else if (strcmp(argv[i],"--silent")==0) { ret = silent_arg_func(argv[i]); if (ret < 0) return ret; } else if (strcmp(argv[i],"--verbose")==0) { ret = verbose_arg_func(argv[i]); if (ret < 0) return ret; } 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], "--parallel") == 0) { //Keep record of cli args for subprocesses if (!origin_argv) { origin_argv = argv; origin_argc = argc; } //Defaults to JUnit report if parallel is enabled xml_enabled = 1; parallel_suites = 1; } else if (strcmp(argv[i], "--timeout") == 0) { CHECK_ARG("--timeout", ++i, argc); globalTimeout = atoi(argv[i]); } 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; } /* returns number of arguments read + 1 */ return i - argid + 1; } //Init BCUnit and register suites and/or tests into internal BCUnit registry before actual BCUnit test launch int bc_tester_register_suites(void) { //Assume everything is already setup if BCUnit registry exists if (CU_registry_initialized()) { return 0; } if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error(); if (suite_name != NULL) { int suiteIdx = bc_tester_suite_index(suite_name); if (suiteIdx == -1) { bc_tester_printf(bc_printf_verbosity_error, "Suite with name \"%s\" not found. Available suites are: ", suite_name); bc_tester_list_suites(); return -1; } bc_tester_register_suite(test_suite[suiteIdx], tag_name); } else { int i; for (i = 0; i < nb_test_suites; i++) { bc_tester_register_suite(test_suite[i], tag_name); } } return 0; } 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); 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 (test_suite != NULL) { bctbx_free(test_suite); test_suite = NULL; nb_test_suites = 0; } if (bc_tester_resource_dir_prefix != NULL) { bctbx_free(bc_tester_resource_dir_prefix); bc_tester_resource_dir_prefix = NULL; } if (bc_tester_writable_dir_prefix != NULL) { bctbx_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) bctbx_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) { bctbx_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-4.4.13/src/utils.h000066400000000000000000000014141375717307100157110ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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 "bctoolbox/port.h"bctoolbox-4.4.13/src/utils/000077500000000000000000000000001375717307100155405ustar00rootroot00000000000000bctoolbox-4.4.13/src/utils/exception.cc000066400000000000000000000062031375717307100200460ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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 // ifdef HAVE_CONFIG_H #ifdef HAVE_EXECINFO #include #include #include #include #include #endif #include "bctoolbox/exception.hh" #include "bctoolbox/logging.h" using namespace std; #ifdef HAVE_EXECINFO static void uncaught_handler() { std::exception_ptr p = current_exception(); try { rethrow_exception(p); } catch (BctbxException &e) { BCTBX_SLOGE << e; } catch (std::exception &ee) { BCTBX_SLOGE << "Unexpected exception [" << ee.what() << " ] use BctbxException for better debug"; } abort(); } #endif BctbxException::BctbxException(const std::string &message) : mSize(0) { #ifdef HAVE_EXECINFO mSize = backtrace(mArray, sizeof(mArray) / sizeof(void *)); #else mSize = 0; #endif if (!message.empty()) mOs << message; #ifdef HAVE_EXECINFO #if __clang if (get_terminate() != uncaught_handler) #endif set_terminate(uncaught_handler); // invoke in case of uncautch exception for this thread #endif } BctbxException::BctbxException(const BctbxException &other) : mSize(other.mSize) { memcpy(mArray, other.mArray, sizeof(mArray)); mOs << other.str(); } void BctbxException::printStackTrace() const { #ifdef HAVE_EXECINFO backtrace_symbols_fd(mArray + 1, mSize - 1, STDERR_FILENO); #else std::cerr << "stack trace not available on this platform" << std::endl; #endif } void BctbxException::printStackTrace(std::ostream &os) const { #ifdef HAVE_EXECINFO char **bt = backtrace_symbols(mArray, mSize); int position=0; for (unsigned int i = 1; 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); #else os << "stack trace not available on this platform"; #endif } const char *BctbxException::what() const noexcept { return str().c_str(); } const std::string& BctbxException::str() const { mMessage = mOs.str(); return mMessage; } std::ostream &operator<<(std::ostream &__os, const BctbxException &e) { __os << e.str() << std::endl; e.printStackTrace(__os); return __os; } bctoolbox-4.4.13/src/utils/ios_utils.mm000066400000000000000000000063761375717307100201210ustar00rootroot00000000000000/* * Copyright (c) 2010-2019 Belledonne Communications SARL. * * This file is part of Liblinphone. * * 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 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 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 __APPLE__ #import #include #include "bctoolbox/ios_utils.hh" #include "bctoolbox/exception.hh" #include "bctoolbox/logging.h" #include "ios_utils_stub.hh" namespace bctoolbox { std::unique_ptr IOSUtils::sInstance = nullptr; IOSUtils& IOSUtils::getUtils() { if (!sInstance) { sInstance = std::unique_ptr(new IOSUtils); } return *sInstance; } IOSUtils::IOSUtils() { if (isApp()) { openDynamicLib(); using create_t = IOSUtilsInterface *(*)(); auto createUtils = reinterpret_cast(loadSymbol("bctbx_create_ios_utils_app")); mUtils = createUtils(); } else { mUtils = new IOSUtilsStub(); } } IOSUtils::~IOSUtils() { if (isApp()) { using destroy_t = void (*)(IOSUtilsInterface *); auto destroyUtils = reinterpret_cast(loadSymbol("bctbx_destroy_ios_utils_app")); destroyUtils(mUtils); dlclose(mHandle); } else { delete mUtils; } } bool IOSUtils::isApp() { return [[[NSBundle mainBundle] bundlePath] hasSuffix:@".app"]; } void IOSUtils::openDynamicLib() { NSString *frameworkPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingString: @"/Frameworks/bctoolbox-ios.framework/bctoolbox-ios"]; const char *frameworkChar = [frameworkPath cStringUsingEncoding:[NSString defaultCStringEncoding]]; mHandle = dlopen(frameworkChar, RTLD_LAZY); if (!mHandle) { throw BCTBX_EXCEPTION << "bctoolbox error dlopen : " << dlerror(); } // reset errors dlerror(); } void *IOSUtils::loadSymbol(const char *symbol) { void *loadedSymbol = dlsym(mHandle, symbol); const char *dlsym_error = dlerror(); if (dlsym_error) { std::string error = dlsym_error; dlclose(mHandle); throw BCTBX_EXCEPTION << "bctoolbox error dlsym : " << error; } return loadedSymbol; } unsigned long IOSUtils::beginBackgroundTask(const char *name, std::function cb) { return mUtils->beginBackgroundTask(name, cb); } void IOSUtils::endBackgroundTask(unsigned long id) { return mUtils->endBackgroundTask(id); } bool IOSUtils::isApplicationStateActive() { return mUtils->isApplicationStateActive(); } unsigned long IOSUtilsStub::beginBackgroundTask(const char *name, std::function cb) { return 0; } void IOSUtilsStub::endBackgroundTask(unsigned long id) {} bool IOSUtilsStub::isApplicationStateActive() { return false; } } //namespace bctoolbox #endif bctoolbox-4.4.13/src/utils/ios_utils_app.hh000066400000000000000000000021171375717307100207340ustar00rootroot00000000000000/* * Copyright (c) 2010-2019 Belledonne Communications SARL. * * This file is part of Liblinphone. * * 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 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 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 . */ #pragma once #include "bctoolbox/ios_utils.hh" namespace bctoolbox { class IOSUtilsApp : public IOSUtilsInterface { public: unsigned long beginBackgroundTask(const char *name, std::function cb) override; void endBackgroundTask(unsigned long id) override; bool isApplicationStateActive() override; }; } //namespace bctoolbox bctoolbox-4.4.13/src/utils/ios_utils_app.mm000066400000000000000000000075241375717307100207550ustar00rootroot00000000000000/* * Copyright (c) 2010-2019 Belledonne Communications SARL. * * This file is part of Liblinphone. * * 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 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 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 #if TARGET_OS_IPHONE #include #include #include "ios_utils_app.hh" #include "bctoolbox/logging.h" namespace bctoolbox { unsigned long IOSUtilsApp::beginBackgroundTask(const char *name, std::function cb) { __block UIBackgroundTaskIdentifier bgid = UIBackgroundTaskInvalid; dispatch_block_t block = ^{ UIApplication *app=[UIApplication sharedApplication]; @try { if (cb==nullptr){ bctbx_error("belle_sip_begin_background_task(): the callback must not be NULL. Application must be aware that the background task needs to be terminated."); bgid = UIBackgroundTaskInvalid; @throw([NSException exceptionWithName:@"LinphoneCoreException" reason:@"Background task has no callback" userInfo:nil]); } void (^handler)() = ^{ cb(); }; if([app respondsToSelector:@selector(beginBackgroundTaskWithName:expirationHandler:)]){ bgid = [app beginBackgroundTaskWithName:[NSString stringWithUTF8String:name] expirationHandler:handler]; } else { bgid = [app beginBackgroundTaskWithExpirationHandler:handler]; } if (bgid==UIBackgroundTaskInvalid){ bctbx_error("Could not start background task %s.", name); bgid = 0; @throw([NSException exceptionWithName:@"LinphoneCoreException" reason:@"Could not start background task" userInfo:nil]); } // backgroundTimeRemaining is properly set only when running background... but not immediately! if (app.applicationState != UIApplicationStateBackground || (app.backgroundTimeRemaining == DBL_MAX)) { bctbx_message("Background task %s started. Unknown remaining time since application is not fully in background.", name); } else { bctbx_message("Background task %s started. Remaining time %.1f secs", name, app.backgroundTimeRemaining); } } @catch (NSException*) { // do nothing } }; if( [NSThread isMainThread] ) { block(); } else { dispatch_sync(dispatch_get_main_queue(), block); } return (unsigned long)bgid; } void IOSUtilsApp::endBackgroundTask(unsigned long id) { dispatch_block_t block = ^{ UIApplication *app=[UIApplication sharedApplication]; if (id != UIBackgroundTaskInvalid){ [app endBackgroundTask:(UIBackgroundTaskIdentifier)id]; } }; if( [NSThread isMainThread] ) { block(); } else { dispatch_sync(dispatch_get_main_queue(), block); } } bool IOSUtilsApp::isApplicationStateActive() { return ([UIApplication sharedApplication].applicationState == UIApplicationStateActive); } } //namespace bctoolbox extern "C" { bctoolbox::IOSUtilsInterface *bctbx_create_ios_utils_app() { return new bctoolbox::IOSUtilsApp; } void bctbx_destroy_ios_utils_app(bctoolbox::IOSUtilsInterface* p) { delete p; } } #endif bctoolbox-4.4.13/src/utils/ios_utils_stub.hh000066400000000000000000000021201375717307100211230ustar00rootroot00000000000000/* * Copyright (c) 2010-2019 Belledonne Communications SARL. * * This file is part of Liblinphone. * * 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 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 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 . */ #pragma once #include "bctoolbox/ios_utils.hh" namespace bctoolbox { class IOSUtilsStub : public IOSUtilsInterface { public: unsigned long beginBackgroundTask(const char *name, std::function cb) override; void endBackgroundTask(unsigned long id) override; bool isApplicationStateActive() override; }; } //namespace bctoolbox bctoolbox-4.4.13/src/utils/port.c000066400000000000000000001431621375717307100166770ustar00rootroot00000000000000 /* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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/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 = strrchr(path, '/'); if (ptr == NULL) ptr = strrchr(path, '\\'); return ptr ? bctbx_strndup(path, ptr-path) : bctbx_strdup("."); } char * bctbx_basename(const char *path) { char *ptr = strrchr(path, '/'); if (ptr == NULL) ptr = strrchr(path, '\\'); if (ptr == NULL) return bctbx_strdup(path); 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); } bool_t bctbx_directory_exists(const char *pathname) { struct stat sb; #ifdef WIN32 return stat(pathname, &sb) == 0 && (_S_IFDIR & sb.st_mode); #else return stat(pathname, &sb) == 0 && S_ISDIR(sb.st_mode); #endif } #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) #if defined(BCTBX_WINDOWS_DESKTOP) && !defined(ENABLE_MICROSOFT_STORE_APP) 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){ #if 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"); # ifdef HAVE_ARC4RANDOM return arc4random(); // fallback to arc4random(). # endif #elif defined(HAVE_ARC4RANDOM) return arc4random(); #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); } struct addrinfo* bctbx_addrinfo_sort(struct addrinfo *ais) { bctbx_list_t* v6 = NULL; bctbx_list_t* v4_mapped = NULL; bctbx_list_t* v4 = NULL; bctbx_list_t *it = NULL; struct addrinfo* res0 = NULL; struct addrinfo* res = NULL; struct addrinfo* ai = NULL; //sort by type for (ai = ais; ai != NULL; ) { struct addrinfo* next = ai->ai_next; struct sockaddr_in6 *sock_in6 = (struct sockaddr_in6 *)ai->ai_addr; if (ai->ai_family == AF_INET6) { if (IN6_IS_ADDR_V4MAPPED(&sock_in6->sin6_addr)) { v4_mapped = bctbx_list_prepend(v4_mapped, ai); } else { v6 = bctbx_list_prepend(v6, ai); } } else { v4 = bctbx_list_prepend(v4, ai); } ai->ai_next = NULL ; ai = next; } v6 = bctbx_list_concat(v6, v4_mapped); v6 = bctbx_list_concat(v6, v4); for (it = v6; it != NULL; it = it->next) { if (res0 == NULL) { res0 = res = (struct addrinfo*)it->data; } else { res->ai_next = (struct addrinfo*)it->data; res = res->ai_next; } } if (res) res->ai_next = NULL; bctbx_list_free(v6); return res0; } 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; } //sort result if (res) res = bctbx_addrinfo_sort(res); return res; } struct addrinfo * bctbx_name_to_addrinfo(int family, int socktype, const char *name, int port){ struct addrinfo * res = NULL; #if defined(__ANDROID__) // This is to workaround possible ANR on Android /*"main" prio=5 tid=1 Native | group="main" sCount=1 dsCount=0 obj=0x75d55258 self=0x231c03fa00 | sysTid=27931 nice=-10 cgrp=default sched=0/0 handle=0x2320165a98 | state=S schedstat=( 0 0 0 ) utm=303 stm=69 core=1 HZ=100 | stack=0x48ae2c5000-0x48ae2c7000 stackSize=8MB | held mutexes= kernel: __switch_to+0x70/0x7c kernel: unix_stream_recvmsg+0x254/0x6f8 kernel: sock_aio_read.part.9+0xe4/0x110 kernel: sock_aio_read+0x20/0x30 kernel: do_sync_read+0x70/0xa8 kernel: vfs_read+0xb0/0x140 kernel: SyS_read+0x54/0xa4 kernel: el0_svc_naked+0x24/0x28 native: #00 pc 000000000006b6e4 /system/lib64/libc.so (read+4) native: #01 pc 00000000000731f8 /system/lib64/libc.so (__sread+44) native: #02 pc 0000000000076fac /system/lib64/libc.so (__srefill+260) native: #03 pc 0000000000076e00 /system/lib64/libc.so (fread+272) native: #04 pc 000000000002fcf0 /system/lib64/libc.so (android_getaddrinfofornetcontext+2356) native: #05 pc 000000000002f33c /system/lib64/libc.so (getaddrinfo+56) native: #06 pc 000000000001e754 /data/app/com.meetme-1/lib/arm64/libbctoolbox.so (bctbx_getaddrinfo+164) native: #07 pc 000000000001ecb4 /data/app/com.meetme-1/lib/arm64/libbctoolbox.so (???) native: #08 pc 0000000000018edc /data/app/com.meetme-1/lib/arm64/libortp.so (???) native: #09 pc 000000000009dd10 /data/app/com.meetme-1/lib/arm64/libmediastreamer_voip.so (audio_stream_start_from_io+132) native: #10 pc 00000000007948d0 /data/app/com.meetme-1/lib/arm64/liblinphone.so (_ZN15LinphonePrivate19MediaSessionPrivate16startAudioStreamENS_11CallSession5StateEb+3508) native: #11 pc 00000000007956e8 /data/app/com.meetme-1/lib/arm64/liblinphone.so (_ZN15LinphonePrivate19MediaSessionPrivate12startStreamsENS_11CallSession5StateE+944) native: #12 pc 00000000007839cc /data/app/com.meetme-1/lib/arm64/liblinphone.so (_ZN15LinphonePrivate19MediaSessionPrivate13updateStreamsEP19SalMediaDescriptionNS_11CallSession5StateE+692) native: #13 pc 000000000078513c /data/app/com.meetme-1/lib/arm64/liblinphone.so (_ZN15LinphonePrivate19MediaSessionPrivate13remoteRingingEv+932) native: #14 pc 0000000000852f9c /data/app/com.meetme-1/lib/arm64/liblinphone.so (???) native: #15 pc 00000000007d79c4 /data/app/com.meetme-1/lib/arm64/liblinphone.so (_ZN15LinphonePrivate9SalCallOp17processResponseCbEPvPK24belle_sip_response_event+788) native: #16 pc 00000000007e4bb4 /data/app/com.meetme-1/lib/arm64/liblinphone.so (_ZN15LinphonePrivate3Sal22processResponseEventCbEPvPK24belle_sip_response_event+1092) native: #17 pc 00000000008fdd2c /data/app/com.meetme-1/lib/arm64/liblinphone.so (belle_sip_client_transaction_notify_response+520) native: #18 pc 00000000008f7494 /data/app/com.meetme-1/lib/arm64/liblinphone.so (belle_sip_provider_dispatch_message+1376) native: #19 pc 00000000008e0760 /data/app/com.meetme-1/lib/arm64/liblinphone.so (???) native: #20 pc 00000000008dee1c /data/app/com.meetme-1/lib/arm64/liblinphone.so (belle_sip_channel_process_data+344) native: #21 pc 00000000008d5b10 /data/app/com.meetme-1/lib/arm64/liblinphone.so (belle_sip_main_loop_run+772) native: #22 pc 00000000008d5d54 /data/app/com.meetme-1/lib/arm64/liblinphone.so (belle_sip_main_loop_sleep+72) native: #23 pc 000000000086b9f8 /data/app/com.meetme-1/lib/arm64/liblinphone.so (linphone_core_iterate+540) native: #24 pc 00000000000743c8 /data/app/com.meetme-1/oat/arm64/base.odex (Java_org_linphone_core_CoreImpl_iterate__J+132)*/ res = _bctbx_name_to_addrinfo(family, socktype, name, port, TRUE); #endif if (res == NULL) { res = _bctbx_name_to_addrinfo(family, socktype, name, port, FALSE); } return res; } 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_replace(char *str, char c, char n) { char *s = str; while (*s) { if (*s == c) { *s = n; } ++s; } return str; } 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]))); } #if defined(__ANDROID__) int mblen(const char* s, size_t n) { mbstate_t state = {}; return (int)mbrlen(s, n, &state); } int wctomb(char *s, wchar_t wc) { return wcrtomb(s,wc,NULL); } #endif bctoolbox-4.4.13/src/utils/regex.cc000066400000000000000000000044221375717307100171630ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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 "bctoolbox/logging.h" #include "bctoolbox/regex.h" /* This part is needed since CentOS7 have an old gcc compiler. TODO: Remove this code when all supported platorms have gcc 4.9.0 or more */ #if __cplusplus >= 201103L && \ (!defined(__GLIBCXX__) || (__cplusplus >= 201402L) || \ (defined(_GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIT) || \ defined(_GLIBCXX_REGEX_STATE_LIMIT) || \ (defined(_GLIBCXX_RELEASE) && \ _GLIBCXX_RELEASE > 4))) && \ !defined(__ANDROID__) || defined(_WIN32) #define HAVE_WORKING_REGEX 1 #else #define HAVE_WORKING_REGEX 0 #include #endif extern "C" bool_t bctbx_is_matching_regex(const char *entry, const char* regex) { #if HAVE_WORKING_REGEX try { std::regex entry_regex(regex, std::regex_constants::extended | std::regex_constants::nosubs); std::cmatch m; return std::regex_match(entry, m, entry_regex); } catch (const std::regex_error& e) { bctbx_error("Could not compile regex '%s': %s", regex, e.what()); return FALSE; } #else regex_t regex_pattern; char err_msg[256]; int res; res = regcomp(®ex_pattern, regex, REG_EXTENDED | REG_NOSUB); if(res != 0) { regerror(res, ®ex_pattern, err_msg, sizeof(err_msg)); bctbx_error("Could not compile regex '%s': %s", regex, err_msg); return FALSE; } res = regexec(®ex_pattern, entry, 0, NULL, 0); regfree(®ex_pattern); return (res != REG_NOMATCH); #endif } bctoolbox-4.4.13/src/vconnect.c000066400000000000000000000126641375717307100163740ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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/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-4.4.13/src/vfs.c000066400000000000000000000306661375717307100153550ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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/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-4.4.13/tester/000077500000000000000000000000001375717307100151175ustar00rootroot00000000000000bctoolbox-4.4.13/tester/CMakeLists.txt000066400000000000000000000046151375717307100176650ustar00rootroot00000000000000############################################################################ # CMakeLists.txt # Copyright (C) 2020 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(ENABLE_TESTS AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") set(TESTER_SOURCES bctoolbox_tester.c bctoolbox_tester.h containers.cc port.c parser.c ) if(MBEDTLS_FOUND OR POLARSSL_FOUND) list(APPEND TESTER_SOURCES crypto.c) endif() if(APPLE) list(APPEND TESTER_SOURCES ios_utils.cc) endif() 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}) target_include_directories(bctoolbox_tester_exe PRIVATE ${MBEDTLS_INCLUDE_DIRS}) endif() if(POLARSSL_FOUND) target_link_libraries(bctoolbox_tester_exe PRIVATE ${POLARSSL_LIBRARIES}) endif() if(DECAF_FOUND) target_link_libraries(bctoolbox_tester_exe PRIVATE ${DECAF_TARGETNAME}) endif() set_target_properties(bctoolbox_tester_exe PROPERTIES XCODE_ATTRIBUTE_WARNING_CFLAGS "") add_test(NAME bctoolbox_tester COMMAND bctoolbox_tester --verbose) endif() bctoolbox-4.4.13/tester/bctoolbox_tester.c000066400000000000000000000066211375717307100206510ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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 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 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); #if (HAVE_MBEDTLS | HAVE_POLARSSL) bc_tester_add_suite(&crypto_test_suite); #endif bc_tester_add_suite(&parser_test_suite); #ifdef __APPLE__ bc_tester_add_suite(&ios_utils_test_suite); #endif } void bctoolbox_tester_uninit(void) { bc_tester_uninit(); } void bctoolbox_tester_before_each() { } int bctoolbox_tester_set_log_file(const char *filename) { int res = 0; char* dir = bctbx_dirname(filename); char* base = bctbx_basename(filename); bctbx_message("Redirecting traces to file [%s]", filename); bctbx_log_handler_t *filehandler = bctbx_create_file_log_handler(0, dir, base); if (filehandler == NULL) { res = -1; goto end; } bctbx_add_log_handler(filehandler); end: bctbx_free(dir); bctbx_free(base); return res; } #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-4.4.13/tester/bctoolbox_tester.h000066400000000000000000000025241375717307100206540ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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 crypto_test_suite; extern test_suite_t parser_test_suite; extern test_suite_t ios_utils_test_suite; #ifdef __cplusplus }; #endif #endif /* _BCTOOLBOX_TESTER_H */ bctoolbox-4.4.13/tester/containers.cc000066400000000000000000000147471375717307100176100ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "bctoolbox_tester.h" #include "bctoolbox/crypto.h" #ifdef HAVE_MBEDTLS /* used to cross test ECDH25519 */ #include "mbedtls/ecdh.h" #endif /* HAVE_MBEDTLS */ static void DHM(void) { int i; bctbx_DHMContext_t *alice,*bob; bctbx_rng_context_t *RNG; uint8_t availableAlgos[2]={BCTBX_DHM_2048, BCTBX_DHM_3072}; uint8_t availableAlgosNb=2; /* Init the RNG */ RNG = bctbx_rng_context_new(); /* Get all the available DH algos */ //availableAlgosNb=bctbx_getDHMAvailableAlgos(availableAlgos); for (i=0; ipeer = (uint8_t *)malloc(keySize*sizeof(uint8_t)); memcpy(alice->peer,bob->self,keySize); bob->peer = (uint8_t *)malloc(keySize*sizeof(uint8_t)); memcpy(bob->peer,alice->self,keySize); /* compute shared secrets */ bctbx_DHMComputeSecret(alice, (int (*)(void *, uint8_t *, size_t))bctbx_rng_get, RNG); bctbx_DHMComputeSecret(bob, (int (*)(void *, uint8_t *, size_t))bctbx_rng_get, RNG); /* compare the secrets */ BC_ASSERT_TRUE(memcmp(alice->key,bob->key,keySize)==0); /* clear contexts */ bctbx_DestroyDHMContext(alice); bctbx_DestroyDHMContext(bob); } /* clear contexts */ bctbx_rng_context_free(RNG); } static void ECDH_exchange(bctbx_ECDHContext_t *alice, bctbx_ECDHContext_t *bob) { /* exchange public keys */ bctbx_ECDHSetPeerPublicKey(alice, bob->selfPublic, alice->pointCoordinateLength); bctbx_ECDHSetPeerPublicKey(bob, alice->selfPublic, bob->pointCoordinateLength); /* compute shared secrets */ bctbx_ECDHComputeSecret(alice, NULL, NULL); bctbx_ECDHComputeSecret(bob, NULL, NULL); /* compare the secrets */ BC_ASSERT_TRUE(memcmp(alice->sharedSecret, bob->sharedSecret, alice->pointCoordinateLength)==0); } static void ECDH(void) { if (!bctbx_crypto_have_ecc()) { bctbx_warning("test skipped as we don't have Elliptic Curve Cryptography in bctoolbox"); return; } /* Patterns */ uint8_t ECDHpattern_X25519_alicePrivate[] = {0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1, 0x72, 0x51, 0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a, 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a}; uint8_t ECDHpattern_X25519_alicePublic[] = {0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, 0x74, 0x8b, 0x7d, 0xdc, 0xb4, 0x3e, 0xf7, 0x5a, 0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38, 0x1a, 0xf4, 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a}; uint8_t ECDHpattern_X25519_bobPrivate[] = {0x5d, 0xab, 0x08, 0x7e, 0x62, 0x4a, 0x8a, 0x4b, 0x79, 0xe1, 0x7f, 0x8b, 0x83, 0x80, 0x0e, 0xe6, 0x6f, 0x3b, 0xb1, 0x29, 0x26, 0x18, 0xb6, 0xfd, 0x1c, 0x2f, 0x8b, 0x27, 0xff, 0x88, 0xe0, 0xeb}; uint8_t ECDHpattern_X25519_bobPublic[] = {0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3, 0x5b, 0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78, 0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f}; uint8_t ECDHpattern_X25519_sharedSecret[] = {0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1, 0x72, 0x8e, 0x3b, 0xf4, 0x80, 0x35, 0x0f, 0x25, 0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1, 0x9e, 0x33, 0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42}; uint8_t alicePublic_libSignalPattern[] = { 0x1b, 0xb7, 0x59, 0x66, 0xf2, 0xe9, 0x3a, 0x36, 0x91, 0xdf, 0xff, 0x94, 0x2b, 0xb2, 0xa4, 0x66, 0xa1, 0xc0, 0x8b, 0x8d, 0x78, 0xca, 0x3f, 0x4d, 0x6d, 0xf8, 0xb8, 0xbf, 0xa2, 0xe4, 0xee, 0x28}; uint8_t alicePrivate_libSignalPattern[] = { 0xc8, 0x06, 0x43, 0x9d, 0xc9, 0xd2, 0xc4, 0x76, 0xff, 0xed, 0x8f, 0x25, 0x80, 0xc0, 0x88, 0x8d, 0x58, 0xab, 0x40, 0x6b, 0xf7, 0xae, 0x36, 0x98, 0x87, 0x90, 0x21, 0xb9, 0x6b, 0xb4, 0xbf, 0x59}; uint8_t bobPublic_libSignalPattern[] = { 0x65, 0x36, 0x14, 0x99, 0x3d, 0x2b, 0x15, 0xee, 0x9e, 0x5f, 0xd3, 0xd8, 0x6c, 0xe7, 0x19, 0xef, 0x4e, 0xc1, 0xda, 0xae, 0x18, 0x86, 0xa8, 0x7b, 0x3f, 0x5f, 0xa9, 0x56, 0x5a, 0x27, 0xa2, 0x2f}; uint8_t bobPrivate_libSignalPattern[] = { 0xb0, 0x3b, 0x34, 0xc3, 0x3a, 0x1c, 0x44, 0xf2, 0x25, 0xb6, 0x62, 0xd2, 0xbf, 0x48, 0x59, 0xb8, 0x13, 0x54, 0x11, 0xfa, 0x7b, 0x03, 0x86, 0xd4, 0x5f, 0xb7, 0x5d, 0xc5, 0xb9, 0x1b, 0x44, 0x66}; uint8_t shared_libSignalPattern[] = { 0x32, 0x5f, 0x23, 0x93, 0x28, 0x94, 0x1c, 0xed, 0x6e, 0x67, 0x3b, 0x86, 0xba, 0x41, 0x01, 0x74, 0x48, 0xe9, 0x9b, 0x64, 0x9a, 0x9c, 0x38, 0x06, 0xc1, 0xdd, 0x7c, 0xa4, 0xc4, 0x77, 0xe6, 0x29}; uint8_t ECDHpattern_X448_alicePrivate[] = {0x9a, 0x8f, 0x49, 0x25, 0xd1, 0x51, 0x9f, 0x57, 0x75, 0xcf, 0x46, 0xb0, 0x4b, 0x58, 0x00, 0xd4, 0xee, 0x9e, 0xe8, 0xba, 0xe8, 0xbc, 0x55, 0x65, 0xd4, 0x98, 0xc2, 0x8d, 0xd9, 0xc9, 0xba, 0xf5, 0x74, 0xa9, 0x41, 0x97, 0x44, 0x89, 0x73, 0x91, 0x00, 0x63, 0x82, 0xa6, 0xf1, 0x27, 0xab, 0x1d, 0x9a, 0xc2, 0xd8, 0xc0, 0xa5, 0x98, 0x72, 0x6b}; uint8_t ECDHpattern_X448_alicePublic[] = {0x9b, 0x08, 0xf7, 0xcc, 0x31, 0xb7, 0xe3, 0xe6, 0x7d, 0x22, 0xd5, 0xae, 0xa1, 0x21, 0x07, 0x4a, 0x27, 0x3b, 0xd2, 0xb8, 0x3d, 0xe0, 0x9c, 0x63, 0xfa, 0xa7, 0x3d, 0x2c, 0x22, 0xc5, 0xd9, 0xbb, 0xc8, 0x36, 0x64, 0x72, 0x41, 0xd9, 0x53, 0xd4, 0x0c, 0x5b, 0x12, 0xda, 0x88, 0x12, 0x0d, 0x53, 0x17, 0x7f, 0x80, 0xe5, 0x32, 0xc4, 0x1f, 0xa0}; uint8_t ECDHpattern_X448_bobPrivate[] = {0x1c, 0x30, 0x6a, 0x7a, 0xc2, 0xa0, 0xe2, 0xe0, 0x99, 0x0b, 0x29, 0x44, 0x70, 0xcb, 0xa3, 0x39, 0xe6, 0x45, 0x37, 0x72, 0xb0, 0x75, 0x81, 0x1d, 0x8f, 0xad, 0x0d, 0x1d, 0x69, 0x27, 0xc1, 0x20, 0xbb, 0x5e, 0xe8, 0x97, 0x2b, 0x0d, 0x3e, 0x21, 0x37, 0x4c, 0x9c, 0x92, 0x1b, 0x09, 0xd1, 0xb0, 0x36, 0x6f, 0x10, 0xb6, 0x51, 0x73, 0x99, 0x2d}; uint8_t ECDHpattern_X448_bobPublic[] = {0x3e, 0xb7, 0xa8, 0x29, 0xb0, 0xcd, 0x20, 0xf5, 0xbc, 0xfc, 0x0b, 0x59, 0x9b, 0x6f, 0xec, 0xcf, 0x6d, 0xa4, 0x62, 0x71, 0x07, 0xbd, 0xb0, 0xd4, 0xf3, 0x45, 0xb4, 0x30, 0x27, 0xd8, 0xb9, 0x72, 0xfc, 0x3e, 0x34, 0xfb, 0x42, 0x32, 0xa1, 0x3c, 0xa7, 0x06, 0xdc, 0xb5, 0x7a, 0xec, 0x3d, 0xae, 0x07, 0xbd, 0xc1, 0xc6, 0x7b, 0xf3, 0x36, 0x09}; uint8_t ECDHpattern_X448_sharedSecret[] = {0x07, 0xff, 0xf4, 0x18, 0x1a, 0xc6, 0xcc, 0x95, 0xec, 0x1c, 0x16, 0xa9, 0x4a, 0x0f, 0x74, 0xd1, 0x2d, 0xa2, 0x32, 0xce, 0x40, 0xa7, 0x75, 0x52, 0x28, 0x1d, 0x28, 0x2b, 0xb6, 0x0c, 0x0b, 0x56, 0xfd, 0x24, 0x64, 0xc3, 0x35, 0x54, 0x39, 0x36, 0x52, 0x1c, 0x24, 0x40, 0x30, 0x85, 0xd5, 0x9a, 0x44, 0x9a, 0x50, 0x37, 0x51, 0x4a, 0x87, 0x9d}; int i; bctbx_ECDHContext_t *alice,*bob; bctbx_rng_context_t *RNG; uint8_t availableAlgos[2]={BCTBX_ECDH_X25519, BCTBX_ECDH_X448}; uint8_t availableAlgosNb=2; /********************************************************************/ /*** Do a random generation and exchange with all available algos ***/ /********************************************************************/ /* Init the RNG */ RNG = bctbx_rng_context_new(); for (i=0; isharedSecret, ECDHpattern_X25519_sharedSecret, 32)==0); /* clear contexts */ bctbx_DestroyECDHContext(alice); bctbx_DestroyECDHContext(bob); /********************************************************************/ /*** Run an key derivation and exchange using patterns from RFC7748 */ /********************************************************************/ /*** Run it on the X25519 patterns ***/ /* set contexts */ alice = bctbx_CreateECDHContext(BCTBX_ECDH_X25519); bob = bctbx_CreateECDHContext(BCTBX_ECDH_X25519); /* Set private and derive the public value */ bctbx_ECDHSetSecretKey(alice, ECDHpattern_X25519_alicePrivate, 32); bctbx_ECDHDerivePublicKey(alice); bctbx_ECDHSetSecretKey(bob, ECDHpattern_X25519_bobPrivate, 32); bctbx_ECDHDerivePublicKey(bob); /* check the public value according to RFC7748 patterns */ BC_ASSERT_TRUE(memcmp(alice->selfPublic, ECDHpattern_X25519_alicePublic, 32)==0); BC_ASSERT_TRUE(memcmp(bob->selfPublic, ECDHpattern_X25519_bobPublic, 32)==0); /* Perform the key exchange and compute shared secret, it will check shared secrets are matching */ ECDH_exchange(alice, bob); /* check shared secret according to RFC7748 patterns */ BC_ASSERT_TRUE(memcmp(alice->sharedSecret, ECDHpattern_X25519_sharedSecret, 32)==0); /* clear contexts */ bctbx_DestroyECDHContext(alice); bctbx_DestroyECDHContext(bob); /**********************************************************************/ /*** Run an key derivation and exchange using patterns from libsignal */ /**********************************************************************/ /* Do another one using pattern retrieved from libsignal tests */ /* set contexts */ alice = bctbx_CreateECDHContext(BCTBX_ECDH_X25519); bob = bctbx_CreateECDHContext(BCTBX_ECDH_X25519); /* Set private and derive the public value */ bctbx_ECDHSetSecretKey(alice, alicePrivate_libSignalPattern, 32); bctbx_ECDHDerivePublicKey(alice); bctbx_ECDHSetSecretKey(bob, bobPrivate_libSignalPattern, 32); bctbx_ECDHDerivePublicKey(bob); /* check the public value according to libsignal patterns */ BC_ASSERT_TRUE(memcmp(alice->selfPublic, alicePublic_libSignalPattern, 32)==0); BC_ASSERT_TRUE(memcmp(bob->selfPublic, bobPublic_libSignalPattern, 32)==0); /* Perform the key exchange and compute shared secret, it will check shared secrets are matching */ ECDH_exchange(alice, bob); /* check shared secret according to libsignal patterns */ BC_ASSERT_TRUE(memcmp(alice->sharedSecret, shared_libSignalPattern, 32)==0); /* clear contexts */ bctbx_DestroyECDHContext(alice); bctbx_DestroyECDHContext(bob); /********************************************************************/ /*** Run an exchange using patterns from RFC7748 */ /********************************************************************/ /*** Run it on the X448 patterns ***/ /* set contexts */ alice = bctbx_CreateECDHContext(BCTBX_ECDH_X448); bob = bctbx_CreateECDHContext(BCTBX_ECDH_X448); /* Set private and derive the public value */ bctbx_ECDHSetSecretKey(alice, ECDHpattern_X448_alicePrivate, 56); bctbx_ECDHSetSelfPublicKey(alice, ECDHpattern_X448_alicePublic, 56); bctbx_ECDHSetSecretKey(bob, ECDHpattern_X448_bobPrivate, 56); bctbx_ECDHSetSelfPublicKey(bob, ECDHpattern_X448_bobPublic, 56); /* Perform the key exchange and compute shared secret, it will check shared secrets are matching */ ECDH_exchange(alice, bob); /* check shared secret according to RFC7748 patterns */ BC_ASSERT_TRUE(memcmp(alice->sharedSecret, ECDHpattern_X448_sharedSecret, 56)==0); /* clear contexts */ bctbx_DestroyECDHContext(alice); bctbx_DestroyECDHContext(bob); /********************************************************************/ /*** Run an key derivation and exchange using patterns from RFC7748 */ /********************************************************************/ /*** Run it on the X448 patterns ***/ /* set contexts */ alice = bctbx_CreateECDHContext(BCTBX_ECDH_X448); bob = bctbx_CreateECDHContext(BCTBX_ECDH_X448); /* Set private and derive the public value */ bctbx_ECDHSetSecretKey(alice, ECDHpattern_X448_alicePrivate, 56); bctbx_ECDHDerivePublicKey(alice); bctbx_ECDHSetSecretKey(bob, ECDHpattern_X448_bobPrivate, 56); bctbx_ECDHDerivePublicKey(bob); /* check the public value according to RFC7748 patterns */ BC_ASSERT_TRUE(memcmp(alice->selfPublic, ECDHpattern_X448_alicePublic, 56)==0); BC_ASSERT_TRUE(memcmp(bob->selfPublic, ECDHpattern_X448_bobPublic, 56)==0); /* Perform the key exchange and compute shared secret, it will check shared secrets are matching */ ECDH_exchange(alice, bob); /* check shared secret according to RFC7748 patterns */ BC_ASSERT_TRUE(memcmp(alice->sharedSecret, ECDHpattern_X448_sharedSecret, 56)==0); /* clear contexts */ bctbx_DestroyECDHContext(alice); bctbx_DestroyECDHContext(bob); } /* just check compatibility of ECDH exchange between mbedtls implementation and decaf one */ /* mbedtls works with all buffer in big endian, while rfc 7748 specify little endian encoding, so all buffer in or out of mbedtls_mpi_read/write must be reversed */ static void ECDH25519compat(void) { #ifdef HAVE_MBEDTLS int i; bctbx_ECDHContext_t *alice=NULL; bctbx_rng_context_t *RNG; mbedtls_ecdh_context *bob=NULL; uint8_t tmpBuffer[32]; uint8_t bobPublic[32]; uint8_t bobShared[32]; if (!bctbx_crypto_have_ecc()) { bctbx_warning("test skipped as we don't have Elliptic Curve Cryptography in bctoolbox"); return; } /* Init the RNG */ RNG = bctbx_rng_context_new(); /* Create Alice and Bob contexts */ alice = bctbx_CreateECDHContext(BCTBX_ECDH_X25519); bob=(mbedtls_ecdh_context *)bctbx_malloc(sizeof(mbedtls_ecdh_context)); mbedtls_ecdh_init(bob); mbedtls_ecp_group_load(&(bob->grp), MBEDTLS_ECP_DP_CURVE25519 ); /* Generate keys pairs */ bctbx_ECDHCreateKeyPair(alice, (int (*)(void *, uint8_t *, size_t))bctbx_rng_get, RNG); mbedtls_ecdh_gen_public(&(bob->grp), &(bob->d), &(bob->Q), (int (*)(void *, unsigned char *, size_t))bctbx_rng_get, RNG); mbedtls_mpi_write_binary(&(bob->Q.X), tmpBuffer, 32 ); /* tmpBuffer is in big endian, but we need it in little endian, reverse it */ for (i=0; i<32; i++) { bobPublic[i]=tmpBuffer[31-i]; } /* exchange public keys */ alice->peerPublic = (uint8_t *)malloc(alice->pointCoordinateLength*sizeof(uint8_t)); memcpy(alice->peerPublic, bobPublic, alice->pointCoordinateLength); /* compute shared secrets */ bctbx_ECDHComputeSecret(alice, NULL, NULL); mbedtls_mpi_lset(&(bob->Qp.Z), 1); /* alice->selfPublic is in little endian, but mbedtls expect it in big, reverse it */ for (i=0; i<32; i++) { tmpBuffer[i]=alice->selfPublic[31-i]; } mbedtls_mpi_read_binary(&(bob->Qp.X), tmpBuffer, 32); /* generate shared secret */ mbedtls_ecdh_compute_shared(&(bob->grp), &(bob->z), &(bob->Qp), &(bob->d), (int (*)(void *, unsigned char *, size_t))bctbx_rng_get, RNG); /* copy it in the output buffer */ mbedtls_mpi_write_binary(&(bob->z), tmpBuffer, 32); /* reverse it as we need it in little endian */ for (i=0; i<32; i++) { bobShared[i]=tmpBuffer[31-i]; } /* compare the secrets */ BC_ASSERT_TRUE(memcmp(alice->sharedSecret, bobShared, alice->pointCoordinateLength)==0); /* clear contexts */ bctbx_DestroyECDHContext(alice); mbedtls_ecdh_free(bob); free(bob); /* clear contexts */ bctbx_rng_context_free(RNG); #else /* HAVE_MBEDTLS */ bctbx_warning("test skipped as we don't have mbedtls in bctoolbox"); #endif /* HAVE_MBEDTLS */ } static char *importantMessage1 = "The most obvious mechanical phenomenon in electrical and magnetical experiments is the mutual action by which bodies in certain states set each other in motion while still at a sensible distance from each other. The first step, therefore, in reducing these phenomena into scientific form, is to ascertain the magnitude and direction of the force acting between the bodies, and when it is found that this force depends in a certain way upon the relative position of the bodies and on their electric or magnetic condition, it seems at first sight natural to explain the facts by assuming the existence of something either at rest or in motion in each body, constituting its electric or magnetic state, and capable of acting at a distance according to mathematical laws.In this way mathematical theories of statical electricity, of magnetism, of the mechanical action between conductors carrying currents, and of the induction of currents have been formed. In these theories the force acting between the two bodies is treated with reference only to the condition of the bodies and their relative position, and without any express consideration of the surrounding medium. These theories assume, more or less explicitly, the existence of substances the particles of which have the property of acting on one another at a distance by attraction or repulsion. The most complete development of a theory of this kind is that of M.W. Weber[1], who has made the same theory include electrostatic and electromagnetic phenomena. In doing so, however, he has found it necessary to assume that the force between two particles depends on their relative velocity, as well as on their distance. This theory, as developed by MM. W. Weber and C. Neumann[2], is exceedingly ingenious, and wonderfully comprehensive in its application to the phenomena of statical electricity, electromagnetic attractions, induction of current and diamagnetic phenomena; and it comes to us with the more authority, as it has served to guide the speculations of one who has made so great an advance in the practical part of electric science, both by introducing a consistent system of units in electrical measurement, and by actually determining electrical quantities with an accuracy hitherto unknown."; static char *importantMessage2 = " The mechanical difficulties, however, which are involved in the assumption of particles acting at a distance with forces which depend on their velocities are such as to prevent me from considering this theory as an ultimate one though it may have been, and may yet be useful in leading to the coordination of phenomena. I have therefore preferred to seek an explanation of the fact in another direction, by supposing them to be produced by actions which go on in the surrounding medium as well as in the excited bodies, and endeavouring to explain the action between distant bodies without assuming the existence of forces capable of acting directly at sensible distances."; static void EdDSA(void) { int i; bctbx_EDDSAContext_t *james,*world; bctbx_rng_context_t *RNG; uint8_t availableAlgos[2]={BCTBX_EDDSA_25519, BCTBX_EDDSA_448}; uint8_t availableAlgosNb=2; uint8_t signature[128]; /* buffer to store the signature, must be at least twice the size of the longer point coordinate (57*2) */ size_t signatureLength = 128; uint8_t context[250]; if (!bctbx_crypto_have_ecc()) { bctbx_warning("test skipped as we don't have Elliptic Curve Cryptography in bctoolbox"); return; } /* Init the RNG */ RNG = bctbx_rng_context_new(); for (i=0; ipublicKey, james->pointCoordinateLength); /* world verifies that the important message was signed by james */ BC_ASSERT_EQUAL(bctbx_EDDSA_verify(world, (uint8_t *)importantMessage1, strlen(importantMessage1), context, 250, signature, signatureLength), BCTBX_VERIFY_SUCCESS, int, "%d"); /* twist the signature to get it wrong and verify again, it shall fail */ signature[0] ^=0xFF; BC_ASSERT_EQUAL(bctbx_EDDSA_verify(world, (uint8_t *)importantMessage1, strlen(importantMessage1), context, 250, signature, signatureLength), BCTBX_VERIFY_FAILED, int, "%d"); /* twist the context to get it wrong and verify again, it shall fail */ signature[0] ^=0xFF; context[0] ^=0xFF; BC_ASSERT_EQUAL(bctbx_EDDSA_verify(world, (uint8_t *)importantMessage1, strlen(importantMessage1), context, 250, signature, signatureLength), BCTBX_VERIFY_FAILED, int, "%d"); /* cleaning */ bctbx_DestroyEDDSAContext(james); bctbx_DestroyEDDSAContext(world); } bctbx_rng_context_free(RNG); } static void ed25519_to_x25519_keyconversion(void) { uint8_t pattern_ed25519_publicKey[] = {0xA4, 0xBF, 0x35, 0x3D, 0x6C, 0x9D, 0x51, 0xCA, 0x6D, 0x98, 0x88, 0xA6, 0x26, 0x8C, 0xF2, 0xE8, 0xA5, 0xAD, 0x58, 0x97, 0x00, 0x5B, 0x58, 0xCC, 0x46, 0x82, 0xEB, 0x88, 0x21, 0x9A, 0xC0, 0x18}; uint8_t pattern_ed25519_secretKey[] = {0x9E, 0xEE, 0x80, 0x89, 0xA1, 0x47, 0x6E, 0x4B, 0x01, 0x70, 0xE4, 0x74, 0x06, 0xE1, 0xCE, 0xF8, 0x62, 0x53, 0xE1, 0xC2, 0x3C, 0xDD, 0x63, 0x53, 0x8D, 0x2B, 0xF0, 0x3B, 0x52, 0xD9, 0x6C, 0x39}; uint8_t pattern_x25519_publicKey[] = {0x53, 0x97, 0x95, 0x45, 0x1A, 0x04, 0xB5, 0xDD, 0x42, 0xD2, 0x73, 0x32, 0x9C, 0x1A, 0xC9, 0xFE, 0x58, 0x3A, 0x82, 0xF1, 0x82, 0xE8, 0xD7, 0xA5, 0xAD, 0xCB, 0xD0, 0x27, 0x6E, 0x03, 0xD7, 0x70}; bctbx_ECDHContext_t *aliceECDH = bctbx_CreateECDHContext(BCTBX_ECDH_X25519); bctbx_EDDSAContext_t *aliceEDDSA = bctbx_CreateEDDSAContext(BCTBX_EDDSA_25519); if (!bctbx_crypto_have_ecc()) { bctbx_warning("test skipped as we don't have Elliptic Curve Cryptography in bctoolbox"); return; } /* Start from ed25519 secret key and derive the public one */ bctbx_EDDSA_setSecretKey(aliceEDDSA, pattern_ed25519_secretKey, 32); bctbx_EDDSADerivePublicKey(aliceEDDSA); BC_ASSERT_TRUE(memcmp(aliceEDDSA->publicKey, pattern_ed25519_publicKey, 32)==0); /* Convert ed25519 private to x25519 and check it derives to the correct public key (do not check direct value of private as some bits are masked at use but not necessarily during conversion) */ bctbx_EDDSA_ECDH_privateKeyConversion(aliceEDDSA, aliceECDH); bctbx_ECDHDerivePublicKey(aliceECDH); BC_ASSERT_TRUE(memcmp(aliceECDH->selfPublic, pattern_x25519_publicKey, 32)==0); /* Convert directly ed25519 public to x25519 and check we stick to pattern */ bctbx_EDDSA_ECDH_publicKeyConversion(aliceEDDSA, aliceECDH, BCTBX_ECDH_ISPEER);/* store it in peerPublic just for this test purpose */ BC_ASSERT_TRUE(memcmp(aliceECDH->peerPublic, pattern_x25519_publicKey, 32)==0); /* cleaning */ bctbx_DestroyEDDSAContext(aliceEDDSA); bctbx_DestroyECDHContext(aliceECDH); } static void sign_and_key_exchange(void) { int i; bctbx_rng_context_t *RNG; bctbx_ECDHContext_t *aliceECDH = NULL; bctbx_EDDSAContext_t *aliceEDDSA = NULL; bctbx_ECDHContext_t *bobECDH = NULL; bctbx_EDDSAContext_t *bobEDDSA = NULL; uint8_t availableAlgosEDDSA[2]={BCTBX_EDDSA_25519, BCTBX_EDDSA_448}; uint8_t availableAlgosECDH[2]={BCTBX_ECDH_X25519, BCTBX_ECDH_X448}; uint8_t availableAlgosNb=2; uint8_t signature1[128]; /* buffer to store the signature, must be at least twice the size of the longer point coordinate (57*2) */ size_t signatureLength1 = 128; uint8_t signature2[128]; /* buffer to store the signature, must be at least twice the size of the longer point coordinate (57*2) */ size_t signatureLength2 = 128; uint8_t tmpKeyBuffer[64]; /* hold the EDDSA public key while swapping them between bob and alice */ uint8_t context1[250]; uint8_t context2[250]; if (!bctbx_crypto_have_ecc()) { bctbx_warning("test skipped as we don't have Elliptic Curve Cryptography in bctoolbox"); return; } /* Init the RNG */ RNG = bctbx_rng_context_new(); for (i=0; ipublicKey, bobEDDSA->pointCoordinateLength); bctbx_EDDSA_setPublicKey(bobEDDSA, aliceEDDSA->publicKey, aliceEDDSA->pointCoordinateLength); bctbx_EDDSA_setPublicKey(aliceEDDSA, tmpKeyBuffer, bobEDDSA->pointCoordinateLength); /* convert peer public key to ECDH format, peer public keys are now in the EDDSA context */ bctbx_EDDSA_ECDH_publicKeyConversion(aliceEDDSA, aliceECDH, BCTBX_ECDH_ISPEER); bctbx_EDDSA_ECDH_publicKeyConversion(bobEDDSA, bobECDH, BCTBX_ECDH_ISPEER); /* Verify signed messages */ BC_ASSERT_EQUAL(bctbx_EDDSA_verify(bobEDDSA, (uint8_t *)importantMessage1, strlen(importantMessage1), context1, 250, signature1, signatureLength1), BCTBX_VERIFY_SUCCESS, int, "%d"); BC_ASSERT_EQUAL(bctbx_EDDSA_verify(aliceEDDSA, (uint8_t *)importantMessage2, strlen(importantMessage2), context2, 250, signature2, signatureLength2), BCTBX_VERIFY_SUCCESS, int, "%d"); /* Compute shared secret and compare them */ bctbx_ECDHComputeSecret(aliceECDH, NULL, NULL); bctbx_ECDHComputeSecret(bobECDH, NULL, NULL); /* compare the secrets */ BC_ASSERT_TRUE(memcmp(aliceECDH->sharedSecret, bobECDH->sharedSecret, aliceECDH->pointCoordinateLength)==0); /* reset signatureLength for next run */ signatureLength1=signatureLength2=128; /* cleaning */ bctbx_DestroyEDDSAContext(aliceEDDSA); bctbx_DestroyECDHContext(aliceECDH); bctbx_DestroyEDDSAContext(bobEDDSA); bctbx_DestroyECDHContext(bobECDH); } bctbx_rng_context_free(RNG); } static void hash_test(void) { /* SHA patterns */ char *sha_input = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; uint8_t sha256_pattern[] = {0xcf, 0x5b, 0x16, 0xa7, 0x78, 0xaf, 0x83, 0x80, 0x03, 0x6c, 0xe5, 0x9e, 0x7b, 0x04, 0x92, 0x37, 0x0b, 0x24, 0x9b, 0x11, 0xe8, 0xf0, 0x7a, 0x51, 0xaf, 0xac, 0x45, 0x03, 0x7a, 0xfe, 0xe9, 0xd1}; uint8_t sha384_pattern[] = {0x09, 0x33, 0x0c, 0x33, 0xf7, 0x11, 0x47, 0xe8, 0x3d, 0x19, 0x2f, 0xc7, 0x82, 0xcd, 0x1b, 0x47, 0x53, 0x11, 0x1b, 0x17, 0x3b, 0x3b, 0x05, 0xd2, 0x2f, 0xa0, 0x80, 0x86, 0xe3, 0xb0, 0xf7, 0x12, 0xfc, 0xc7, 0xc7, 0x1a, 0x55, 0x7e, 0x2d, 0xb9, 0x66, 0xc3, 0xe9, 0xfa, 0x91, 0x74, 0x60, 0x39}; uint8_t sha512_pattern[] = {0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda, 0x8c, 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f, 0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1, 0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18, 0x50, 0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4, 0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a, 0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54, 0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09}; /* HMAC SHA patterns from RFC 4231 test case 7 */ uint8_t hmac_sha_key[] = {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}; uint8_t hmac_sha_data[] = {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65, 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62, 0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e}; uint8_t hmac_sha256_pattern[] = {0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2}; uint8_t hmac_sha384_pattern[] = {0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d, 0x35, 0x1e, 0x2f, 0x25, 0x4e, 0x8f, 0xd3, 0x2c, 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a, 0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5, 0xa6, 0x78, 0xcc, 0x31, 0xe7, 0x99, 0x17, 0x6d, 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e}; uint8_t hmac_sha512_pattern[] = {0xe3, 0x7b, 0x6a, 0x77, 0x5d, 0xc8, 0x7d, 0xba, 0xa4, 0xdf, 0xa9, 0xf9, 0x6e, 0x5e, 0x3f, 0xfd, 0xde, 0xbd, 0x71, 0xf8, 0x86, 0x72, 0x89, 0x86, 0x5d, 0xf5, 0xa3, 0x2d, 0x20, 0xcd, 0xc9, 0x44, 0xb6, 0x02, 0x2c, 0xac, 0x3c, 0x49, 0x82, 0xb1, 0x0d, 0x5e, 0xeb, 0x55, 0xc3, 0xe4, 0xde, 0x15, 0x13, 0x46, 0x76, 0xfb, 0x6d, 0xe0, 0x44, 0x60, 0x65, 0xc9, 0x74, 0x40, 0xfa, 0x8c, 0x6a, 0x58}; uint8_t outputBuffer[64]; bctbx_sha256((uint8_t *)sha_input, strlen(sha_input), 32, outputBuffer); BC_ASSERT_TRUE(memcmp(outputBuffer, sha256_pattern, 32)==0); bctbx_sha384((uint8_t *)sha_input, strlen(sha_input), 48, outputBuffer); BC_ASSERT_TRUE(memcmp(outputBuffer, sha384_pattern, 48)==0); bctbx_sha512((uint8_t *)sha_input, strlen(sha_input), 64, outputBuffer); BC_ASSERT_TRUE(memcmp(outputBuffer, sha512_pattern, 64)==0); bctbx_hmacSha256(hmac_sha_key, sizeof(hmac_sha_key), hmac_sha_data, sizeof(hmac_sha_data), 32, outputBuffer); BC_ASSERT_TRUE(memcmp(outputBuffer, hmac_sha256_pattern, 32)==0); bctbx_hmacSha384(hmac_sha_key, sizeof(hmac_sha_key), hmac_sha_data, sizeof(hmac_sha_data), 48, outputBuffer); BC_ASSERT_TRUE(memcmp(outputBuffer, hmac_sha384_pattern, 48)==0); bctbx_hmacSha512(hmac_sha_key, sizeof(hmac_sha_key), hmac_sha_data, sizeof(hmac_sha_data), 64, outputBuffer); BC_ASSERT_TRUE(memcmp(outputBuffer, hmac_sha512_pattern, 64)==0); } static test_t crypto_tests[] = { TEST_NO_TAG("Diffie-Hellman Key exchange", DHM), TEST_NO_TAG("Elliptic Curve Diffie-Hellman Key exchange", ECDH), TEST_NO_TAG("ECDH25519 decaf-mbedtls", ECDH25519compat), TEST_NO_TAG("EdDSA sign and verify", EdDSA), TEST_NO_TAG("Ed25519 to X25519 key conversion", ed25519_to_x25519_keyconversion), TEST_NO_TAG("Sign message and exchange key using the same base secret", sign_and_key_exchange), TEST_NO_TAG("Hash functions", hash_test) }; test_suite_t crypto_test_suite = {"Crypto", NULL, NULL, NULL, NULL, sizeof(crypto_tests) / sizeof(crypto_tests[0]), crypto_tests}; bctoolbox-4.4.13/tester/ios_utils.cc000066400000000000000000000025651375717307100174500ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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/ios_utils.hh" using namespace bctoolbox; static void ios_utils_return_values(void) { auto &iOSUtils = IOSUtils::getUtils(); BC_ASSERT_EQUAL(iOSUtils.beginBackgroundTask(nullptr, nullptr), 0, unsigned long, "%lu"); BC_ASSERT_EQUAL(iOSUtils.isApplicationStateActive(), false, bool, "%d"); } static test_t ios_utils_tests[] = { TEST_NO_TAG("Return values for stubbed functions", ios_utils_return_values), }; test_suite_t ios_utils_test_suite = {"iOS Utilities", NULL, NULL, NULL, NULL, sizeof(ios_utils_tests) / sizeof(ios_utils_tests[0]), ios_utils_tests}; bctoolbox-4.4.13/tester/parser.c000066400000000000000000000031531375717307100165610ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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 "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-4.4.13/tester/port.c000066400000000000000000000210041375717307100162440ustar00rootroot00000000000000/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * 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 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 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((char *)outputBytes, (char *)a55aBytes, 2); bctbx_str_to_uint8(outputBytes, upString, 16); BC_ASSERT_NSTRING_EQUAL((char *)outputBytes, (char *)upBytes, 8); bctbx_str_to_uint8(outputBytes, downString, 16); BC_ASSERT_NSTRING_EQUAL((char *)outputBytes, (char *)downBytes, 8); bctbx_int8_to_str(outputString, a55aBytes, 2); BC_ASSERT_NSTRING_EQUAL((char *)outputString, (char *)a55aString, 4); bctbx_int8_to_str(outputString, upBytes, 8); BC_ASSERT_NSTRING_EQUAL((char *)outputString, (char *)upString, 16); bctbx_int8_to_str(outputString, downBytes, 8); BC_ASSERT_NSTRING_EQUAL((char *)outputString, (char *)downString, 16); bctbx_uint32_to_str(outputString, 0x5aa5c376); BC_ASSERT_NSTRING_EQUAL((char *)outputString, "5aa5c376", 8); bctbx_uint32_to_str(outputString, 0x01234567); BC_ASSERT_NSTRING_EQUAL((char *)outputString, "01234567", 8); bctbx_uint32_to_str(outputString, 0xfedcba98); BC_ASSERT_NSTRING_EQUAL((char *)outputString, "fedcba98", 8); BC_ASSERT_EQUAL(bctbx_str_to_uint32((uint8_t *)"5aa5c376"), 0x5aa5c376, uint32_t, "0x%08x"); BC_ASSERT_EQUAL(bctbx_str_to_uint32((uint8_t *)"01234567"), 0x01234567, uint32_t, "0x%08x"); BC_ASSERT_EQUAL(bctbx_str_to_uint32((uint8_t *)"fedcba98"), 0xfedcba98, uint32_t, "0x%08x"); bctbx_uint64_to_str(outputString, 0xfa5c37643cde8de0); BC_ASSERT_NSTRING_EQUAL((char *)outputString, "fa5c37643cde8de0", 16); bctbx_uint64_to_str(outputString, 0x0123456789abcdef); BC_ASSERT_NSTRING_EQUAL((char *)outputString, "0123456789abcdef", 16); bctbx_uint64_to_str(outputString, 0xfedcba9876543210); BC_ASSERT_NSTRING_EQUAL((char *)outputString, "fedcba9876543210", 16); BC_ASSERT_EQUAL(bctbx_str_to_uint64((uint8_t *)"fa5c37643cde8de0"), 0xfa5c37643cde8de0, uint64_t, "0x%" PRIx64); BC_ASSERT_EQUAL(bctbx_str_to_uint64((uint8_t *)"0123456789abcdef"), 0x0123456789abcdef, uint64_t, "0x%" PRIx64); BC_ASSERT_EQUAL(bctbx_str_to_uint64((uint8_t *)"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 void bctbx_addrinfo_sort_test(void) { struct addrinfo * res1 = bctbx_name_to_addrinfo(AF_INET6, SOCK_DGRAM, "sip3.linphone.org", 27256); struct addrinfo * res2 = bctbx_ip_address_to_addrinfo(AF_INET6, SOCK_DGRAM, "91.121.209.194", 27256); struct addrinfo * res3 = bctbx_ip_address_to_addrinfo(AF_INET, SOCK_DGRAM, "91.121.209.194", 27256); bool_t searching_for_v6=TRUE; struct addrinfo * ai = NULL; char printable_ip[256]; struct addrinfo * res = res3; for ( ai=res2 ; ai !=NULL; ai=ai->ai_next) { if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6*)(ai->ai_addr))->sin6_addr)) { res->ai_next=ai; break; } } res->ai_next->ai_next=res1; res->ai_next->ai_next->ai_next=NULL; //So now, res as ipv4 first, then v4 mapped, then v6 for ( ai=res ; ai !=NULL; ai=ai->ai_next) { bctbx_addrinfo_to_printable_ip_address(ai, printable_ip, sizeof(printable_ip)); bctbx_message("bctbx_getaddrinfo origin address:%s", printable_ip); } //now apply bctbx_addrinfo_sort for ( ai=bctbx_addrinfo_sort(res) ; ai !=NULL; ai=ai->ai_next) { if (ai->ai_family == AF_INET6) { if (!searching_for_v6) { BC_ASSERT_FALSE(IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6*)(ai->ai_addr))->sin6_addr)); } if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6*)(ai->ai_addr))->sin6_addr)) { searching_for_v6 = FALSE; // stating from now, all subsequent IP shall be pure V6 } } bctbx_addrinfo_to_printable_ip_address(ai, printable_ip, sizeof(printable_ip)); bctbx_message("bctbx_getaddrinfo sorted address:%s", printable_ip); } bctbx_freeaddrinfo(res); } 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_NO_TAG("Addrinfo sort", bctbx_addrinfo_sort_test) }; test_suite_t utils_test_suite = {"Utils", NULL, NULL, NULL, NULL, sizeof(utils_tests) / sizeof(utils_tests[0]), utils_tests};