From 8c52f6a64fc300a1d86c1ae7d0d235f38b785402 Mon Sep 17 00:00:00 2001 From: Cameron Bytheway Date: Fri, 3 Sep 2021 14:29:29 -0700 Subject: [PATCH] build: add libcrypto interning tests (#3035) --- CMakeLists.txt | 6 -- codebuild/bin/install_openssl_1_0_2.sh | 4 +- codebuild/bin/install_openssl_1_1_1.sh | 4 +- codebuild/bin/s2n_codebuild.sh | 1 + codebuild/bin/test_libcrypto_interning.sh | 98 +++++++++++++++++++++++ codebuild/spec/buildspec_omnibus.yml | 9 +++ 6 files changed, 114 insertions(+), 8 deletions(-) create mode 100755 codebuild/bin/test_libcrypto_interning.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 74e4a18c35a..f58303a67ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -532,12 +532,6 @@ if (BUILD_TESTING) target_include_directories(s2nd PRIVATE api) target_compile_options(s2nd PRIVATE -std=gnu99 -D_POSIX_C_SOURCE=200112L) - # if we've interned libcrypto, try linking to the public version here to ensure we don't get any symbol collisions - if (S2N_INTERN_LIBCRYPTO) - target_link_libraries(s2nd crypto) - target_link_libraries(s2nc crypto) - endif() - if(BENCHMARK) find_package(benchmark REQUIRED) file(GLOB BENCHMARK_SRC "tests/benchmark/*.cc") diff --git a/codebuild/bin/install_openssl_1_0_2.sh b/codebuild/bin/install_openssl_1_0_2.sh index 24012b1e6ff..ee4a24fd592 100755 --- a/codebuild/bin/install_openssl_1_0_2.sh +++ b/codebuild/bin/install_openssl_1_0_2.sh @@ -30,6 +30,7 @@ INSTALL_DIR=$2 OS_NAME=$3 source codebuild/bin/jobs.sh +mkdir -p $BUILD_DIR cd "$BUILD_DIR" curl --retry 3 -L https://github.com/openssl/openssl/archive/OpenSSL_1_0_2-stable.zip --output openssl-OpenSSL_1_0_2-stable.zip unzip openssl-OpenSSL_1_0_2-stable.zip @@ -44,7 +45,8 @@ else usage fi -$CONFIGURE -g3 -fPIC no-libunbound no-gmp no-jpake no-krb5 no-md2 no-rc5 no-rfc3779 no-sctp no-ssl-trace \ +mkdir -p $INSTALL_DIR +$CONFIGURE shared -g3 -fPIC no-libunbound no-gmp no-jpake no-krb5 no-md2 no-rc5 no-rfc3779 no-sctp no-ssl-trace \ no-store no-zlib no-hw no-mdc2 no-seed no-idea enable-ec_nistp_64_gcc_128 no-camellia no-bf no-ripemd \ no-dsa no-ssl2 no-capieng -DSSL_FORBID_ENULL -DOPENSSL_NO_DTLS1 -DOPENSSL_NO_HEARTBEATS \ --prefix="$INSTALL_DIR" diff --git a/codebuild/bin/install_openssl_1_1_1.sh b/codebuild/bin/install_openssl_1_1_1.sh index 85a08713ab7..625cc316090 100755 --- a/codebuild/bin/install_openssl_1_1_1.sh +++ b/codebuild/bin/install_openssl_1_1_1.sh @@ -31,6 +31,7 @@ OS_NAME=$3 source codebuild/bin/jobs.sh RELEASE=1_1_1k +mkdir -p $BUILD_DIR cd "$BUILD_DIR" curl --retry 3 -L https://github.com/openssl/openssl/archive/OpenSSL_${RELEASE}.zip --output OpenSSL_${RELEASE}.zip unzip OpenSSL_${RELEASE}.zip @@ -45,8 +46,9 @@ else usage fi +mkdir -p $INSTALL_DIR # Use g3 to get debug symbols in libcrypto to chase memory leaks -$CONFIGURE -g3 -fPIC \ +$CONFIGURE shared -g3 -fPIC \ no-md2 no-rc5 no-rfc3779 no-sctp no-ssl-trace no-zlib \ no-hw no-mdc2 no-seed no-idea enable-ec_nistp_64_gcc_128 no-camellia\ no-bf no-ripemd no-dsa no-ssl2 no-ssl3 no-capieng \ diff --git a/codebuild/bin/s2n_codebuild.sh b/codebuild/bin/s2n_codebuild.sh index 6299a2a6baf..54b61a5a59b 100755 --- a/codebuild/bin/s2n_codebuild.sh +++ b/codebuild/bin/s2n_codebuild.sh @@ -70,6 +70,7 @@ if [[ "$TESTS" == "ALL" || "$TESTS" == "sawHMACPlus" ]] && [[ "$OS_NAME" == "lin # Run Individual tests if [[ "$TESTS" == "ALL" || "$TESTS" == "unit" ]]; then cmake . -Bbuild -DCMAKE_PREFIX_PATH=$LIBCRYPTO_ROOT -D${CMAKE_PQ_OPTION}; cmake --build ./build; make -C build test ARGS=-j$(nproc); fi +if [[ "$TESTS" == "ALL" || "$TESTS" == "interning" ]]; then ./codebuild/bin/test_libcrypto_interning.sh; fi if [[ "$TESTS" == "ALL" || "$TESTS" == "asan" ]]; then make clean; S2N_ADDRESS_SANITIZER=1 make -j $JOBS ; fi if [[ "$TESTS" == "ALL" || "$TESTS" == "integration" ]]; then make clean; make integration ; fi if [[ "$TESTS" == "ALL" || "$TESTS" == "integrationv2" ]]; then make clean; make integrationv2 ; fi diff --git a/codebuild/bin/test_libcrypto_interning.sh b/codebuild/bin/test_libcrypto_interning.sh new file mode 100755 index 00000000000..f93d7f4cf9c --- /dev/null +++ b/codebuild/bin/test_libcrypto_interning.sh @@ -0,0 +1,98 @@ +#!/usr/bin/env bash +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). +# You may not use this file except in compliance with the License. +# A copy of the License is located at +# +# http://aws.amazon.com/apache2.0 +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. +# + +set -e + + +source codebuild/bin/jobs.sh + +# build 2 different version of libcrypto to make it easy to break the application if +# interning doesn't work as expected +OPENSSL_1_1="$(pwd)/build/openssl_1_1" +OPENSSL_1_0="$(pwd)/build/openssl_1_0" +if [ ! -f $OPENSSL_1_0/lib/libcrypto.a ]; then + ./codebuild/bin/install_openssl_1_0_2.sh $OPENSSL_1_0/src $OPENSSL_1_0 linux +fi +if [ ! -f $OPENSSL_1_1/lib/libcrypto.a ]; then + ./codebuild/bin/install_openssl_1_1_1.sh $OPENSSL_1_1/src $OPENSSL_1_1 linux +fi + +function fail() { + echo "test failure: $1" + exit 1 +} + +# build a default version to test what happens without interning +cmake . -Bbuild/shared-default -DCMAKE_PREFIX_PATH="$OPENSSL_1_1" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=on -DBUILD_TESTING=on +cmake --build ./build/shared-default -- -j $JOBS +ldd ./build/shared-default/lib/libs2n.so | grep -q libcrypto || fail "libcrypto was not linked" + +# ensure libcrypto interning works with shared libs and testing +cmake . -Bbuild/shared-testing -DCMAKE_PREFIX_PATH="$OPENSSL_1_1" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=on -DBUILD_TESTING=on -DS2N_INTERN_LIBCRYPTO=on +cmake --build ./build/shared-testing -- -j $JOBS +make -C build/shared-testing test ARGS="-j $JOBS" +# s2n should not publicly depend on libcrypto +ldd ./build/shared-testing/lib/libs2n.so | grep -q libcrypto && fail "libcrypto was not interned" + +# ensure libcrypto interning works with shared libs and no testing +cmake . -Bbuild/shared -DCMAKE_PREFIX_PATH="$OPENSSL_1_1" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=on -DBUILD_TESTING=off -DS2N_INTERN_LIBCRYPTO=on +cmake --build ./build/shared -- -j $JOBS +# s2n should not publicly depend on libcrypto +ldd ./build/shared/lib/libs2n.so | grep -q libcrypto && fail "libcrypto was not interned" + +# ensure libcrypto interning works with static libs +# NOTE: static builds don't vary based on testing being enabled +cmake . -Bbuild/static -DCMAKE_PREFIX_PATH="$OPENSSL_1_1" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=off -DBUILD_TESTING=on -DS2N_INTERN_LIBCRYPTO=on +cmake --build ./build/static -- -j $JOBS +make -C build/static test ARGS="-j $JOBS" + +# create a small app that links against both s2n and libcrypto +cat < build/static/app.c +#include +#include + +int main() { + s2n_init(); + BN_CTX_new(); + return 0; +} +EOF + +# ensure the small app will compile with both versions of openssl without any linking issues +for target in $OPENSSL_1_0 $OPENSSL_1_1 +do + echo "testing static linking with $target" + mkdir -p $target/bin + cc -fPIE -Iapi -I$target/include build/static/app.c build/static/lib/libs2n.a $target/lib/libcrypto.a -lpthread -ldl -o $target/bin/test-app + nm $target/bin/test-app | grep -q 'T s2n$BN_CTX_new' || fail "libcrypto symbols were not prefixed" + nm $target/bin/test-app | grep -q 'T BN_CTX_new' || fail "libcrypto was not linked in application" + # make sure the app doesn't crash + $target/bin/test-app +done + +# without interning, the connection should fail when linking the wrong version of libcrypto +LD_PRELOAD=$OPENSSL_1_0/lib/libcrypto.so ./build/shared-default/bin/s2nd -c default_tls13 localhost 4433 & +SERVER_PID=$! +! LD_PRELOAD=$OPENSSL_1_0/lib/libcrypto.so ./build/shared-default/bin/s2nc -i -c default_tls13 localhost 4433 +kill $SERVER_PID || true + +# with interning, the connection should succeed even though we've linked the wrong version of libcrypto +LD_PRELOAD=$OPENSSL_1_0/lib/libcrypto.so ./build/shared-testing/bin/s2nd -c default_tls13 localhost 4433 & +SERVER_PID=$! +LD_PRELOAD=$OPENSSL_1_0/lib/libcrypto.so ./build/shared-testing/bin/s2nc -i -c default_tls13 localhost 4433 | tee build/client.log +kill $SERVER_PID || true + +# ensure a TLS 1.3 session was negotiated +grep -q "Actual protocol version: 34" build/client.log || fail "TLS 1.3 was not negotiated" diff --git a/codebuild/spec/buildspec_omnibus.yml b/codebuild/spec/buildspec_omnibus.yml index 45ac691c969..21fce1732c0 100644 --- a/codebuild/spec/buildspec_omnibus.yml +++ b/codebuild/spec/buildspec_omnibus.yml @@ -353,6 +353,15 @@ batch: TESTS: unit S2N_NO_PQ: 1 + - identifier: s2nLibcryptoInterning + buildspec: codebuild/spec/buildspec_ubuntu.yml + env: + privileged-mode: true + compute-type: BUILD_GENERAL1_LARGE + variables: + TESTS: interning + BUILD_S2N: 'true' + # Fuzz tests - identifier: s2nFuzzerOpenSSL111Coverage buildspec: codebuild/spec/buildspec_ubuntu_fuzz_artifacts.yml