Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 66 additions & 1 deletion contrib/openssl-cmake/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ docker cp $id:$lib_dir/build/ssl/libssl.a $OUTPUT_DIR
docker cp $id:$lib_dir/build/crypto/libcrypto.a $OUTPUT_DIR
docker cp $id:$lib_dir/include $OUTPUT_DIR

# Extract pre-built test harness libraries (symbol-localized, with libstdc++ baked in)
docker cp $id:/harness-output/libawslc_shim.a $OUTPUT_DIR
docker cp $id:/harness-output/libawslc_handshaker.a $OUTPUT_DIR
docker cp $id:/harness-output/libawslc_acvp_server.a $OUTPUT_DIR

docker rm $id"
)

Expand Down Expand Up @@ -70,7 +75,12 @@ execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory "${AWSLC_BINARIES_DIR

add_custom_target(build-awslc
COMMENT "Build AWS-LC in FIPS mode with docker"
DEPENDS ${AWSLC_BINARIES_DIR}/libssl.a ${AWSLC_BINARIES_DIR}/libcrypto.a
DEPENDS
${AWSLC_BINARIES_DIR}/libssl.a
${AWSLC_BINARIES_DIR}/libcrypto.a
${AWSLC_BINARIES_DIR}/libawslc_shim.a
${AWSLC_BINARIES_DIR}/libawslc_handshaker.a
${AWSLC_BINARIES_DIR}/libawslc_acvp_server.a
Comment on lines +81 to +83
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid requiring harness archives in every FIPS build

build-awslc is a dependency of the imported crypto target, so adding these three archives here makes every -DFIPS_CLICKHOUSE=1 build produce the SSL/ACVP harness before libcrypto.a is usable. That is a build regression on non-x86_64/aarch64 FIPS targets: the new harness path always compiles programs/ssl-common/posix_spawn_2.c, which hard-errors outside those two architectures, so Linux ppc64le/riscv64/s390x configurations now fail in the Docker step even if they never use clickhouse ssl-shim or clickhouse ssl-handshaker.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are not going to support non-x86_64/aarch64 build, so this is not relevant.

)

