# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.8)
project(AmazonCorrettoCryptoProvider)
include(CheckLibraryExists)
include(UseJava)
include(CheckCXXSourceCompiles)
include(CheckCXXCompilerFlag)
if (CMAKE_VERSION VERSION_GREATER 3.10)
find_package(Java 10 REQUIRED)
else()
# We must support old versions of cmake which do not understand modern versions of java.
# Old CMAKE doesn't support JDK10 (because it stops offering javah). So, we cannot use find_package(java)
# Instead, we'll manually set the variables we need.
set(JAVA_BIN ${JAVA_HOME}/bin)
set(Java_JAVA_EXECUTABLE ${JAVA_BIN}/java)
set(Java_JAVAC_EXECUTABLE ${JAVA_BIN}/javac)
set(Java_JAVADOC_EXECUTABLE ${JAVA_BIN}/javadoc)
set(Java_IDLJ_EXECUTABLE ${JAVA_BIN}/idlj)
set(Java_JAR_EXECUTABLE ${JAVA_BIN}/jar)
set(Java_JARSIGNER_EXECUTABLE ${JAVA_BIN}/jarsigner)
set(Java_IDLJ_EXECUTABLE ${JAVA_BIN}/idlj)
set(Java_VERSION_STRING ${JAVA_MAJOR_VERSION}.${JAVA_MINOR_VERSION})
set(Java_VERSION_MAJOR ${JAVA_MAJOR_VERSION})
set(Java_VERSION_MINOR ${JAVA_MINOR_VERSION})
endif()
find_package(JNI REQUIRED)
include(FindOpenSSL)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
set(BUILD_CLASSPATH "" CACHE STRING "Classpath to JARs to be included at build time")
set(TEST_CLASSPATH "" CACHE STRING "Classpath to be included at test build and test execution time")
set(SIGNED_JAR "" CACHE STRING "Path to a pre-signed JAR file, to be used instead of compiling the java source")
set(DIEHARDER_EXECUTABLE "dieharder" CACHE STRING "Path to the dieharder executable")
set(ENABLE_NATIVE_TEST_HOOKS NO CACHE BOOL "Enable debugging hooks in the RNG. Disable for production use.")
set(TEST_DATA_DIR ${PROJECT_SOURCE_DIR}/test-data/ CACHE STRING "Path to directory containing test data")
set(ORIG_SRCROOT ${PROJECT_SOURCE_DIR} CACHE STRING "Path to root of original package")
set(PROVIDER_VERSION_STRING "" CACHE STRING "X.Y.Z formatted version of the provider")
set(FIPS NO CACHE BOOL "Determine if this build is for FIPS mode")
set(ALWAYS_ALLOW_EXTERNAL_LIB NO CACHE BOOL "Always permit tests to load ACCP shared objects from the library path")
if (USE_CLANG_TIDY)
# https://releases.llvm.org/9.0.0/tools/clang/tools/extra/docs/clang-tidy/checks/list.html
# https://clang.llvm.org/extra/clang-tidy/#suppressing-undesired-diagnostics
# TODO: Make this enforcing with "-warnings-as-errors=*;" once we're happy with the state
set(CMAKE_CXX_CLANG_TIDY "clang-tidy;-checks=-*")
# Categories we want
set(CMAKE_CXX_CLANG_TIDY ${CMAKE_CXX_CLANG_TIDY},bugprone-*)
set(CMAKE_CXX_CLANG_TIDY ${CMAKE_CXX_CLANG_TIDY},cert-*)
set(CMAKE_CXX_CLANG_TIDY ${CMAKE_CXX_CLANG_TIDY},cppcoreguidelines-*)
set(CMAKE_CXX_CLANG_TIDY ${CMAKE_CXX_CLANG_TIDY},clang-analyzer-*)
set(CMAKE_CXX_CLANG_TIDY ${CMAKE_CXX_CLANG_TIDY},performance-*)
set(CMAKE_CXX_CLANG_TIDY ${CMAKE_CXX_CLANG_TIDY},portability-*)
set(CMAKE_CXX_CLANG_TIDY ${CMAKE_CXX_CLANG_TIDY},readability-*)
# Things we don't want
# We must use reinterpret cast to move things across the JNI boundary
set(CMAKE_CXX_CLANG_TIDY ${CMAKE_CXX_CLANG_TIDY},-cppcoreguidelines-pro-type-reinterpret-cast)
# We intentionally omit the parameters for jclass
set(CMAKE_CXX_CLANG_TIDY ${CMAKE_CXX_CLANG_TIDY},-readability-named-parameter)
# We target older styles of C++. We can revisit these after checking all build chains
set(CMAKE_CXX_CLANG_TIDY ${CMAKE_CXX_CLANG_TIDY},-cppcoreguidelines-macro-usage)
# Anything referencing gsl:: (Guidelines support library) is too new for us
endif()
if (NOT DEFINED JACOCO_AGENT_JAR)
set(JACOCO_AGENT_JAR ${JACOCO_ROOT}/jacocoagent.jar)
endif()
if (NOT DEFINED TEST_JAVA_HOME)
set(TEST_JAVA_EXECUTABLE ${Java_JAVA_EXECUTABLE})
set(TEST_JAVA_MAJOR_VERSION ${Java_VERSION_MAJOR})
else()
set(TEST_JAVA_EXECUTABLE ${TEST_JAVA_HOME}/bin/java)
endif()
# Translate from the java colon-delimited paths to cmake ';' delimited lists
string(REPLACE ":" ";" BUILD_CLASSPATH_LIST "${BUILD_CLASSPATH}")
string(REPLACE ":" ";" TEST_CLASSPATH_LIST "${TEST_CLASSPATH}")
# Needed as we abuse some of the test compile macros to test shared lib links
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# CMake's default RPath handling includes the full build directory path, which isn't needed. Turn it off.
set(CMAKE_SKIP_RPATH TRUE)
set(GENERATE_HASHERS ${CMAKE_CURRENT_SOURCE_DIR}/build-tools/bin/generate-java-hash-spi)
set(GENERATED_JAVA_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated-java/com/amazon/corretto/crypto/provider)
set(JNI_HEADER_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated-include)
## Query our SPI generator to find out what output files it intends to generate.
## Note that this query runs at configure time...
execute_process(
COMMAND ${GENERATE_HASHERS} list ${CMAKE_CURRENT_SOURCE_DIR} ${GENERATED_JAVA_DIR}
OUTPUT_VARIABLE GENERATED_JAVA_SRC
RESULT_VARIABLE RETURN_VALUE
)
if (NOT RETURN_VALUE EQUAL 0)
message(FATAL_ERROR "Failed to list generated hash function types")
endif()
# This forces cmake to rerun if the generate script itself changes (and
# therefore the list of files generated might change). Unfortunately this
# dummy-file bit seems to be the supported way to do this, see e.g.
# https://cmake.org/pipermail/cmake/2010-November/040978.html
# The actual effect of this line is to do some variable substitutions in
# ${GENERATE_HASHERS} and write the output to the dummy-file, and this action
# results in re-invoking cmake to perform this substitution.
CONFIGURE_FILE(${GENERATE_HASHERS} ${CMAKE_CURRENT_BINARY_DIR}/dummy-file)
set(VERSION_PROPERTIES_FILE ${GENERATED_JAVA_DIR}/version.properties)
add_custom_command(
OUTPUT ${VERSION_PROPERTIES_FILE}
COMMAND ${CMAKE_COMMAND} -E echo versionStr=${PROVIDER_VERSION_STRING} > ${VERSION_PROPERTIES_FILE}
COMMENT "Generation version properties file"
)
add_custom_command(
COMMAND ${GENERATE_HASHERS} generate ${CMAKE_CURRENT_SOURCE_DIR} ${GENERATED_JAVA_DIR}
DEPENDS ${GENERATE_HASHERS}
OUTPUT ${GENERATED_JAVA_SRC}
COMMENT "Generating hash function SPI classes..."
)
# NOTE: CMake introduced the CONFIGURE_DEPENDS feature in 3.12, so condition
# its use on CMake version. If the feature is not available, you may need
# to `touch CMakeLists.txt` after adding/removing files for them to be
# detected by CMake.
if (${CMAKE_VERSION} VERSION_LESS "3.12.0")
file(GLOB_RECURSE ACCP_SRC "src/com/amazon/corretto/crypto/provider/*.java")
else()
file(GLOB_RECURSE ACCP_SRC CONFIGURE_DEPENDS "src/com/amazon/corretto/crypto/provider/*.java")
endif()
set(ACCP_SRC ${ACCP_SRC} ${GENERATED_JAVA_SRC})
set(BASE_JAVA_COMPILE_FLAGS ${CMAKE_JAVA_COMPILE_FLAGS} -h "${JNI_HEADER_DIR}" -Werror -Xlint)
# Java targets defined here are compiled for Java supporting modules
set(CMAKE_JAVA_COMPILE_FLAGS ${BASE_JAVA_COMPILE_FLAGS} --release 9)
set(ACCP_JAR "${CMAKE_CURRENT_BINARY_DIR}/AmazonCorrettoCryptoProvider.jar")
set(ACCP_JAR_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/AmazonCorrettoCryptoProvider-sources.jar")
add_jar(
module-jar
SOURCES ${ACCP_SRC}
src/module-info.java
INCLUDE_JARS ${BUILD_CLASSPATH_LIST}
)
create_javadoc(
AmazonCorrettoCryptoProvider
FILES ${ACCP_SRC}
WINDOWTITLE "Amazon Corretto Crypto Provider"
DOCTITLE "
Amazon Corretto Crypto Provider
"
AUTHOR FALSE
USE TRUE
VERSION TRUE
)
add_custom_target(javadoc DEPENDS ${JNI_HEADER_DIR}/generated-headers.h ${GENERATED_JAVA_SRC} AmazonCorrettoCryptoProvider_javadoc)
# All subsequent Java targets are compatible with Java 8
set(CMAKE_JAVA_COMPILE_FLAGS ${BASE_JAVA_COMPILE_FLAGS} --release 8)
# Add a JAR target. We can't add resources here (as discussed below) so we'll
# build a temporary one first.
add_jar(
code-only-jar
SOURCES ${ACCP_SRC}
INCLUDE_JARS ${BUILD_CLASSPATH_LIST}
)
if (SIGNED_JAR)
# Just copy the JAR in
add_custom_command(
OUTPUT ${ACCP_JAR}
COMMAND ${CMAKE_COMMAND} -E copy ${SIGNED_JAR} ${ACCP_JAR}
COMMAND ${CMAKE_COMMAND} -E echo Copied ${SIGNED_JAR} to ${ACCP_JAR}
COMMAND ${CMAKE_COMMAND} -E copy ${OPENSSL_CRYPTO_LIBRARY} $
)
else()
# CMake's UseJar doesn't let us control the paths that resource files are
# placed at - if we list them, they'll be stored based on their path relative
# to CMAKE_CURRENT_SOURCE_DIR, so we'll need to manually add them in. We let
# CMake build the class files above, then copy the JAR and add some additional
# files to it.
set(ACCP_JAR_TMP "${CMAKE_CURRENT_BINARY_DIR}/AmazonCorrettoCryptoProvider.tmp.jar")
add_custom_command(
OUTPUT ${ACCP_JAR}
COMMAND ${CMAKE_COMMAND} -E copy $ ${ACCP_JAR_TMP}
COMMAND ${CMAKE_COMMAND} -E remove_directory ${ACCP_JAR_TMP}/com/amazon/corretto/crypto/provider/test
COMMAND ${Java_JAR_EXECUTABLE} uf ${ACCP_JAR_TMP} -C ${CMAKE_CURRENT_SOURCE_DIR}/extra-jar-files .
COMMAND ${Java_JAR_EXECUTABLE} uf ${ACCP_JAR_TMP} -C $ module-info.class
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/tmplib/com/amazon/corretto/crypto/provider/
COMMAND ${CMAKE_COMMAND} -E copy ${OPENSSL_CRYPTO_LIBRARY} $
COMMAND ${CMAKE_COMMAND} -E copy ${OPENSSL_CRYPTO_LIBRARY} ${CMAKE_CURRENT_BINARY_DIR}/tmplib/com/amazon/corretto/crypto/provider/
COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR}/tmplib/com/amazon/corretto/crypto/provider/
COMMAND ${Java_JAR_EXECUTABLE} uf ${ACCP_JAR_TMP} -C ${CMAKE_CURRENT_BINARY_DIR}/tmplib/ com/amazon/corretto/crypto/provider/
COMMAND ${Java_JAR_EXECUTABLE} uf ${ACCP_JAR_TMP} -C ${CMAKE_CURRENT_BINARY_DIR}/generated-java/ com/amazon/corretto/crypto/provider/version.properties
COMMAND ${CMAKE_COMMAND} -E copy ${ACCP_JAR_TMP} ${ACCP_JAR}
DEPENDS code-only-jar module-jar ${VERSION_PROPERTIES_FILE}
)
endif()
add_custom_target(accp-jar ALL DEPENDS ${ACCP_JAR})
# Attach the JAR_FILE property to our custom jar target; this allows add_jar
# later on to recognize this target as a JAR target, and handle classpath
# dependencies appropriately.
set_property(TARGET accp-jar PROPERTY JAR_FILE ${ACCP_JAR})
# Generate a combined headers file; currently we assume all headers are in a
# single file on the C++ side, but javac -h creates a separate header for each
# class. Arguably, we should include the specific headers we need only, but
# that's a later refactor.
ADD_CUSTOM_COMMAND(
OUTPUT ${JNI_HEADER_DIR}/generated-headers.h
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build-tools/bin/generate-omni-header ${JNI_HEADER_DIR}
# Note that we still build the code-only-jar even if we're using the signed jar; this is
# primarily to generate java headers (generating headers via javah from binary classfiles is
# deprecated starting in Java 9). We depend on tests-code-jar because that generates headers
# we need for some test code.
DEPENDS code-only-jar tests-code-jar
)
### Native library configuration
include_directories(${OPENSSL_INCLUDE_DIR} ${JNI_INCLUDE_DIRS} ${JNI_HEADER_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/src/cpp)
add_library(
amazonCorrettoCryptoProvider SHARED
csrc/aes_gcm.cpp
csrc/aes_xts.cpp
csrc/aes_kwp.cpp
csrc/agreement.cpp
csrc/bn.cpp
csrc/buffer.cpp
csrc/ec_gen.cpp
csrc/ec_utils.cpp
csrc/env.cpp
csrc/hkdf.cpp
csrc/hmac.cpp
csrc/keyutils.cpp
csrc/java_evp_keys.cpp
csrc/libcrypto_rng.cpp
csrc/loader.cpp
csrc/md5.cpp
csrc/rsa_cipher.cpp
csrc/rsa_gen.cpp
csrc/sha1.cpp
csrc/sha256.cpp
csrc/sha384.cpp
csrc/sha512.cpp
csrc/sign.cpp
csrc/testhooks.cpp
csrc/util.cpp
csrc/util_class.cpp
csrc/fips_kat_self_test.cpp
${JNI_HEADER_DIR}/generated-headers.h
)
# We MUST set ACCP's RPATH to "$ORIGIN" so that the runtime dynamic loader will look in the same directory as ACCP for
# any shared library dependencies BEFORE looking for a system-installed depencencies (such as libcrypto). If RPath is
# not set, the loader may attempt to load an incompatible system-installed libcrypto and cause runtime crashes.
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(CMAKE_MACOSX_RPATH TRUE)
set(RPATH_ORIGIN "@loader_path")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(RPATH_ORIGIN "\$ORIGIN")
else()
message( FATAL_ERROR "Unsupported OS, need to determine OS-specific analog of linux rpath's $ORIGIN")
endif()
set_target_properties(amazonCorrettoCryptoProvider PROPERTIES LINK_FLAGS "-Wl,-rpath,${RPATH_ORIGIN}")
add_custom_command(
OUTPUT ${ACCP_JAR_SOURCE}
COMMAND ${Java_JAR_EXECUTABLE} cf ${ACCP_JAR_SOURCE} -C ${CMAKE_CURRENT_SOURCE_DIR}/src .
COMMAND ${Java_JAR_EXECUTABLE} uf ${ACCP_JAR_SOURCE} -C ${CMAKE_CURRENT_SOURCE_DIR} csrc
COMMAND ${Java_JAR_EXECUTABLE} uf ${ACCP_JAR_SOURCE} -C ${CMAKE_CURRENT_SOURCE_DIR}/extra-jar-files com/amazon/corretto/crypto/provider/testdata
COMMAND ${Java_JAR_EXECUTABLE} uf ${ACCP_JAR_SOURCE} -C ${CMAKE_CURRENT_BINARY_DIR}/generated-java/ .
DEPENDS ${GENERATED_JAVA_SRC}
)
add_custom_target(accp-jar-source DEPENDS ${ACCP_JAR_SOURCE})
if(ENABLE_NATIVE_TEST_HOOKS)
add_executable(test_keyutils EXCLUDE_FROM_ALL
csrc/test_keyutils.cpp
)
set_target_properties(test_keyutils PROPERTIES LINK_FLAGS "-Wl,-rpath,${RPATH_ORIGIN}")
target_link_libraries(test_keyutils ${OPENSSL_CRYPTO_LIBRARY})
target_link_libraries(test_keyutils amazonCorrettoCryptoProvider)
endif()
#### Start of feature tests
## First, figure out how best to link against openssl
set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
# This macro helps us perform tests that are not supported through the
# generic CHECK_CXX_COMPILER_FLAG mechanism. Specifically, these result
# in building certain targets on the project under the CMake/trycompile
# directory in the source tree. This is needed because there's no built-in
# mechanism for specifically testing for linker flag support on shared object
# targets.
#
# Usage: CHECK_CUSTOM_TRY_COMPILE(cached_flag_variable_name target_name [-DVAR:TYPE=value ...])
macro(CHECK_CUSTOM_TRY_COMPILE var target)
if(NOT DEFINED "${var}")
message(STATUS "Performing test ${var}...")
# Clean up any stray temp directory before we trycompile; otherwise we might
# get a false positive result due to the target being built already
file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/try_compile_tmp/${var})
try_compile(${var}
${CMAKE_CURRENT_BINARY_DIR}/try_compile_tmp/${var}
${CMAKE_CURRENT_SOURCE_DIR}/CMake/trycompile
TryCompile ${target}
CMAKE_FLAGS
-DLINK_LIBS:STRING=${OPENSSL_CRYPTO_LIBRARY}
-DOPENSSL_INCLUDE_DIR:STRING=${OPENSSL_INCLUDE_DIR}
${ARGN}
)
if(${var})
message(STATUS "Performing test ${var} - Success")
else()
message(STATUS "Performing test ${var} - Failed")
endif()
endif()
endmacro(CHECK_CUSTOM_TRY_COMPILE)
# Macro to check and enable if supported a CXX compiler flag
macro(CHECK_ENABLE_CXX_FLAG var flags)
CHECK_CXX_COMPILER_FLAG("${flags}" ${var})
if(${var})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flags}")
endif()
endmacro()
# Linking openssl may require -ldl and/or -lm
CHECK_LIBRARY_EXISTS(dl "dlopen" "" HAVE_LIBDL)
CHECK_LIBRARY_EXISTS(m "sqrt" "" HAVE_LIBM)
if(HAVE_LIBDL)
target_link_libraries(amazonCorrettoCryptoProvider dl)
endif()
if(HAVE_LIBM)
target_link_libraries(amazonCorrettoCryptoProvider m)
endif()
# Enable language feature flags first, as they impact later feature tests
CHECK_ENABLE_CXX_FLAG(HAVE_CXX_11 "--std=c++11")
CHECK_CXX_SOURCE_COMPILES("int main() __attribute__((cold)) {return 0;}" HAVE_ATTR_COLD)
CHECK_CXX_SOURCE_COMPILES("int main() __attribute__((noreturn)) {return 0;}" HAVE_ATTR_NORETURN)
CHECK_CXX_SOURCE_COMPILES("int main() __attribute__((always_inline)) {return 0;}" HAVE_ATTR_ALWAYS_INLINE)
CHECK_CXX_SOURCE_COMPILES("int main() __attribute__((noinline)) {return 0;}" HAVE_ATTR_NOINLINE)
# getentropy is in unistd.h on linux
CHECK_CXX_SOURCE_COMPILES("
#define _DEFAULT_SOURCE
#include
int main() {
int foo;
getentropy(&foo, sizeof(foo));
return 0;
}" HAVE_GETENTROPY)
# ... and in sys/random on BSD/darwin
CHECK_CXX_SOURCE_COMPILES("
#define _DEFAULT_SOURCE
// OSX bug - sys/random.h is missing some #includes needed for macros
// it uses internally. Pull in unistd.h to try to work around this.
#include
#include
int main() {
int foo;
getentropy(&foo, sizeof(foo));
return 0;
}" HAVE_GETENTROPY_IN_SYSRANDOM)
CHECK_CXX_SOURCE_COMPILES("
#include
#include
#include
int main() {
Dl_info info;
(void)info.dli_fname;
(void)info.dli_sname;
(void)info.dli_saddr;
(void)&dladdr;
backtrace(NULL, 1);
abi::__cxa_demangle(NULL, NULL, NULL, NULL);
return 0;
}
" HAVE_BACKTRACE_APIS)
# Some versions of GCC claim CXX11 compliance but do not fully implement
CHECK_CXX_SOURCE_COMPILES("
#include
static_assert(std::is_trivially_copyable::value,
\"int should be trivally copyable\");
int main() { return 0; }
" HAVE_IS_TRIVIALLY_COPYABLE)
CHECK_CXX_SOURCE_COMPILES("
#include
static_assert(std::is_trivially_destructable::value,
\"int should be trivally destructable\");
int main() { return 0; }
" HAVE_IS_TRIVIALLY_DESTRUCTABLE)
if(${HAVE_BACKTRACE_APIS})
if(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Release")
set(BACKTRACE_DEFAULT ON)
endif()
endif()
option(BACKTRACE_ON_EXCEPTION "Enable backtraces in C++-originated exceptions" BACKTRACE_DEFAULT)
CHECK_CXX_SOURCE_COMPILES("
int main(int, char **) noexcept {}
" HAVE_NOEXCEPT)
set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${OLD_CMAKE_EXE_LINKER_FLAGS}")
# Miscellaneous linker flag tests. Unfortunately cmake doesn't have built-in
# functionality for a linker flag test, so we have to roll our own.
# This function will test if a linker flag is supported, and if it is, add it to
# ${PROBED_LINKER_FLAGS}. 'var' should be a unique cache variable name to store the
# flag-supported test result.
macro(CHECK_LINKER_FLAG_SUPPORT var flags)
CHECK_CUSTOM_TRY_COMPILE(${var} empty -DLINK_FLAGS:STRING=${flags})
if(${var})
MESSAGE(STATUS "Using linker flags ${flags}")
set(PROBED_LINKED_FLAGS "${PROBED_LINKED_FLAGS} ${flags}")
endif()
endmacro(CHECK_LINKER_FLAG_SUPPORT)
# When test hooks are enabled we need to expose a bunch of internal symbols for the tests to poke at.
if(NOT ENABLE_NATIVE_TEST_HOOKS)
# This version script attempts to hide the openssl symbols (and any other
# internal symbols) from the exports table.
CHECK_LINKER_FLAG_SUPPORT(USE_VERSION_SCRIPT "-Wl,--version-script -Wl,${CMAKE_CURRENT_SOURCE_DIR}/final-link.version")
# This does the same thing as the version script, but works on Darwin platforms
CHECK_LINKER_FLAG_SUPPORT(USE_EXPORTED_SYMBOL "-Wl,-exported_symbol '-Wl,_Java_*' -Wl,-exported_symbol '-Wl,_JNI_*'")
endif()
# Attempt to drop unused sections; the idea here is to exclude unreferenced
# parts of openssl in the final library
CHECK_LINKER_FLAG_SUPPORT(USE_GC_SECTIONS "-Wl,--gc-sections")
# Mark that our library is compatible with non-executable stack segments.
# Otherwise, on linux, loading our library will mark the stack as executable.
CHECK_LINKER_FLAG_SUPPORT(USE_NOEXECSTACK "-Wl,-z -Wl,noexecstack")
# Disabling New DTags ensures that RPath is used instead of RunPath (which has lower priority). Since it's likely that
# other libcrypto.so files will be in LD_LIBRARY_PATH, we need to ensure that we're using RPath so that our copy of
# libcrypto.so that is extracted into a temp directory at startup is loaded *before* LD_LIBRARY_PATH is checked.
CHECK_LINKER_FLAG_SUPPORT(USE_DISABLE_NEW_DTAGS "-Wl,--disable-new-dtags")
### CXX flag tests
CHECK_ENABLE_CXX_FLAG(CXX_FLAG_WALL -Wall)
CHECK_ENABLE_CXX_FLAG(CXX_FLAG_WUNINIT -Wuninitialized)
CHECK_ENABLE_CXX_FLAG(CXX_FLAG_WERROR -Werror)
# We need C++11 or higher for 'long long' with -pedantic
CHECK_ENABLE_CXX_FLAG(CXX_FLAG_CXX11 --std=c++11)
if(${CMAKE_BUILD_TYPE} STREQUAL "Release")
# This breaks backtraces, so only enable it in release mode
CHECK_ENABLE_CXX_FLAG(CXX_FLAG_FOMITFP -fomit-frame-pointer)
endif()
if(NOT CXX_FLAG_CXX11)
# Maybe the old name will work? c++0x is a deprecated name but if we're on an old compiler we need to use it
CHECK_ENABLE_CXX_FLAG(CXX_FLAG_CXX0x --std=c++0x)
# On gcc4.1, we get "cc1plus: warning: -Wuninitialized is not supported without -O" if this isn't added.
CHECK_ENABLE_CXX_FLAG(CXX_FLAG_TEST -O)
endif()
if(CXX_FLAG_CXX11 OR CXX_FLAG_CXX0x)
# 'long long' is not supported before C++11, so don't enable -pedantic
# (which will warn on using long long at unsupported language levels)
# unless we have a new enough C++ version available
CHECK_ENABLE_CXX_FLAG(CXX_FLAG_PEDANTIC -pedantic)
endif()
option(COVERAGE "Enable code coverage instrumentation" OFF)
if(COVERAGE)
CHECK_CUSTOM_TRY_COMPILE(CXX_FLAG_COVERAGE coverage)
if(NOT CXX_FLAG_COVERAGE)
message(FATAL_ERROR "C++ compiler does not support coverage instrumentation")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
# Disable assert()s. This avoids having unreachable assert branches pollute our branch coverage.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNDEBUG")
endif()
### End feature tests - add our probed flags to the library link invocation
if(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Release")
# This enables expensive test-only assertions
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEXTRA_TEST_ASSERT")
endif()
# Pass in provider version
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPROVIDER_VERSION_STRING=${PROVIDER_VERSION_STRING}")
# CMake disallows leading or trailing whitespace here, but our concatenations will
# leave us with leading whitespace, so strip it off first.
string(STRIP "${PROBED_LINKED_FLAGS}" PROBED_LINKED_FLAGS)
MESSAGE(STATUS "probed flags ${PROBED_LINKED_FLAGS}")
target_link_libraries(amazonCorrettoCryptoProvider ${PROBED_LINKED_FLAGS})
# Statically link libc++ and libgcc on linux to avoid compatibility issues with
# obsolete system libraries on older platforms. These options don't apply to
# MacOS/Darwin because its gcc is actually an alias to clang, which does not
# fully support them.
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
message(STATUS "System name matches linux. Checking if -static-libstdc++ and -static-libgcc are supported by the compiler.")
CHECK_ENABLE_CXX_FLAG(CXX_SUPPORT_STATIC_LIBSTDCPP -static-libstdc++)
CHECK_ENABLE_CXX_FLAG(CXX_SUPPORT_STATIC_LIBGCC -static-libgcc)
if(CXX_SUPPORT_STATIC_LIBSTDCPP AND CXX_SUPPORT_STATIC_LIBGCC)
message(STATUS "Using -static-libstdc++ and -static-libgcc flags")
target_link_libraries(amazonCorrettoCryptoProvider -static-libstdc++)
target_link_libraries(amazonCorrettoCryptoProvider -static-libgcc)
endif()
endif()
# Add pthread support
target_link_libraries(amazonCorrettoCryptoProvider Threads::Threads)
# Take a dependency on our libcrypto.so file
target_link_libraries(amazonCorrettoCryptoProvider ${OPENSSL_CRYPTO_LIBRARY})
# NOTE: CMake introduced the CONFIGURE_DEPENDS feature in 3.12, so condition
# its use on CMake version. If the feature is not available, you may need
# to `touch CMakeLists.txt` after adding/removing files for them to be
# detected by CMake.
if (${CMAKE_VERSION} VERSION_LESS "3.12.0")
file(GLOB_RECURSE ACCP_TEST_SRC "tst/com/amazon/corretto/crypto/provider/*.java")
else()
file(GLOB_RECURSE ACCP_TEST_SRC CONFIGURE_DEPENDS "tst/com/amazon/corretto/crypto/provider/*.java")
endif()
## Tests
add_jar(
tests-code-jar
SOURCES ${ACCP_TEST_SRC}
INCLUDE_JARS ${TEST_CLASSPATH_LIST} code-only-jar
)
set_target_properties(tests-code-jar PROPERTIES EXCLUDE_FROM_ALL 1)
# Our tests have some custom resources they rely upon as well. We'll just bundle the whole tests directory
# to make this easy.
set(TESTS_JAR "${CMAKE_CURRENT_BINARY_DIR}/tests.jar")
add_custom_command(
OUTPUT ${TESTS_JAR}
COMMAND ${CMAKE_COMMAND} -E copy $ ${TESTS_JAR}.tmp.jar
COMMAND ${Java_JAR_EXECUTABLE} uf ${TESTS_JAR}.tmp.jar -C ${CMAKE_CURRENT_SOURCE_DIR}/tst .
COMMAND ${CMAKE_COMMAND} -E copy ${TESTS_JAR}.tmp.jar ${TESTS_JAR}
DEPENDS tests-code-jar
)
add_custom_target(tests-jar DEPENDS ${TESTS_JAR})
set_property(TARGET tests-jar PROPERTY JAR_FILE ${TESTS_JAR})
# These flags are necessary in Java17+ in order for certain unit tests to
# perform deep reflection on nonpublic members
if (TEST_JAVA_MAJOR_VERSION VERSION_GREATER_EQUAL 17)
set(TEST_ADD_OPENS
--add-opens java.base/javax.crypto=ALL-UNNAMED
--add-opens java.base/java.lang.invoke=ALL-UNNAMED
--add-opens java.base/java.security=ALL-UNNAMED
--add-opens java.base/sun.security.util=ALL-UNNAMED
--add-exports jdk.crypto.ec/sun.security.ec=java.base
)
endif()
set(COVERAGE_ARGUMENTS
-javaagent:${JACOCO_AGENT_JAR}=destfile=coverage/jacoco.exec,classdumpdir=coverage/classes
)
if(FIPS)
set(TEST_FIPS_PROPERTY "-DFIPS=true")
# ACCP's default behavior in FIPS mode is to not register a SecureRandom implementation.
# However, we explicitly register it here to ensure its coverage under test.
set(REGISTER_RNG_PROPERTY "-Dcom.amazon.corretto.crypto.provider.registerSecureRandom=true")
else()
set(TEST_FIPS_PROPERTY "-DFIPS=false")
endif()
if(ALWAYS_ALLOW_EXTERNAL_LIB)
set(EXTERNAL_LIB_PROPERTY "-Djava.library.path=$")
endif()
set(TEST_RUNNER_ARGUMENTS
${COVERAGE_ARGUMENTS}
${TEST_ADD_OPENS}
${TEST_FIPS_PROPERTY}
${EXTERNAL_LIB_PROPERTY}
${REGISTER_RNG_PROPERTY}
-Dcom.amazon.corretto.crypto.provider.inTestSuite=hunter2
-Dtest.data.dir=${TEST_DATA_DIR}
-Djunit.jupiter.execution.parallel.enabled=true
-Djunit.jupiter.execution.parallel.mode.default=concurrent
-Djunit.jupiter.execution.parallel.mode.classes.default=concurrent
-XX:+HeapDumpOnOutOfMemoryError
${TEST_JAVA_ARGS}
-jar ${TEST_RUNNER_JAR}
-cp $:$:${TEST_CLASSPATH}
--details=summary
--details-theme=ascii
--fail-if-no-tests
)
if("$ENV{ACCP_TEST_COLOR}" STREQUAL "false")
set(TEST_RUNNER_ARGUMENTS ${TEST_RUNNER_ARGUMENTS} --disable-ansi-colors)
endif()
## Note: We can't use the 'test' target as it's reserved by cmake's own test subsystem.
add_custom_target(check-junit
COMMAND ${TEST_JAVA_EXECUTABLE}
${TEST_RUNNER_ARGUMENTS}
--reports-dir=unit-tests
--select-package=com.amazon.corretto.crypto.provider.test
--exclude-package=com.amazon.corretto.crypto.provider.test.integration
--exclude-classname=com.amazon.corretto.crypto.provider.test.SecurityManagerTest
DEPENDS accp-jar tests-jar)
if (DEFINED SINGLE_TEST)
add_custom_target(check-junit-single
COMMAND ${TEST_JAVA_EXECUTABLE}
${TEST_RUNNER_ARGUMENTS}
--select-class=${SINGLE_TEST}
DEPENDS accp-jar tests-jar)
endif() # SINGLE_TEST
add_custom_target(check-junit-SecurityManager
COMMAND ${TEST_JAVA_EXECUTABLE}
${TEST_RUNNER_ARGUMENTS}
--select-class=com.amazon.corretto.crypto.provider.test.AesTest # Force loading ciphers
--select-class=com.amazon.corretto.crypto.provider.test.SHA1Test # Force loading digests
--select-class=com.amazon.corretto.crypto.provider.test.SecurityManagerTest
DEPENDS accp-jar tests-jar)
add_custom_target(check-junit-extra-checks
COMMAND ${TEST_JAVA_EXECUTABLE}
-Dcom.amazon.corretto.crypto.provider.extrachecks=ALL
-Dcom.amazon.corretto.crypto.provider.debug=ALL
${TEST_RUNNER_ARGUMENTS}
--select-package=com.amazon.corretto.crypto.provider.test
--exclude-package=com.amazon.corretto.crypto.provider.test.integration
--exclude-classname=com.amazon.corretto.crypto.provider.test.SecurityManagerTest
DEPENDS accp-jar tests-jar)
add_custom_target(check-recursive-init
COMMAND ${TEST_JAVA_EXECUTABLE}
${COVERAGE_ARGUMENTS}
${TEST_FIPS_PROPERTY}
-cp $:$:${TEST_CLASSPATH}
${EXTERNAL_LIB_PROPERTY}
-Dcom.amazon.corretto.crypto.provider.inTestSuite=hunter2
-Dtest.data.dir=${TEST_DATA_DIR}
${TEST_JAVA_ARGS}
com.amazon.corretto.crypto.provider.test.RecursiveInitializationTest
DEPENDS accp-jar tests-jar)
if (TEST_JAVA_MAJOR_VERSION VERSION_GREATER 11)
set(INSTALL_PROPERTY_FILE ${ORIG_SRCROOT}/etc/amazon-corretto-crypto-provider-jdk15.security)
else()
set(INSTALL_PROPERTY_FILE ${ORIG_SRCROOT}/etc/amazon-corretto-crypto-provider.security)
endif()
add_custom_target(check-install-via-properties
COMMAND ${TEST_JAVA_EXECUTABLE}
${COVERAGE_ARGUMENTS}
${TEST_FIPS_PROPERTY}
-cp $:$:${TEST_CLASSPATH}
${EXTERNAL_LIB_PROPERTY}
-Dcom.amazon.corretto.crypto.provider.inTestSuite=hunter2
-Dtest.data.dir=${TEST_DATA_DIR}
-Djava.security.properties=${INSTALL_PROPERTY_FILE}
${TEST_JAVA_ARGS}
com.amazon.corretto.crypto.provider.test.SecurityPropertyTester
DEPENDS accp-jar tests-jar)
add_custom_target(check-external-lib
# Unfortunately we do not have a way to know where the library is loaded from.
# So this test just proves that requesting the external lib does not break things
COMMAND ${TEST_JAVA_EXECUTABLE}
${COVERAGE_ARGUMENTS}
${TEST_FIPS_PROPERTY}
-cp $:$:${TEST_CLASSPATH}
# Since this tests external loading we always provide this property
-Djava.library.path=$
-Dcom.amazon.corretto.crypto.provider.useExternalLib=true
-Dcom.amazon.corretto.crypto.provider.inTestSuite=hunter2
-Dtest.data.dir=${TEST_DATA_DIR}
-Djava.security.properties=${INSTALL_PROPERTY_FILE}
${TEST_JAVA_ARGS}
com.amazon.corretto.crypto.provider.test.SecurityPropertyTester
DEPENDS accp-jar tests-jar)
add_custom_target(check-install-via-properties-recursive
COMMAND ${TEST_JAVA_EXECUTABLE}
${COVERAGE_ARGUMENTS}
${TEST_FIPS_PROPERTY}
-cp $:$:${TEST_CLASSPATH}
${EXTERNAL_LIB_PROPERTY}
-Dcom.amazon.corretto.crypto.provider.inTestSuite=hunter2
-Dtest.data.dir=${TEST_DATA_DIR}
-Djava.security.properties=${INSTALL_PROPERTY_FILE}
${TEST_JAVA_ARGS}
com.amazon.corretto.crypto.provider.test.SecurityPropertyRecursiveTester
DEPENDS accp-jar tests-jar)
add_custom_target(check-install-via-properties-with-debug
COMMAND ${TEST_JAVA_EXECUTABLE}
${COVERAGE_ARGUMENTS}
${TEST_FIPS_PROPERTY}
-cp $:$:${TEST_CLASSPATH}
${EXTERNAL_LIB_PROPERTY}
-Dcom.amazon.corretto.crypto.provider.inTestSuite=hunter2
-Dtest.data.dir=${TEST_DATA_DIR}
-Djava.security.properties=${INSTALL_PROPERTY_FILE}
-Djava.security.debug=all
${TEST_JAVA_ARGS}
com.amazon.corretto.crypto.provider.test.SecurityPropertyTester
DEPENDS accp-jar tests-jar)
add_custom_target(check
DEPENDS check-recursive-init check-install-via-properties check-install-via-properties-with-debug check-junit check-junit-SecurityManager check-external-lib check-libaccp-rpath)
if(ENABLE_NATIVE_TEST_HOOKS)
add_custom_target(check-keyutils
COMMAND ${CMAKE_COMMAND} -E copy ${OPENSSL_CRYPTO_LIBRARY} $
COMMAND $
)
add_dependencies(check check-keyutils)
endif()
add_custom_target(coverage
COMMAND ${TEST_JAVA_EXECUTABLE}
-cp $:${TEST_CLASSPATH}
com.amazon.corretto.crypto.provider.coverage.ReportGenerator
AmazonCorrettoCryptoProvider
coverage/jacoco.exec
$
${CMAKE_CURRENT_SOURCE_DIR}/src,${CMAKE_CURRENT_BINARY_DIR}/generated-java
coverage/results
DEPENDS check)
add_custom_target(check-integration-extra-checks
COMMAND ${TEST_JAVA_EXECUTABLE}
-Dcom.amazon.corretto.crypto.provider.extrachecks=ALL
# perform standard integration tests with JCE EC parameters, and extra-checks integration tests with ACCP's
-Dcom.amazon.corretto.crypto.provider.registerEcParams=true
${TEST_RUNNER_ARGUMENTS}
--select-package=com.amazon.corretto.crypto.provider.test.integration
DEPENDS accp-jar tests-jar)
set_target_properties(check-integration-extra-checks PROPERTIES EXCLUDE_FROM_ALL 1)
add_custom_target(check-integration
COMMAND ${TEST_JAVA_EXECUTABLE}
${TEST_RUNNER_ARGUMENTS}
--reports-dir=integration-tests
--select-package=com.amazon.corretto.crypto.provider.test.integration
DEPENDS accp-jar tests-jar)
set_target_properties(check-integration PROPERTIES EXCLUDE_FROM_ALL 1)
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
add_custom_target(run-dieharder-libcrypto-rng
COMMAND ${TEST_JAVA_EXECUTABLE} -cp $:$:${TEST_CLASSPATH}
${EXTERNAL_LIB_PROPERTY}
${REGISTER_RNG_PROPERTY}
com.amazon.corretto.crypto.provider.test.SecureRandomGenerator 'LibCryptoRng' 8192 1 |
${DIEHARDER_EXECUTABLE} -a -g 200 -Y 1 -k 2 |
tee dieharder-results-libcrypto-rng.txt
DEPENDS accp-jar tests-jar)
add_custom_target(run-dieharder-libcrypto-rng-tail
COMMAND ${TEST_JAVA_EXECUTABLE} -cp $:$:${TEST_CLASSPATH}
${EXTERNAL_LIB_PROPERTY}
${REGISTER_RNG_PROPERTY}
com.amazon.corretto.crypto.provider.test.SecureRandomGenerator 'LibCryptoRng' 31 1 |
${DIEHARDER_EXECUTABLE} -d 15 -g 200 -Y 1 -k 2 |
tee dieharder-results-libcrypto-rng-tail.txt
DEPENDS accp-jar tests-jar)
add_custom_target(run-dieharder-libcrypto-rng-threads
COMMAND ${TEST_JAVA_EXECUTABLE} -cp $:$:${TEST_CLASSPATH}
${EXTERNAL_LIB_PROPERTY}
${REGISTER_RNG_PROPERTY}
com.amazon.corretto.crypto.provider.test.SecureRandomGenerator 'LibCryptoRng' 128 4 |
${DIEHARDER_EXECUTABLE} -a -g 200 -Y 1 -k 2 |
tee dieharder-results-libcrypto-rng-threads.txt
DEPENDS accp-jar tests-jar)
add_custom_target(run-dieharder-libcrypto-rng-threads-tail
COMMAND ${TEST_JAVA_EXECUTABLE} -cp $:$:${TEST_CLASSPATH}
${EXTERNAL_LIB_PROPERTY}
${REGISTER_RNG_PROPERTY}
com.amazon.corretto.crypto.provider.test.SecureRandomGenerator 'LibCryptoRng' 31 4 |
${DIEHARDER_EXECUTABLE} -d 15 -g 200 -Y 1 -k 2 |
tee dieharder-results-libcrypto-rng-threads-tail.txt
DEPENDS accp-jar tests-jar)
add_custom_target(check-dieharder
COMMAND ! grep -l FAIL dieharder-results-libcrypto-rng.txt
COMMAND grep PASSED dieharder-results-libcrypto-rng.txt
COMMAND ! grep -l FAIL dieharder-results-libcrypto-rng-tail.txt
COMMAND grep PASSED dieharder-results-libcrypto-rng-tail.txt
DEPENDS run-dieharder-libcrypto-rng run-dieharder-libcrypto-rng-tail)
add_custom_target(check-dieharder-threads
COMMAND ! grep -l FAIL dieharder-results-libcrypto-rng-threads.txt
COMMAND grep PASSED dieharder-results-libcrypto-rng-threads.txt
COMMAND ! grep -l FAIL dieharder-results-libcrypto-rng-threads-tail.txt
COMMAND grep PASSED dieharder-results-libcrypto-rng-threads-tail.txt
DEPENDS run-dieharder-libcrypto-rng-threads run-dieharder-libcrypto-rng-threads-tail)
endif() # End of Dieharder targets
# Add a target to assert that the libaccp shared object's rpath meets 2 conditions:
# 1. rpath contains only a single entry
# 2. that entry is set to $ORIGIN on linux or @loader_path on mac
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
add_custom_target(check-libaccp-rpath
COMMAND otool -l $
| grep 'cmd LC_RPATH'
| wc -l
| tr -d '[:blank:]'
| xargs test 1 -eq
COMMAND otool -l $
| grep -A2 'cmd LC_RPATH'
| tail -1
| grep '@loader_path'
)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
add_custom_target(check-libaccp-rpath
COMMAND objdump -x $
| grep -E 'RPATH|RUNPATH' # RPATH on AL, RUNPATH on Ubuntu
| grep -v ':'
COMMAND objdump -x $
| grep -E 'RPATH|RUNPATH' # RPATH on AL, RUNPATH on Ubuntu
| grep -E "\$ORIGIN"
)
else()
message( FATAL_ERROR "Unsupported OS, need to validate OS-specific rpath $ORIGIN")
endif()
# Do this at the end, after we finish all our feature tests, or it'll be missing flags
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/csrc/config.h.in ${JNI_HEADER_DIR}/config.h)