cmake_minimum_required (VERSION 3.0) project (s2n C) if(POLICY CMP0077) cmake_policy(SET CMP0077 NEW) #option does nothing when a normal variable of the same name exists. endif() set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries") set(INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files") set(INSTALL_CMAKE_DIR lib/cmake CACHE PATH "Installation directory for cmake files") option(S2N_NO_PQ "Disables all Post Quantum Crypto code. You likely want this for older compilers or uncommon platforms." OFF) option(S2N_NO_PQ_ASM "Turns off the ASM for PQ Crypto even if it's available for the toolchain. You likely want this on older compilers." OFF) option(SEARCH_LIBCRYPTO "Set this if you want to let S2N search libcrypto for you, otherwise a crypto target needs to be defined." ON) option(UNSAFE_TREAT_WARNINGS_AS_ERRORS "Compiler warnings are treated as errors. Warnings may indicate danger points where you should verify with the S2N-TLS developers that the security of the library is not compromised. Turn this OFF to ignore warnings." ON) # Turn BUILD_TESTING=ON by default include(CTest) file(GLOB API_HEADERS "api/*.h") file(GLOB CRYPTO_HEADERS "crypto/*.h") file(GLOB CRYPTO_SRC "crypto/*.c") file(GLOB ERROR_HEADERS "error/*.h") file(GLOB ERROR_SRC "error/*.c") file(GLOB STUFFER_HEADERS "stuffer/*.h") file(GLOB STUFFER_SRC "stuffer/*.c") file(GLOB_RECURSE TLS_HEADERS "tls/*.h") file(GLOB_RECURSE TLS_SRC "tls/*.c") file(GLOB UTILS_HEADERS "utils/*.h") file(GLOB UTILS_SRC "utils/*.c") # Always include the top-level pq-crypto/ files file(GLOB PQ_HEADERS "pq-crypto/*.h") file(GLOB PQ_SRC "pq-crypto/*.c") if(S2N_NO_PQ) # PQ is disabled, so we do not include any PQ crypto code message(STATUS "S2N_NO_PQ flag was detected - disabling PQ crypto") set(S2N_NO_PQ_ASM ON) else() # PQ is enabled, so include all of the PQ crypto code file(GLOB PQ_HEADERS "pq-crypto/*.h" "pq-crypto/bike_r1/*.h" "pq-crypto/bike_r2/*.h" "pq-crypto/bike_r3/*.h" "pq-crypto/sike_r1/*.h" "pq-crypto/kyber_r2/*.h" "pq-crypto/kyber_90s_r2/*.h" "pq-crypto/kyber_r3/*.h" "pq-crypto/sike_r3/*.h") # The SIKE r1 code #includes .c files directly; including sike_r1/*.c # here breaks the build due to duplicates. The SIKE r3 code does not have this issue. file(GLOB PQ_SRC "pq-crypto/*.c" "pq-crypto/bike_r1/*.c" "pq-crypto/bike_r2/*.c" "pq-crypto/bike_r3/*.c" "pq-crypto/sike_r1/fp_generic_r1.c" "pq-crypto/sike_r1/P503_r1.c" "pq-crypto/sike_r1/sike_r1_kem.c" "pq-crypto/sike_r1/fips202_r1.c" "pq-crypto/kyber_r2/*.c" "pq-crypto/kyber_90s_r2/*.c" "pq-crypto/kyber_r3/*.c" "pq-crypto/sike_r3/*.c") endif() ##be nice to visual studio users if(MSVC) source_group("Header Files\\s2n\\api" FILES ${API_HEADERS}) source_group("Header Files\\s2n\\crypto" FILES ${CRYPTO_HEADERS}) source_group("Header Files\\s2n\\error" FILES ${ERROR_HEADERS}) source_group("Header Files\\s2n\\pq-crypto" FILES ${PQ_HEADERS}) source_group("Header Files\\s2n\\stuffer" FILES ${STUFFER_HEADERS}) source_group("Header Files\\s2n\\tls" FILES ${TLS_HEADERS}) source_group("Header Files\\s2n\\utils" FILES ${UTILS_HEADERS}) source_group("Source Files\\crypto" FILES ${CRYPTO_SRC}) source_group("Source Files\\error" FILES ${ERROR_SRC}) source_group("Source Files\\pq-crypto" FILES ${PQ_SRC}) source_group("Source Files\\stuffer" FILES ${STUFFER_SRC}) source_group("Source Files\\tls" FILES ${TLS_SRC}) source_group("Source Files\\utils" FILES ${UTILS_SRC}) else() set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) endif() # The PQ ASM try_compile has to come after we turn on pthread. # If S2N_NO_PQ_ASM is defined, all PQ assembly options will # remain turned off by default. set(SIKEP434R3_ASM_SUPPORTED false) set(ADX_SUPPORTED false) if(S2N_NO_PQ_ASM) message(STATUS "S2N_NO_PQ_ASM flag was detected - disabling PQ crypto assembly code") else() enable_language(ASM) # sikep434r3 try_compile( SIKEP434R3_ASM_SUPPORTED ${CMAKE_BINARY_DIR} SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/noop_main.c" "${CMAKE_CURRENT_LIST_DIR}/pq-crypto/sike_r3/sikep434r3.c" "${CMAKE_CURRENT_LIST_DIR}/pq-crypto/sike_r3/sikep434r3_fp_x64_asm.S" ) if(SIKEP434R3_ASM_SUPPORTED) file(GLOB SIKEP434R3_ASM_SRC "pq-crypto/sike_r3/sikep434r3_fp_x64_asm.S") list(APPEND PQ_SRC ${SIKEP434R3_ASM_SRC}) # The ADX instruction set is preferred for best performance, but not necessary. try_compile( ADX_SUPPORTED ${CMAKE_BINARY_DIR} SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/noop_main.c" "${CMAKE_CURRENT_LIST_DIR}/pq-crypto/sike_r3/sikep434r3.c" "${CMAKE_CURRENT_LIST_DIR}/pq-crypto/sike_r3/sikep434r3_fp_x64_asm.S" COMPILE_DEFINITIONS "-DS2N_ADX" ) endif() # BIKE Round-3 code has several different optimizations which require # specific compiler flags to be supported by the compiler. # So for each needed instruction set extension we check if the compiler # supports it and set proper compiler flags to be added later to the # BIKE compilation units. if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^(x86_64|amd64|AMD64)$") # First, check if the compiler supports the specific instruction set # extensions. For example, gcc-4 doesn't fully support AVX-512, while # gcc-7 doesn't support VPCLMUL extension. try_compile(BIKE_R3_AVX2_SUPPORTED ${CMAKE_BINARY_DIR} "${CMAKE_CURRENT_LIST_DIR}/tests/features/noop_main.c" COMPILE_DEFINITIONS "-mavx2") set(BIKE_R3_AVX512_FLAGS "-mavx512f -mavx512bw -mavx512dq") try_compile(BIKE_R3_AVX512_SUPPORTED ${CMAKE_BINARY_DIR} "${CMAKE_CURRENT_LIST_DIR}/tests/features/noop_main.c" COMPILE_DEFINITIONS ${BIKE_R3_AVX512_FLAGS}) set(BIKE_R3_PCLMUL_FLAGS "-mpclmul -msse2") try_compile(BIKE_R3_PCLMUL_SUPPORTED ${CMAKE_BINARY_DIR} "${CMAKE_CURRENT_LIST_DIR}/tests/features/noop_main.c" COMPILE_DEFINITIONS ${BIKE_R3_PCLMUL_FLAGS}) set(BIKE_R3_VPCLMUL_FLAGS "-mvpclmulqdq -mavx512f -mavx512bw -mavx512dq") try_compile(BIKE_R3_VPCLMUL_SUPPORTED ${CMAKE_BINARY_DIR} "${CMAKE_CURRENT_LIST_DIR}/tests/features/noop_main.c" COMPILE_DEFINITIONS ${BIKE_R3_VPCLMUL_FLAGS}) if(BIKE_R3_AVX2_SUPPORTED OR BIKE_R3_AVX512_SUPPORTED OR BIKE_R3_PCLMUL_SUPPORTED OR BIKE_R3_VPCLMUL_SUPPORTED) set(BIKE_R3_X86_64_OPT_SUPPORTED ON) endif() endif() endif() # Probe for execinfo.h extensions (not present on some systems, notably android) include(CheckCSourceCompiles) # Determine if execinfo.h is available try_compile( S2N_HAVE_EXECINFO ${CMAKE_BINARY_DIR} SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/execinfo.c" ) # Determine if cpuid.h is available try_compile( S2N_CPUID_AVAILABLE ${CMAKE_BINARY_DIR} SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/cpuid.c" ) # Determine if __attribute__((fallthrough)) is available try_compile( FALL_THROUGH_SUPPORTED ${CMAKE_BINARY_DIR} SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/fallthrough.c" COMPILE_DEFINITIONS "-Werror" ) # Determine if __restrict__ is available try_compile( __RESTRICT__SUPPORTED ${CMAKE_BINARY_DIR} SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/__restrict__.c" COMPILE_DEFINITIONS "-Werror" ) if(APPLE) set(OS_LIBS c Threads::Threads) elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") set(OS_LIBS thr) elseif(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") set(OS_LIBS Threads::Threads) elseif(CMAKE_SYSTEM_NAME STREQUAL "Android") set(OS_LIBS Threads::Threads dl) else() set(OS_LIBS Threads::Threads dl rt) endif() file(GLOB S2N_HEADERS ${API_HEADERS} ${CRYPTO_HEADERS} ${ERROR_HEADERS} ${PQ_HEADERS} ${STUFFER_HEADERS} ${TLS_HEADERS} ${UTILS_HEADERS} ) file(GLOB S2N_SRC ${CRYPTO_SRC} ${ERROR_SRC} ${PQ_SRC} ${STUFFER_SRC} ${TLS_SRC} ${UTILS_SRC} ) add_library(${PROJECT_NAME} ${S2N_HEADERS} ${S2N_SRC}) set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE C) set(CMAKE_C_FLAGS_DEBUGOPT "") target_compile_options(${PROJECT_NAME} PRIVATE -pedantic -std=gnu99 -Wall -Wimplicit -Wunused -Wcomment -Wchar-subscripts -Wuninitialized -Wshadow -Wcast-qual -Wcast-align -Wwrite-strings -Wno-deprecated-declarations -Wno-unknown-pragmas -Wformat-security -Wno-missing-braces -Wa,--noexecstack ) if (UNSAFE_TREAT_WARNINGS_AS_ERRORS) target_compile_options(${PROJECT_NAME} PRIVATE -Werror ) endif () if(BUILD_TESTING AND BUILD_SHARED_LIBS) target_compile_options(${PROJECT_NAME} PRIVATE -fvisibility=default) else() target_compile_options(${PROJECT_NAME} PRIVATE -fvisibility=hidden -DS2N_EXPORTS) endif() if(NOT APPLE) set(CMAKE_SHARED_LINKER_FLAGS -Wl,-z,noexecstack,-z,relro,-z,now) endif() if(S2N_NO_PQ) target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_NO_PQ) endif() if(SIKEP434R3_ASM_SUPPORTED) target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_SIKE_P434_R3_ASM) message(STATUS "Enabling SIKEP434R3 assembly code") endif() if(BIKE_R3_X86_64_OPT_SUPPORTED) # If any of the BIKE_R3 x86_64 optimizations is supported (this was checked # earlier in the file), we add the required compile flags to files that # contain the optimized code. if(BIKE_R3_AVX2_SUPPORTED) FILE(GLOB BIKE_R3_AVX2_SRCS "pq-crypto/bike_r3/*_avx2.c") set_source_files_properties(${BIKE_R3_AVX2_SRCS} PROPERTIES COMPILE_FLAGS -mavx2) target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_BIKE_R3_AVX2) endif() if(BIKE_R3_AVX512_SUPPORTED) FILE(GLOB BIKE_R3_AVX512_SRCS "pq-crypto/bike_r3/*_avx512.c") set_source_files_properties(${BIKE_R3_AVX512_SRCS} PROPERTIES COMPILE_FLAGS ${BIKE_R3_AVX512_FLAGS}) target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_BIKE_R3_AVX512) endif() if(BIKE_R3_PCLMUL_SUPPORTED) FILE(GLOB BIKE_R3_PCLMUL_SRCS "pq-crypto/bike_r3/*_pclmul.c") set_source_files_properties(${BIKE_R3_PCLMUL_SRCS} PROPERTIES COMPILE_FLAGS ${BIKE_R3_PCLMUL_FLAGS}) target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_BIKE_R3_PCLMUL) endif() if(BIKE_R3_VPCLMUL_SUPPORTED) FILE(GLOB BIKE_R3_VPCLMUL_SRCS "pq-crypto/bike_r3/*_vpclmul.c") set_source_files_properties(${BIKE_R3_VPCLMUL_SRCS} PROPERTIES COMPILE_FLAGS ${BIKE_R3_VPCLMUL_FLAGS}) target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_BIKE_R3_VPCLMUL) endif() message(STATUS "Enabling BIKE_R3 x86_64 optimizations") endif() if(ADX_SUPPORTED) target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_ADX) message(STATUS "Support for ADX assembly instructions detected") endif() if(S2N_HAVE_EXECINFO) target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_HAVE_EXECINFO) endif() if(S2N_CPUID_AVAILABLE) target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_CPUID_AVAILABLE) endif() target_compile_options(${PROJECT_NAME} PUBLIC -fPIC) target_compile_definitions(${PROJECT_NAME} PRIVATE -D_POSIX_C_SOURCE=200809L) if(CMAKE_BUILD_TYPE MATCHES Release) target_compile_definitions(${PROJECT_NAME} PRIVATE -D_FORTIFY_SOURCE=2) endif() if(NO_STACK_PROTECTOR) target_compile_options(${PROJECT_NAME} PRIVATE -Wstack-protector -fstack-protector-all) endif() if(S2N_UNSAFE_FUZZING_MODE) target_compile_options(${PROJECT_NAME} PRIVATE -fsanitize-coverage=trace-pc-guard -fsanitize=address,undefined,leak -fuse-ld=gold -DS2N_ADDRESS_SANITIZER=1) endif() if (FALL_THROUGH_SUPPORTED) target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_FALL_THROUGH_SUPPORTED) endif() if (__RESTRICT__SUPPORTED) target_compile_options(${PROJECT_NAME} PUBLIC -DS2N___RESTRICT__SUPPORTED) endif() set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) if (SEARCH_LIBCRYPTO) find_package(LibCrypto REQUIRED) else() if (TARGET crypto) message(STATUS "S2N found target: crypto") else() message(FATAL_ERROR "Target crypto is not defined, failed to find libcrypto") endif() endif() target_link_libraries(${PROJECT_NAME} PUBLIC crypto ${OS_LIBS} m) target_include_directories(${PROJECT_NAME} PUBLIC $) target_include_directories(${PROJECT_NAME} PUBLIC $ $) target_include_directories(${PROJECT_NAME} PRIVATE $) if (BUILD_TESTING) enable_testing() file(GLOB TESTLIB_SRC "tests/testlib/*.c") file(GLOB TESTLIB_HEADERS "tests/testlib/*.h" "tests/s2n_test.h") add_library(testss2n STATIC ${TESTLIB_HEADERS} ${TESTLIB_SRC}) target_include_directories(testss2n PUBLIC tests) target_compile_options(testss2n PRIVATE -std=gnu99) target_link_libraries(testss2n PUBLIC ${PROJECT_NAME}) target_include_directories(testss2n PUBLIC $) #run unit tests file (GLOB TEST_LD_PRELOAD "tests/LD_PRELOAD/*.c") add_library(allocator_overrides SHARED ${TEST_LD_PRELOAD}) file(GLOB UNITTESTS_SRC "tests/unit/*.c") foreach(test_case ${UNITTESTS_SRC}) string(REGEX REPLACE ".+\\/(.+)\\.c" "\\1" test_case_name ${test_case}) add_executable(${test_case_name} ${test_case}) target_include_directories(${test_case_name} PRIVATE api) target_include_directories(${test_case_name} PRIVATE ./) target_include_directories(${test_case_name} PRIVATE tests) target_link_libraries(${test_case_name} PRIVATE testss2n) target_compile_options(${test_case_name} PRIVATE -Wno-implicit-function-declaration -Wno-deprecated -D_POSIX_C_SOURCE=200809L -std=gnu99) add_test(NAME ${test_case_name} COMMAND $ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests/unit) set_property( TEST ${test_case_name} PROPERTY ENVIRONMENT LD_PRELOAD=$) set_property( TEST ${test_case_name} PROPERTY ENVIRONMENT S2N_DONT_MLOCK=1) endforeach(test_case) add_executable(s2nc "bin/s2nc.c" "bin/echo.c" "bin/https.c" "bin/common.c") target_link_libraries(s2nc ${PROJECT_NAME}) target_include_directories(s2nc PRIVATE $) target_include_directories(s2nc PRIVATE api) target_compile_options(s2nc PRIVATE -std=gnu99 -D_POSIX_C_SOURCE=200112L) add_executable(s2nd "bin/s2nd.c" "bin/echo.c" "bin/https.c" "bin/common.c") target_link_libraries(s2nd ${PROJECT_NAME}) target_include_directories(s2nd PRIVATE $) target_include_directories(s2nd PRIVATE api) target_compile_options(s2nd PRIVATE -std=gnu99 -D_POSIX_C_SOURCE=200112L) if(BENCHMARK) find_package(benchmark REQUIRED) file(GLOB BENCHMARK_SRC "tests/benchmark/*.cc") enable_language(CXX) foreach(benchmark ${BENCHMARK_SRC}) string(REGEX REPLACE ".+\\/(.+)\\.cc" "\\1" benchmark_name ${benchmark}) add_executable(${benchmark_name} ${benchmark}) target_include_directories(${benchmark_name} PRIVATE api) target_include_directories(${benchmark_name} PRIVATE tests) target_link_libraries(${benchmark_name} PUBLIC ${PROJECT_NAME} testss2n benchmark::benchmark) # Based off the flags in tests/benchmark/Makefile target_compile_options(${benchmark_name} PRIVATE -pedantic -Wall -Werror -Wunused -Wcomment -Wchar-subscripts -Wuninitialized -Wshadow -Wcast-qual -Wcast-align -Wwrite-strings -Wno-deprecated-declarations -Wno-unknown-pragmas -Wformat-security -Wno-missing-braces -fvisibility=hidden -Wno-unreachable-code -Wno-unused-but-set-variable) endforeach(benchmark) endif() endif() #install the s2n files install(FILES ${API_HEADERS} DESTINATION "include/" COMPONENT Development) if (UNIX AND NOT APPLE) include(GNUInstallDirs) elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) set(CMAKE_INSTALL_LIBDIR "lib") endif() install( TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}-targets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Development LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Runtime RUNTIME DESTINATION bin COMPONENT Runtime ) configure_file("cmake/${PROJECT_NAME}-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" @ONLY) if (BUILD_SHARED_LIBS) set (TARGET_DIR "shared") else() set (TARGET_DIR "static") endif() install(EXPORT "${PROJECT_NAME}-targets" DESTINATION "${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/cmake/${TARGET_DIR}" NAMESPACE AWS:: COMPONENT Development) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/cmake/" COMPONENT Development) install(FILES "cmake/modules/FindLibCrypto.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/cmake/modules/" COMPONENT Development)