if(ARCH_AARCH64)
Expand All @@ -83,7 +93,20 @@ add_custom_command(
OUTPUT
"${AWSLC_BUILD_DIR}/output/libssl.a"
"${AWSLC_BUILD_DIR}/output/libcrypto.a"
"${AWSLC_BUILD_DIR}/output/libawslc_shim.a"
"${AWSLC_BUILD_DIR}/output/libawslc_handshaker.a"
"${AWSLC_BUILD_DIR}/output/libawslc_acvp_server.a"
COMMENT "Building AWS-LC in FIPS mode using docker"
# Copy test harness build inputs into the Docker context directory
COMMAND ${CMAKE_COMMAND} -E copy
${ClickHouse_SOURCE_DIR}/programs/ssl-common/posix_spawn_2.c
${AWSLC_BUILD_DIR}/posix_spawn_2.c
COMMAND ${CMAKE_COMMAND} -E copy
${ClickHouse_SOURCE_DIR}/programs/ssl-common/glibc_compat.c
${AWSLC_BUILD_DIR}/glibc_compat.c
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/build_test_harness.sh
${AWSLC_BUILD_DIR}/build_test_harness.sh
COMMAND bash -c "chmod +x ${AWSLC_BUILD_DIR}/build_awclc_fips.sh"
COMMAND bash -c "${AWSLC_BUILD_DIR}/build_awclc_fips.sh ${AWSLC_BINARIES_DIR} ${DOCKERFILE_PATH}"
WORKING_DIRECTORY ${AWSLC_BUILD_DIR}
Expand All @@ -92,6 +115,9 @@ add_custom_command(
${AWSLC_BUILD_DIR}/build_awclc_fips.sh
${AWSLC_BUILD_DIR}/check_version.c
${DOCKERFILE_PATH}
${ClickHouse_SOURCE_DIR}/programs/ssl-common/posix_spawn_2.c
${ClickHouse_SOURCE_DIR}/programs/ssl-common/glibc_compat.c
${CMAKE_CURRENT_SOURCE_DIR}/build_test_harness.sh
)

add_library(crypto UNKNOWN IMPORTED GLOBAL)
Expand Down Expand Up @@ -130,6 +156,45 @@ target_compile_options(ssl INTERFACE
target_compile_options(global-group INTERFACE "-Wno-deprecated-declarations")
target_compile_options(global-group INTERFACE "-Wno-poison-system-directories")

# ── Test harness IMPORTED libraries ──────────────────────────────────────────
# These archives are built inside Docker (build_test_harness.sh), partially
# linked with libstdc++ via `ld -r`, and symbol-localized so only the entry
# point is globally visible. No --allow-multiple-definition needed.

add_library(awslc_shim STATIC IMPORTED GLOBAL)
add_dependencies(awslc_shim build-awslc)
set_target_properties(awslc_shim PROPERTIES
IMPORTED_LOCATION "${AWSLC_BINARIES_DIR}/libawslc_shim.a")

add_library(awslc_handshaker STATIC IMPORTED GLOBAL)
add_dependencies(awslc_handshaker build-awslc)
set_target_properties(awslc_handshaker PROPERTIES
IMPORTED_LOCATION "${AWSLC_BINARIES_DIR}/libawslc_handshaker.a")

add_library(awslc_acvp_server STATIC IMPORTED GLOBAL)
add_dependencies(awslc_acvp_server build-awslc)
set_target_properties(awslc_acvp_server PROPERTIES
IMPORTED_LOCATION "${AWSLC_BINARIES_DIR}/libawslc_acvp_server.a")

# ── Test harness program libraries ───────────────────────────────────────────
# Linked into the main clickhouse binary via clickhouse_program_install()
# in programs/CMakeLists.txt. The entry-point .cpp files stay in programs/.

add_library(clickhouse-ssl-shim-lib
${ClickHouse_SOURCE_DIR}/programs/ssl-shim/SslShim.cpp)
target_link_libraries(clickhouse-ssl-shim-lib PRIVATE awslc_shim ssl crypto)
add_dependencies(clickhouse-ssl-shim-lib build-awslc)

add_library(clickhouse-ssl-handshaker-lib
${ClickHouse_SOURCE_DIR}/programs/ssl-handshaker/SslHandshaker.cpp)
target_link_libraries(clickhouse-ssl-handshaker-lib PRIVATE awslc_handshaker ssl crypto)
add_dependencies(clickhouse-ssl-handshaker-lib build-awslc)

add_library(clickhouse-acvp-server-lib
${ClickHouse_SOURCE_DIR}/programs/acvp-server/AcvpServer.cpp)
target_link_libraries(clickhouse-acvp-server-lib PRIVATE awslc_acvp_server crypto)
add_dependencies(clickhouse-acvp-server-lib build-awslc)

else() # FIPS_CLICKHOUSE


Expand Down
6 changes: 6 additions & 0 deletions contrib/openssl-cmake/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,9 @@ RUN test $(/aws-lc-AWS-LC-FIPS-2.0.0/build/tool/bssl isfips) = 1

# execute all test
RUN find /aws-lc-AWS-LC-FIPS-2.0.0/build -iname '*test*' -type f -executable -print -exec {} \;

# Build test harness libraries for ClickHouse FIPS testing integration
COPY posix_spawn_2.c glibc_compat.c /tmp/
COPY build_test_harness.sh /tmp/
RUN chmod +x /tmp/build_test_harness.sh && \
/tmp/build_test_harness.sh /aws-lc-AWS-LC-FIPS-2.0.0 /harness-output
6 changes: 6 additions & 0 deletions contrib/openssl-cmake/Dockerfile.aarch64
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,9 @@ RUN test $(/aws-lc-AWS-LC-FIPS-2.0.0/build/tool/bssl isfips) = 1

# execute all test
RUN find /aws-lc-AWS-LC-FIPS-2.0.0/build -iname '*test*' -type f -executable -print -exec {} \;

# Build test harness libraries for ClickHouse FIPS testing integration
COPY posix_spawn_2.c glibc_compat.c /tmp/
COPY build_test_harness.sh /tmp/
RUN chmod +x /tmp/build_test_harness.sh && \
/tmp/build_test_harness.sh /aws-lc-AWS-LC-FIPS-2.0.0 /harness-output
95 changes: 95 additions & 0 deletions contrib/openssl-cmake/build_test_harness.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/bin/bash
# Build test harness static libraries for ClickHouse FIPS testing integration.
#
# Each library is partially linked with libstdc++ via `ld -r` and then all
# symbols are prefixed with __awslc_ using `objcopy --prefix-symbols`.
# Undefined symbols (libssl/libcrypto/libc refs) and the entry point are
# restored to their original names via `--redefine-syms`.
#
# This prevents libstdc++ symbols from colliding with ClickHouse's libc++
# at final link time, while keeping COMDAT groups intact (localizing COMDAT
# key symbols would cause lld to discard their sections).
#
# Usage: build_test_harness.sh <awslc-src-dir> <output-dir>
set -ex

SRC=${1:?usage: build_test_harness.sh <awslc-src-dir> <output-dir>}
OUTDIR=${2:?usage: build_test_harness.sh <awslc-src-dir> <output-dir>}
mkdir -p "$OUTDIR"

CXXFLAGS="-std=c++17 -fPIC -g -O2 -fno-exceptions -w"
CFLAGS="-fPIC -O2 -w"
INC="-I$SRC/include -I$SRC -I$SRC/ssl/test"
STDCXX=$(c++ -print-file-name=libstdc++.a)
PREFIX="__awslc_"

# build_target <name> <entry_grep> <obj_dir>
# Partial-links .o files in <obj_dir> with libstdc++, prefixes all symbols,
# then restores undefined refs and entry point to original names.
build_target() {
local name=$1 entry_grep=$2 obj_dir=$3
ld -r -o "$obj_dir/combined.o" "$obj_dir"/*.o "$STDCXX"

# Collect undefined symbols — these reference external libraries
# (libssl, libcrypto, libc, pthreads) and must keep their original names.
nm -u "$obj_dir/combined.o" | awk 'NF>=2{print $NF}' | sort -u > "$obj_dir/undef.txt"

# Find entry point symbol
nm "$obj_dir/combined.o" | awk "/T.*${entry_grep}/{print \$3}" > "$obj_dir/entry.txt"

# Build redefine map: after --prefix-symbols adds the prefix,
# restore undefined symbols and entry point to original names.
awk -v p="$PREFIX" '{print p $0 " " $0}' "$obj_dir/undef.txt" > "$obj_dir/redefine.txt"
awk -v p="$PREFIX" '{print p $0 " " $0}' "$obj_dir/entry.txt" >> "$obj_dir/redefine.txt"

# Two passes: objcopy applies --redefine-syms BEFORE --prefix-symbols
# in a single invocation, so we must split them.
# Pass 1: prefix every symbol.
objcopy --prefix-symbols="$PREFIX" "$obj_dir/combined.o"
# Pass 2: restore undefined refs + entry point to original names,
# and weaken all defined symbols so duplicates across archives
# (same libstdc++ members pulled into shim, handshaker, acvp) don't clash.
objcopy --redefine-syms="$obj_dir/redefine.txt" --weaken "$obj_dir/combined.o"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this weaken all global symbols? I think we only want to weaken defined symbols (embedded libstdc++ internals) while keeping external references strong. I think this might fix the segfaults I'm running into with ssl-shim.

Something like this?

nm --defined-only "$obj_dir/combined.o" | awk 'NF>=3{print $3}' | sort -u > "$obj_dir/defined_syms.txt"
awk -v p="$PREFIX" '{print p $0}' "$obj_dir/defined_syms.txt" > "$obj_dir/weaken_list.txt"
objcopy --redefine-syms="$obj_dir/redefine.txt" --weaken-symbols="$obj_dir/weaken_list.txt" "$obj_dir/combined.o"

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in light of the findings, reverted the PR #1565, will re-open this proposed set of changes in the third on of the series. Where we'll test the proposed fix as well...

BTW, @DimensionWieldr do you have a test that reliable reproduces the crashes? That would simplify the fix

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This piece of code weaken all defined symbols so duplicates across archive only affects some of the symbols in test-related code, (ssl-shim, ssl-handshaker, and acvp-server), like: C++ std lib symbols, any duplicates, etc. Everything that is supposed to be known ant run-time is restored back:

  • undefined symbols == external dependencies, like malloc, SSL-API, etc
  • entry-point symbols == bssl_shim_main, handshaker_main, acvp_modulewrapper_main

And symbols from the rest of clickhouse are left as is (and in fact there is no way to modify those here).

Copy link
Copy Markdown
Member Author

@Enmk Enmk Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only one possibility that comes to mind: some symbols are missing, meaning we've not built/linked corresponding source file. Hence weak symbols are resolved to "NULL" at link-time, and will cause segfault.

Copy link
Copy Markdown
Collaborator

@DimensionWieldr DimensionWieldr Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, maybe some symbols are missing.

I have a test on the fips-testing branch at https://github.com/Altinity/clickhouse-regression/blob/fips-testing/ssl_server/tests/fips_140_3.py#L753 that I run with ./regression.py --local --clickhouse https://s3.amazonaws.com/altinity-build-artifacts/PRs/1560/9c61bc52473f908e9126ddb12284ba82850b238e/package_release/clickhouse-common-static_25.3.8.10134.altinitytest_amd64.deb --force-fips --only "/ssl server/part 2/fips 140-3/aws-lc test suites/*" -l test.log. (Run from clickhouse-regression/ssl_server)

Copy link
Copy Markdown
Member Author

@Enmk Enmk Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hastily merged this PR, it is re-done in #1567

@DimensionWieldr let's continue conversation there


ar rcs "$OUTDIR/lib${name}.a" "$obj_dir/combined.o"
rm -rf "$obj_dir"
}

# --- ssl-shim ---
OBJ=$(mktemp -d)
for f in async_bio bssl_shim handshake_util mock_quic_transport \
packeted_bio settings_writer ssl_transfer test_config test_state; do
EXTRA="-Dposix_spawn=__ssl_posix_spawn"
[ "$f" = "bssl_shim" ] && EXTRA="$EXTRA -Dmain=bssl_shim_main"
c++ $CXXFLAGS $INC $EXTRA -c "$SRC/ssl/test/$f.cc" -o "$OBJ/$f.o"
done
c++ $CXXFLAGS $INC -Dposix_spawn=__ssl_posix_spawn \
-c "$SRC/crypto/test/test_util.cc" -o "$OBJ/test_util.o"
cc $CFLAGS -c /tmp/posix_spawn_2.c -o "$OBJ/posix_spawn_2.o"
cc $CFLAGS -c /tmp/glibc_compat.c -o "$OBJ/glibc_compat.o"
build_target awslc_shim bssl_shim_main "$OBJ"

# --- ssl-handshaker ---
OBJ=$(mktemp -d)
for f in async_bio handshake_util handshaker mock_quic_transport \
packeted_bio settings_writer test_config test_state; do
EXTRA="-Dposix_spawn=__ssl_posix_spawn"
[ "$f" = "handshaker" ] && EXTRA="$EXTRA -Dmain=handshaker_main"
c++ $CXXFLAGS $INC $EXTRA -c "$SRC/ssl/test/$f.cc" -o "$OBJ/$f.o"
done
c++ $CXXFLAGS $INC -Dposix_spawn=__ssl_posix_spawn \
-c "$SRC/crypto/test/test_util.cc" -o "$OBJ/test_util.o"
cc $CFLAGS -c /tmp/posix_spawn_2.c -o "$OBJ/posix_spawn_2.o"
cc $CFLAGS -c /tmp/glibc_compat.c -o "$OBJ/glibc_compat.o"
build_target awslc_handshaker handshaker_main "$OBJ"

# --- acvp-server ---
OBJ=$(mktemp -d)
ACVP_DIR="$SRC/util/fipstools/acvp/modulewrapper"
c++ $CXXFLAGS -I"$ACVP_DIR" -I"$SRC/include" -I"$SRC" \
-Dmain=acvp_modulewrapper_main \
-c "$ACVP_DIR/main.cc" -o "$OBJ/main.o"
c++ $CXXFLAGS -I"$ACVP_DIR" -I"$SRC/include" -I"$SRC" \
-c "$ACVP_DIR/modulewrapper.cc" -o "$OBJ/modulewrapper.o"
cc $CFLAGS -c /tmp/glibc_compat.c -o "$OBJ/glibc_compat.o"
build_target awslc_acvp_server acvp_modulewrapper_main "$OBJ"
16 changes: 16 additions & 0 deletions programs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ else()
message(STATUS "ClickHouse keeper-client mode: OFF")
endif()

if (FIPS_CLICKHOUSE AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(ENABLE_CLICKHOUSE_SSL_SHIM 1)
set(ENABLE_CLICKHOUSE_SSL_HANDSHAKER 1)
set(ENABLE_CLICKHOUSE_ACVP_SERVER 1)
endif()

configure_file (config_tools.h.in ${CONFIG_INCLUDE_PATH}/config_tools.h)

macro(clickhouse_target_link_split_lib target name)
Expand Down Expand Up @@ -225,6 +231,16 @@ if (ENABLE_CLICKHOUSE_KEEPER_CLIENT)
list(APPEND CLICKHOUSE_BUNDLE clickhouse-keeper-client)
endif ()

if (ENABLE_CLICKHOUSE_SSL_SHIM)
clickhouse_program_install(clickhouse-ssl-shim ssl-shim)
endif()
if (ENABLE_CLICKHOUSE_SSL_HANDSHAKER)
clickhouse_program_install(clickhouse-ssl-handshaker ssl-handshaker)
endif()
if (ENABLE_CLICKHOUSE_ACVP_SERVER)
clickhouse_program_install(clickhouse-acvp-server acvp-server)
endif()

add_custom_target (clickhouse-bundle ALL DEPENDS ${CLICKHOUSE_BUNDLE})

if (USE_BINARY_HASH)
Expand Down
6 changes: 6 additions & 0 deletions programs/acvp-server/AcvpServer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
extern int acvp_modulewrapper_main(int argc, char ** argv);

int mainEntryClickHouseAcvpServer(int argc, char ** argv)
{
return acvp_modulewrapper_main(argc, argv);
}
3 changes: 3 additions & 0 deletions programs/config_tools.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@
#cmakedefine01 ENABLE_CLICKHOUSE_KEEPER
#cmakedefine01 ENABLE_CLICKHOUSE_KEEPER_CLIENT
#cmakedefine01 ENABLE_CLICKHOUSE_KEEPER_CONVERTER
#cmakedefine01 ENABLE_CLICKHOUSE_SSL_SHIM
#cmakedefine01 ENABLE_CLICKHOUSE_SSL_HANDSHAKER
#cmakedefine01 ENABLE_CLICKHOUSE_ACVP_SERVER
19 changes: 19 additions & 0 deletions programs/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@ int mainEntryClickHouseKeeperBench(int argc, char ** argv);
int mainEntryClickHouseKeeperDataDumper(int argc, char ** argv);
#endif

#if ENABLE_CLICKHOUSE_SSL_SHIM
int mainEntryClickHouseSslShim(int argc, char ** argv);
#endif
#if ENABLE_CLICKHOUSE_SSL_HANDSHAKER
int mainEntryClickHouseSslHandshaker(int argc, char ** argv);
#endif
#if ENABLE_CLICKHOUSE_ACVP_SERVER
int mainEntryClickHouseAcvpServer(int argc, char ** argv);
#endif

// install
int mainEntryClickHouseInstall(int argc, char ** argv);
int mainEntryClickHouseStart(int argc, char ** argv);
Expand Down Expand Up @@ -115,6 +125,15 @@ std::pair<std::string_view, MainFunc> clickhouse_applications[] =
#endif
#if USE_NURAFT
{"keeper-data-dumper", mainEntryClickHouseKeeperDataDumper},
#endif
#if ENABLE_CLICKHOUSE_SSL_SHIM
{"ssl-shim", mainEntryClickHouseSslShim},
#endif
#if ENABLE_CLICKHOUSE_SSL_HANDSHAKER
{"ssl-handshaker", mainEntryClickHouseSslHandshaker},
#endif
#if ENABLE_CLICKHOUSE_ACVP_SERVER
{"acvp-server", mainEntryClickHouseAcvpServer},
#endif
// install
{"install", mainEntryClickHouseInstall},
Expand Down
Loading
Loading