diff --git a/.github/workflows/replace-default.yml b/.github/workflows/replace-default.yml new file mode 100644 index 00000000..4a9860e8 --- /dev/null +++ b/.github/workflows/replace-default.yml @@ -0,0 +1,66 @@ +name: Replace Default Tests + +# START OF COMMON SECTION +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +# END OF COMMON SECTION + +jobs: + replace_default_test: + name: Replace Default Test + runs-on: ubuntu-22.04 + timeout-minutes: 30 + strategy: + matrix: + # Test both standard and replace-default builds + replace_default: ['', '--replace-default'] + # Test with stable versions + wolfssl_ref: ['v5.8.0-stable'] + openssl_ref: ['openssl-3.5.0'] + steps: + - name: Checkout wolfProvider + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Build wolfProvider ${{ matrix.replace_default && 'with replace-default' || 'standard' }} + run: | + OPENSSL_TAG=${{ matrix.openssl_ref }} \ + WOLFSSL_TAG=${{ matrix.wolfssl_ref }} \ + ./scripts/build-wolfprovider.sh ${{ matrix.replace_default }} + + - name: Run standalone test suite + run: | + ./test/standalone/runners/run_standalone_tests.sh + + - name: Print errors on failure + if: ${{ failure() }} + run: | + # Build failure log + if [ -f scripts/build-release.log ]; then + echo "=== Build log (last 50 lines) ===" + tail -n 50 scripts/build-release.log + fi + + # Test suite failure log + if [ -f test-suite.log ]; then + echo "=== Test suite log ===" + cat test-suite.log + fi + + # Standalone test failures + if [ -d test/standalone/runners/test_results ]; then + for log in test/standalone/runners/test_results/*.log; do + if [ -f "$log" ]; then + echo "=== $log ===" + cat "$log" + fi + done + fi diff --git a/.gitignore b/.gitignore index 6c79bf33..483d9a6c 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,30 @@ /wolfprov-install/ /artifacts +# Default stub autotools files +default_stub/ar-lib +default_stub/compile +default_stub/config.guess +default_stub/config.sub +default_stub/depcomp +default_stub/install-sh +default_stub/ltmain.sh +default_stub/missing + +# Build install directories +*-install/ + +# Libtool archive files +*.la + +# Test artifacts in subdirectories +test/**/*.log +test/**/*.test +test/**/*.trs +test/**/*.o +test/**/.deps/ +test/**/.dirstamp + IDE/Android/android-ndk-r26b/ IDE/Android/openssl-source/ IDE/Android/openssl-install/ diff --git a/Makefile.am b/Makefile.am index 69ad2f6a..6d3e43af 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,5 @@ -SUFFIXES = +SUFFIXES = TESTS = noinst_PROGRAMS = noinst_HEADERS = @@ -14,6 +14,15 @@ AM_CPPFLAGS = -I$(top_srcdir)/include lib_LTLIBRARIES = libwolfprov.la +# Conditionally build libdefault.so when --replace-default is enabled +if BUILD_REPLACE_DEFAULT +# Install libdefault.la directly to OpenSSL lib directory +openssldir = $(OPENSSL_LIB_DIR) +openssl_LTLIBRARIES = libdefault.la +libdefault_la_SOURCES = src/wp_default_replace.c +libdefault_la_LIBADD = libwolfprov.la +endif + EXTRA_DIST+=ChangeLog.md EXTRA_DIST+=README.md EXTRA_DIST+=IDE diff --git a/configure.ac b/configure.ac index d1962b1b..17e31303 100644 --- a/configure.ac +++ b/configure.ac @@ -123,8 +123,26 @@ AS_IF([ test "x$ENABLED_SINGLETHREADED" = "xno" ],[ ]) ]) +# Replace default provider +AC_ARG_ENABLE([replace-default], + [AS_HELP_STRING([--enable-replace-default],[Build real libdefault.so from wp_default_replace.c (default: disabled).])], + [ ENABLED_REPLACE_DEFAULT=$enableval ], + [ ENABLED_REPLACE_DEFAULT=no ] + ) - +AM_CONDITIONAL([BUILD_REPLACE_DEFAULT], [test "x$ENABLED_REPLACE_DEFAULT" = "xyes"]) + +# Set OpenSSL lib directory for installing libdefault.so +if test "x$ENABLED_REPLACE_DEFAULT" = "xyes"; then + if test -d "$OPENSSL_INSTALL_DIR/lib64"; then + OPENSSL_LIB_DIR="$OPENSSL_INSTALL_DIR/lib64" + elif test -d "$OPENSSL_INSTALL_DIR/lib"; then + OPENSSL_LIB_DIR="$OPENSSL_INSTALL_DIR/lib" + else + OPENSSL_LIB_DIR="$OPENSSL_INSTALL_DIR/lib" + fi +fi +AC_SUBST([OPENSSL_LIB_DIR]) AX_HARDEN_CC_COMPILER_FLAGS @@ -170,6 +188,7 @@ echo echo " Features " echo " * User settings: $ENABLED_USERSETTINGS" echo " * Dynamic provider: $ENABLED_DYNAMIC_PROVIDER" +echo " * Replace default: $ENABLED_REPLACE_DEFAULT" echo "" echo "---" diff --git a/default_stub/.gitignore b/default_stub/.gitignore new file mode 100644 index 00000000..f13db083 --- /dev/null +++ b/default_stub/.gitignore @@ -0,0 +1,15 @@ +Makefile +Makefile.in +.deps/ +.libs/ +*.la +*.lo +*.o +aclocal.m4 +autom4te.cache/ +config.log +config.status +configure +libtool +*.so +*.so.* diff --git a/default_stub/Makefile.am b/default_stub/Makefile.am new file mode 100644 index 00000000..e31303de --- /dev/null +++ b/default_stub/Makefile.am @@ -0,0 +1,2 @@ +lib_LTLIBRARIES = libdefault.la +libdefault_la_SOURCES = wp_default_stub.c diff --git a/default_stub/README.md b/default_stub/README.md new file mode 100644 index 00000000..3bf15917 --- /dev/null +++ b/default_stub/README.md @@ -0,0 +1,21 @@ +# libdefault - Default Provider Stub Library + +Minimal autotools build for a stub version of the default provider. + +## Building + +```bash +# Generate build system +./autogen.sh + +# Configure and build +./configure +make + +# Clean build artifacts +make clean +``` + +## Output + +The build produces `libdefault.so` in the `.libs/` directory. diff --git a/default_stub/autogen.sh b/default_stub/autogen.sh new file mode 100755 index 00000000..c350c05b --- /dev/null +++ b/default_stub/autogen.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +set -e + +autoreconf -fiv diff --git a/default_stub/configure.ac b/default_stub/configure.ac new file mode 100644 index 00000000..5c44872c --- /dev/null +++ b/default_stub/configure.ac @@ -0,0 +1,7 @@ +AC_INIT([libdefault], [1.0], [support@wolfssl.com]) +AM_INIT_AUTOMAKE([-Wall -Werror foreign]) +AC_PROG_CC +AM_PROG_AR +LT_INIT +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/default_stub/wp_default_stub.c b/default_stub/wp_default_stub.c new file mode 100644 index 00000000..52d9ea28 --- /dev/null +++ b/default_stub/wp_default_stub.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2006-2024 wolfSSL Inc. + * + * This file is part of wolfProvider. + * + * wolfProvider 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. + * + * wolfProvider 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 wolfProvider. If not, see . + */ + +#include + +/* Prototype of public function that initializes the wolfSSL provider. */ +OSSL_provider_init_fn wolfssl_provider_init; + +/* Prototype for the wolfprov_provider_init function */ +int wolfprov_provider_init(const OSSL_CORE_HANDLE* handle, + const OSSL_DISPATCH* in, + const OSSL_DISPATCH** out, + void** provCtx); + +/* + * Provider implementation stub + */ +int wolfprov_provider_init(const OSSL_CORE_HANDLE* handle, + const OSSL_DISPATCH* in, + const OSSL_DISPATCH** out, + void** provCtx) +{ + return 0; +} diff --git a/patches/README.md b/patches/README.md new file mode 100644 index 00000000..abfcd2cb --- /dev/null +++ b/patches/README.md @@ -0,0 +1,16 @@ +# OpenSSL Default Provider Replacement Patch + +> **Note**: For comprehensive Open Source Project (OSP) patches and integration work, visit the main wolfSSL OSP repository: **https://github.com/wolfSSL/osp/tree/master/wolfProvider** + +This directory contains the patch for replacing OpenSSL's default provider with wolfProvider. + +## Purpose + +The patch modifies OpenSSL's provider registration to substitute wolfProvider as the "default" provider, ensuring that all default provider operations are handled by wolfProvider instead of OpenSSL's built-in implementation. + +## Compatibility + +- **Supported Versions**: OpenSSL 3.0 and later +- **Patch Target**: `crypto/provider_predefined.c` + +This directory contains only the OpenSSL default provider replacement functionality. \ No newline at end of file diff --git a/patches/openssl3-replace-default.patch b/patches/openssl3-replace-default.patch new file mode 100644 index 00000000..37aa2578 --- /dev/null +++ b/patches/openssl3-replace-default.patch @@ -0,0 +1,30 @@ +diff --git a/crypto/provider_predefined.c b/crypto/provider_predefined.c +index 068e0b7..499a9ca 100644 +--- a/crypto/provider_predefined.c ++++ b/crypto/provider_predefined.c +@@ -10,21 +10,15 @@ + #include + #include "provider_local.h" + +-OSSL_provider_init_fn ossl_default_provider_init; ++OSSL_provider_init_fn wolfprov_provider_init; + OSSL_provider_init_fn ossl_base_provider_init; + OSSL_provider_init_fn ossl_null_provider_init; +-OSSL_provider_init_fn ossl_fips_intern_provider_init; +-#ifdef STATIC_LEGACY +-OSSL_provider_init_fn ossl_legacy_provider_init; +-#endif + const OSSL_PROVIDER_INFO ossl_predefined_providers[] = { + #ifdef FIPS_MODULE +- { "fips", NULL, ossl_fips_intern_provider_init, NULL, 1 }, ++ { "fips", NULL, wolfprov_provider_init, NULL, 1 }, + #else +- { "default", NULL, ossl_default_provider_init, NULL, 1 }, +-# ifdef STATIC_LEGACY +- { "legacy", NULL, ossl_legacy_provider_init, NULL, 0 }, +-# endif ++ { "default", NULL, wolfprov_provider_init, NULL, 1 }, ++ { "legacy", NULL, wolfprov_provider_init, NULL, 0 }, + { "base", NULL, ossl_base_provider_init, NULL, 0 }, + { "null", NULL, ossl_null_provider_init, NULL, 0 }, + #endif diff --git a/scripts/build-wolfprovider.sh b/scripts/build-wolfprovider.sh index 9aa46e7b..16f2584d 100755 --- a/scripts/build-wolfprovider.sh +++ b/scripts/build-wolfprovider.sh @@ -8,7 +8,7 @@ show_help() { echo "Script Arguments:" echo " --help, -help, -h Display this help menu and exit" echo " --clean Run make clean in OpenSSL, wolfSSL, and wolfProvider" - echo " --distclean Remove source directories of OpenSSL and wolfSSL" + echo " --distclean Remove source and install directories of OpenSSL, wolfSSL, and wolfProvider" echo " --debug Builds OpenSSL, wolfSSL, and WolfProvider with debugging enabled. This is the same as setting WOLFPROV_DEBUG=1" echo " --debug-asn-template Enable debug information for asn within wolfSSL" echo " --disable-err-trace No debug trace messages from library errors in wolfSSL" @@ -21,6 +21,7 @@ show_help() { echo " --debian Build a Debian package" echo " --debian --enable-fips Build a Debian package with FIPS support" echo " --quicktest Disable some tests for a faster testing suite" + echo " --replace-default Patch OpenSSL and build it so that wolfProvider is the default provider" echo "" echo "Environment Variables:" echo " OPENSSL_TAG OpenSSL tag to use (e.g., openssl-3.5.0)" @@ -30,7 +31,7 @@ show_help() { echo " WOLFSSL_FIPS_VERSION Version of wolfSSL FIPS bundle (v5, v6, ready), used as an argument for --enable-fips when configuring wolfSSL" echo " WOLFSSL_FIPS_CHECK_TAG Tag for wolfSSL FIPS bundle (linuxv5.2.1, v6.0.0, etc), used as an argument for fips-check.sh when cloning a wolfSSL FIPS version" echo " WOLFPROV_CLEAN If set to 1, run make clean in OpenSSL, wolfSSL, and wolfProvider" - echo " WOLFPROV_DISTCLEAN If set to 1, remove the source directories of OpenSSL and wolfSSL" + echo " WOLFPROV_DISTCLEAN If set to 1, remove the source and install directories of OpenSSL, wolfSSL, and wolfProvider" echo " WOLFPROV_DEBUG If set to 1, builds OpenSSL, wolfSSL, and wolfProvider with debug options enabled" echo " WOLFPROV_QUICKTEST If set to 1, disables some tests in the test suite to increase test speed" echo " WOLFPROV_DISABLE_ERR_TRACE If set to 1, wolfSSL will not be configured with --enable-debug-trace-errcodes=backtrace" @@ -82,7 +83,6 @@ for arg in "$@"; do WOLFSSL_ISFIPS=1 ;; --fips-bundle=*) - unset WOLFSSL_ISFIPS unset WOLFSSL_FIPS_CHECK_TAG IFS='=' read -r trash fips_bun <<< "$arg" if [ -z "$fips_bun" ]; then @@ -114,6 +114,9 @@ for arg in "$@"; do --quicktest) WOLFPROV_QUICKTEST=1 ;; + --replace-default) + WOLFPROV_REPLACE_DEFAULT=1 + ;; *) args_wrong+="$arg, " ;; @@ -145,6 +148,10 @@ source ${SCRIPT_DIR}/utils-wolfprovider.sh echo "Using openssl: $OPENSSL_TAG, wolfssl: $WOLFSSL_TAG" +if [ "$WOLFPROV_REPLACE_DEFAULT" = "1" ]; then + build_default_stub +fi + init_wolfprov exit $? diff --git a/scripts/env-setup b/scripts/env-setup index 4077cdff..46ca81ba 100755 --- a/scripts/env-setup +++ b/scripts/env-setup @@ -33,9 +33,9 @@ echo "PWD: $PWD" # Detect the openssl library path if [ -d $REPO_ROOT/openssl-install/lib ]; then - OPENSSL_LIB_PATH=$REPO_ROOT/openssl-install/lib + export OPENSSL_LIB_PATH=$REPO_ROOT/openssl-install/lib elif [ -d $REPO_ROOT/openssl-install/lib64 ]; then - OPENSSL_LIB_PATH=$REPO_ROOT/openssl-install/lib64 + export OPENSSL_LIB_PATH=$REPO_ROOT/openssl-install/lib64 else echo "Error: Could not find OpenSSL lib directory in $REPO_ROOT/openssl-install" exit 1 @@ -44,8 +44,9 @@ fi WOLFSSL_LIB_PATH="$REPO_ROOT/wolfssl-install/lib" WOLFPROV_LIB_PATH="$REPO_ROOT/wolfprov-install/lib" -# Set variables with default values if not already set -export LD_LIBRARY_PATH="${LD_LIBRARY_PATH:=$WOLFSSL_LIB_PATH:$OPENSSL_LIB_PATH}" +# Always reconstruct LD_LIBRARY_PATH with correctly detected OPENSSL_LIB_PATH +# ${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} expands to :$LD_LIBRARY_PATH only if LD_LIBRARY_PATH was already set +export LD_LIBRARY_PATH="$WOLFSSL_LIB_PATH:$OPENSSL_LIB_PATH${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" # Auto-detect FIPS mode and use appropriate config if [ "${WOLFSSL_ISFIPS:-0}" = "1" ]; then diff --git a/scripts/utils-openssl.sh b/scripts/utils-openssl.sh index 2fd908e7..ca320667 100755 --- a/scripts/utils-openssl.sh +++ b/scripts/utils-openssl.sh @@ -50,6 +50,8 @@ clean_openssl() { if [ "$WOLFPROV_DISTCLEAN" -eq "1" ]; then printf "Removing OpenSSL source ...\n" rm -rf "${OPENSSL_SOURCE_DIR}" + printf "Removing OpenSSL install ...\n" + rm -rf "${OPENSSL_INSTALL_DIR}" fi } @@ -93,19 +95,113 @@ clone_openssl() { fi } +check_openssl_replace_default_mismatch() { + local openssl_is_patched=0 + + # Check if the source was patched for --replace-default + if [ -f "${OPENSSL_SOURCE_DIR}/crypto/provider_predefined.c" ]; then + if grep -q "wolfprov_provider_init" "${OPENSSL_SOURCE_DIR}/crypto/provider_predefined.c" 2>/dev/null; then + openssl_is_patched=1 + printf "INFO: OpenSSL source modified - wolfProvider integrated as default provider (non-stock build).\n" + fi + fi + + # Check for mismatch + if [ "$WOLFPROV_REPLACE_DEFAULT" = "1" ] && [ "$openssl_is_patched" = "0" ]; then + printf "ERROR: --replace-default build mode mismatch!\n" + printf "Existing OpenSSL was built WITHOUT --replace-default patch\n" + printf "Current request: --replace-default build\n\n" + printf "Fix: ./scripts/build-wolfprovider.sh --distclean\n" + printf "Then rebuild with desired configuration.\n" + exit 1 + elif [ "$WOLFPROV_REPLACE_DEFAULT" != "1" ] && [ "$openssl_is_patched" = "1" ]; then + printf "ERROR: Standard build mode mismatch!\n" + printf "Existing OpenSSL was built WITH --replace-default patch\n" + printf "Current request: standard build\n\n" + printf "Fix: ./scripts/build-wolfprovider.sh --distclean\n" + printf "Then rebuild with desired configuration.\n" + exit 1 + fi +} + +patch_openssl() { + if [ "$WOLFPROV_REPLACE_DEFAULT" = "1" ]; then + + if [ -d "${OPENSSL_INSTALL_DIR}" ]; then + # If openssl is already installed, patching makes no sense as + # it will not be rebuilt. It may already be built as patched, + # just return and let check_openssl_replace_default_mismatch + # check for the mismatch. + return 0 + fi + + printf "\tApplying OpenSSL default provider patch ... " + cd ${OPENSSL_SOURCE_DIR} + + # Check if patch is already applied + if grep -q "wolfprov_provider_init" crypto/provider_predefined.c 2>/dev/null; then + printf "Already applied.\n" + return 0 + fi + + # Apply the patch + patch -p1 < ${SCRIPT_DIR}/../patches/openssl3-replace-default.patch >>$LOG_FILE 2>&1 + if [ $? != 0 ]; then + printf "ERROR.\n" + printf "\n\nPatch application failed. Last 40 lines of log:\n" + tail -n 40 $LOG_FILE + do_cleanup + exit 1 + fi + printf "Done.\n" + + cd ${SCRIPT_DIR}/.. + fi +} + install_openssl() { printf "\nInstalling OpenSSL ${OPENSSL_TAG} ...\n" clone_openssl + patch_openssl + check_openssl_replace_default_mismatch cd ${OPENSSL_SOURCE_DIR} if [ ! -d ${OPENSSL_INSTALL_DIR} ]; then printf "\tConfigure OpenSSL ${OPENSSL_TAG} ... " + + # Build configure command + CONFIG_CMD="./config shared --prefix=${OPENSSL_INSTALL_DIR}" if [ "$WOLFPROV_DEBUG" = "1" ]; then - ./config shared enable-trace --prefix=${OPENSSL_INSTALL_DIR} --debug >>$LOG_FILE 2>&1 - RET=$? + CONFIG_CMD+=" enable-trace --debug" + fi + if [ "$WOLFPROV_REPLACE_DEFAULT" = "1" ]; then + CONFIG_CMD+=" no-external-tests no-tests" + + # Set up library paths to find the stub libdefault + STUB_LIB_DIR=${SCRIPT_DIR}/../libdefault-stub-install/lib + if [ -d "${STUB_LIB_DIR}" ]; then + export PKG_CONFIG_PATH="${STUB_LIB_DIR}/pkgconfig:${PKG_CONFIG_PATH}" + # Link the stub library directly into libcrypto using LDFLAGS and LDLIBS + CONFIGURE_LDFLAGS="-L${STUB_LIB_DIR}" + CONFIGURE_LDLIBS="-ldefault" + else + printf "ERROR - stub libdefault not found in: ${STUB_LIB_DIR}\n" + do_cleanup + exit 1 + fi + fi + + # Execute configure + if [ "$WOLFPROV_REPLACE_DEFAULT" = "1" ]; then + $CONFIG_CMD LDFLAGS="${CONFIGURE_LDFLAGS}" LDLIBS="${CONFIGURE_LDLIBS}" >>$LOG_FILE 2>&1 else - ./config shared --prefix=${OPENSSL_INSTALL_DIR} >>$LOG_FILE 2>&1 - RET=$? + $CONFIG_CMD >>$LOG_FILE 2>&1 + fi + RET=$? + + # Clean up environment + if [ "$WOLFPROV_REPLACE_DEFAULT" = "1" ]; then + unset LDFLAGS fi if [ $RET != 0 ]; then printf "ERROR.\n" @@ -143,15 +239,18 @@ init_openssl() { install_openssl printf "\tOpenSSL ${OPENSSL_TAG} installed in: ${OPENSSL_INSTALL_DIR}\n" - OSSL_VER=`LD_LIBRARY_PATH=${OPENSSL_LIB_DIRS} $OPENSSL_BIN version | tail -n1` - case $OSSL_VER in - OpenSSL\ 3.*) ;; - *) - echo "OpenSSL ($OPENSSL_BIN) has wrong version: $OSSL_VER" - echo "Set: OPENSSL_DIR" - exit 1 - ;; - esac + # Skip version check for replace-default mode since we only build libraries + if [ "$WOLFPROV_REPLACE_DEFAULT" != "1" ]; then + OSSL_VER=`LD_LIBRARY_PATH=${OPENSSL_LIB_DIRS} $OPENSSL_BIN version | tail -n1` + case $OSSL_VER in + OpenSSL\ 3.*) ;; + *) + echo "OpenSSL ($OPENSSL_BIN) has wrong version: $OSSL_VER" + echo "Set: OPENSSL_DIR" + exit 1 + ;; + esac + fi if [ -z $LD_LIBRARY_PATH ]; then export LD_LIBRARY_PATH=${OPENSSL_LIB_DIRS} diff --git a/scripts/utils-wolfprovider.sh b/scripts/utils-wolfprovider.sh index 8b00f00c..f3d11481 100644 --- a/scripts/utils-wolfprovider.sh +++ b/scripts/utils-wolfprovider.sh @@ -25,6 +25,7 @@ source ${SCRIPT_DIR}/utils-general.sh WOLFPROV_SOURCE_DIR=${SCRIPT_DIR}/.. WOLFPROV_INSTALL_DIR=${SCRIPT_DIR}/../wolfprov-install +LIBDEFAULT_STUB_INSTALL_DIR=${SCRIPT_DIR}/../libdefault-stub-install WOLFPROV_WITH_WOLFSSL=--with-wolfssl=${WOLFSSL_INSTALL_DIR} # Check if using system wolfSSL installation @@ -57,6 +58,55 @@ WOLFPROV_DEBUG=${WOLFPROV_DEBUG:-0} WOLFPROV_CLEAN=${WOLFPROV_CLEAN:-0} WOLFPROV_DISTCLEAN=${WOLFPROV_DISTCLEAN:-0} +build_default_stub() { + printf "\nBuilding default stub library ...\n" + cd ${SCRIPT_DIR}/../default_stub + + printf "\tGenerate build system ... " + if [ ! -e "configure" ]; then + ./autogen.sh >>$LOG_FILE 2>&1 + if [ $? != 0 ]; then + printf "\n\n...\n" + tail -n 40 $LOG_FILE + do_cleanup + exit 1 + fi + fi + printf "Done.\n" + + printf "\tConfigure default stub ... " + ./configure --prefix=${LIBDEFAULT_STUB_INSTALL_DIR} >>$LOG_FILE 2>&1 + if [ $? != 0 ]; then + printf "\n\n...\n" + tail -n 40 $LOG_FILE + do_cleanup + exit 1 + fi + printf "Done.\n" + + printf "\tBuild default stub ... " + make >>$LOG_FILE 2>&1 + if [ $? != 0 ]; then + printf "\n\n...\n" + tail -n 40 $LOG_FILE + do_cleanup + exit 1 + fi + printf "Done.\n" + + printf "\tInstall default stub ... " + make install >>$LOG_FILE 2>&1 + if [ $? != 0 ]; then + printf "\n\n...\n" + tail -n 40 $LOG_FILE + do_cleanup + exit 1 + fi + printf "Done.\n" + + cd ${SCRIPT_DIR}/.. +} + clean_wolfprov() { printf "\n" @@ -65,19 +115,41 @@ clean_wolfprov() { if [ -f "Makefile" ]; then make clean >>$LOG_FILE 2>&1 fi + # Clean default_stub build artifacts + if [ -f "default_stub/Makefile" ]; then + printf "Cleaning default stub ...\n" + make -C default_stub clean >>$LOG_FILE 2>&1 + fi + # Remove root libdefault.la file + rm -f libdefault.la + rm -rf ${WOLFPROV_INSTALL_DIR} + fi + if [ "$WOLFPROV_DISTCLEAN" -eq "1" ]; then + printf "Removing wolfProvider install ...\n" rm -rf ${WOLFPROV_INSTALL_DIR} + rm -rf ${LIBDEFAULT_STUB_INSTALL_DIR} fi } install_wolfprov() { cd ${WOLFPROV_SOURCE_DIR} + # Add stub library path for replace-default functionality after dependencies are installed + if [ "$WOLFPROV_REPLACE_DEFAULT" = "1" ]; then + if [ -z "$LD_LIBRARY_PATH" ]; then + export LD_LIBRARY_PATH="${LIBDEFAULT_STUB_INSTALL_DIR}/lib" + else + export LD_LIBRARY_PATH="${LIBDEFAULT_STUB_INSTALL_DIR}/lib:$LD_LIBRARY_PATH" + fi + fi + init_openssl init_wolfssl printf "\nConsolidating wolfProvider ...\n" unset OPENSSL_MODULES unset OPENSSL_CONF + printf "LD_LIBRARY_PATH: $LD_LIBRARY_PATH\n" printf "\tConfigure wolfProvider ... " @@ -89,6 +161,10 @@ install_wolfprov() { WOLFPROV_CONFIG_OPTS+=" --enable-debug" fi + if [ "$WOLFPROV_REPLACE_DEFAULT" = "1" ]; then + WOLFPROV_CONFIG_OPTS+=" --enable-replace-default" + fi + ./configure ${WOLFPROV_CONFIG_OPTS} CFLAGS="${WOLFPROV_CONFIG_CFLAGS}" >>$LOG_FILE 2>&1 RET=$? diff --git a/scripts/utils-wolfssl.sh b/scripts/utils-wolfssl.sh index 45ac9cda..481929d9 100644 --- a/scripts/utils-wolfssl.sh +++ b/scripts/utils-wolfssl.sh @@ -49,6 +49,8 @@ clean_wolfssl() { if [ "$WOLFPROV_DISTCLEAN" -eq "1" ]; then printf "Removing wolfSSL source ...\n" rm -rf "${WOLFSSL_SOURCE_DIR}" + printf "Removing wolfSSL install ...\n" + rm -rf "${WOLFSSL_INSTALL_DIR}" fi } @@ -72,7 +74,10 @@ clone_wolfssl() { DEPTH_ARG=${WOLFPROV_DEBUG:+""} DEPTH_ARG=${DEPTH_ARG:---depth=1} - git clone ${DEPTH_ARG} -b ${CLONE_TAG} ${WOLFSSL_GIT} ${WOLFSSL_SOURCE_DIR} >>$LOG_FILE 2>&1 + # If we are replacing default provider, our current built openssl still + # links to the default stub and is non-functional. Run the clone with + # no explicitly LD_LIBRARY_PATH to ensure use of global openssl for clone + LD_LIBRARY_PATH="" git clone ${DEPTH_ARG} -b ${CLONE_TAG} ${WOLFSSL_GIT} ${WOLFSSL_SOURCE_DIR} >>$LOG_FILE 2>&1 RET=$? if [ $RET != 0 ]; then diff --git a/src/wp_default_replace.c b/src/wp_default_replace.c new file mode 100644 index 00000000..046a48ec --- /dev/null +++ b/src/wp_default_replace.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2006-2024 wolfSSL Inc. + * + * This file is part of wolfProvider. + * + * wolfProvider 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. + * + * wolfProvider 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 wolfProvider. If not, see . + */ + +/* + * wolfProvider Real Implementation for libdefault.so + * + * This is the real implementation of wolfprov_provider_init that bridges + * OpenSSL's default provider interface to wolfProvider by dynamically + * loading libwolfprov.so and calling wolfssl_provider_init. + * + * This replaces the stub implementation after wolfProvider is fully built. + */ + +#include + +/* Prototype of public function that initializes the wolfSSL provider. */ +OSSL_provider_init_fn wolfssl_provider_init; + +/* Prototype for the wolfprov_provider_init function */ +int wolfprov_provider_init(const OSSL_CORE_HANDLE* handle, + const OSSL_DISPATCH* in, + const OSSL_DISPATCH** out, + void** provCtx); + +/* + * Real implementation of wolfprov_provider_init. + * + * This function dynamically loads libwolfprov.so and calls its + * wolfssl_provider_init function to provide full wolfProvider functionality. + * + * @param [in] handle Handle to the core. + * @param [in] in Dispatch table from previous provider. + * @param [out] out Dispatch table of wolfSSL provider. + * @param [out] provCtx New provider context. + * @return 1 on success, 0 on failure. + */ +int wolfprov_provider_init(const OSSL_CORE_HANDLE* handle, + const OSSL_DISPATCH* in, + const OSSL_DISPATCH** out, + void** provCtx) +{ + return wolfssl_provider_init(handle, in, out, provCtx); +} diff --git a/test/include.am b/test/include.am index a2eed11c..6dbad0cc 100644 --- a/test/include.am +++ b/test/include.am @@ -35,3 +35,5 @@ test_unit_test_SOURCES = \ test_unit_test_LDADD = libwolfprov.la noinst_HEADERS += test/unit.h +# Include standalone binary tests +include test/standalone/include.am diff --git a/test/standalone/include.am b/test/standalone/include.am new file mode 100644 index 00000000..f61b2dba --- /dev/null +++ b/test/standalone/include.am @@ -0,0 +1,35 @@ +# vim:ft=automake +# included from test/include.am +# All paths should be given relative to the root + +# Standalone test programs use no extension - simple and clean! + +# Common standalone test headers +noinst_HEADERS += test/standalone/test_common.h + +# Standalone test programs +# Each test compiles to its own binary for isolated execution +# Note: These are NOT in check_PROGRAMS because they must be run through scripts, not directly +noinst_PROGRAMS += test/sha256_simple.test test/hardload.test +DISTCLEANFILES += test/.libs/sha256_simple.test test/.libs/hardload.test + +# Common flags for all standalone tests +STANDALONE_COMMON_CPPFLAGS = -DCERTS_DIR='"$(abs_top_srcdir)/certs"' \ + -I$(srcdir)/test/standalone +STANDALONE_COMMON_LDADD = libwolfprov.la + +# Individual test configurations +test_sha256_simple_test_CPPFLAGS = $(STANDALONE_COMMON_CPPFLAGS) +test_sha256_simple_test_SOURCES = test/standalone/tests/sha256_simple/test_sha256_simple.c +test_sha256_simple_test_LDADD = $(STANDALONE_COMMON_LDADD) + +test_hardload_test_CPPFLAGS = $(STANDALONE_COMMON_CPPFLAGS) +test_hardload_test_SOURCES = test/standalone/tests/hardload/test_hardload.c +test_hardload_test_LDADD = $(STANDALONE_COMMON_LDADD) + +# Common test utilities are built automatically by automake + +# Standalone tests are available for manual execution but not part of make check +# Run manually with: ./test/standalone/runners/run_standalone_tests.sh + +# Note: test results are cleaned by the test runner automatically diff --git a/test/standalone/provider-default.conf b/test/standalone/provider-default.conf new file mode 100644 index 00000000..12da8cb5 --- /dev/null +++ b/test/standalone/provider-default.conf @@ -0,0 +1,10 @@ +openssl_conf = openssl_init + +[openssl_init] +providers = provider_sect + +[provider_sect] +default = default_sect + +[default_sect] +activate = 1 diff --git a/test/standalone/runners/run_standalone_tests.sh b/test/standalone/runners/run_standalone_tests.sh new file mode 100755 index 00000000..9fcf6c01 --- /dev/null +++ b/test/standalone/runners/run_standalone_tests.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# run_standalone_tests.sh - Master runner for all standalone tests + +set -e + +# Get the directory of this script and find the root +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "$SCRIPT_DIR/../../.." && pwd)" + +echo "Running all standalone tests..." +echo "================================" + +TOTAL_FAILURES=0 + +# Run SHA256 simple test +echo "" +echo "Running SHA256 simple test..." +set +e +"$ROOT_DIR/test/standalone/tests/sha256_simple/run.sh" +if [ $? -eq 0 ]; then + echo "SHA256 simple test: PASSED" +else + echo "SHA256 simple test: FAILED" + TOTAL_FAILURES=$((TOTAL_FAILURES + 1)) +fi +set -e + +# Run hardload test +echo "" +echo "Running hardload test..." +set +e +"$ROOT_DIR/test/standalone/tests/hardload/run.sh" +if [ $? -eq 0 ]; then + echo "Hardload test: PASSED" +else + echo "Hardload test: FAILED" + TOTAL_FAILURES=$((TOTAL_FAILURES + 1)) +fi +set -e + +echo "" +echo "================================" +if [ $TOTAL_FAILURES -eq 0 ]; then + echo "All standalone tests passed!" + exit 0 +else + echo "$TOTAL_FAILURES standalone test(s) failed" + exit 1 +fi \ No newline at end of file diff --git a/test/standalone/test_common.h b/test/standalone/test_common.h new file mode 100644 index 00000000..9cff9cd6 --- /dev/null +++ b/test/standalone/test_common.h @@ -0,0 +1,89 @@ +/* test_common.h + * + * Copyright (C) 2006-2025 wolfSSL Inc. + * + * This file is part of wolfProvider. + * + * wolfProvider 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. + * + * wolfProvider 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 wolfProvider. If not, see . + */ + +#ifndef TEST_COMMON_H +#define TEST_COMMON_H + +#include +#include + +#ifdef WOLFPROV_USER_SETTINGS +#include +#endif +#include +#include + +#include +#include + +/* Test result codes */ +#define TEST_SUCCESS 0 +#define TEST_FAILURE 1 + +/* Debug printing macros */ +#define TEST_INFO(fmt, ...) printf("[INFO] " fmt "\n", ##__VA_ARGS__) +#define TEST_ERROR(fmt, ...) fprintf(stderr, "[ERROR] " fmt "\n", ##__VA_ARGS__) +#define TEST_DEBUG(fmt, ...) do { \ + if (getenv("TEST_DEBUG")) { \ + printf("[DEBUG] " fmt "\n", ##__VA_ARGS__); \ + } \ +} while(0) + +/* Buffer printing for debugging */ +#ifdef WOLFPROV_DEBUG +#define TEST_PRINT_BUFFER(desc, buf, len) test_print_buffer(desc, buf, len) +static inline void test_print_buffer(const char *desc, const unsigned char *buffer, size_t len) +{ + size_t i; + printf("[BUFFER] %s (%zu bytes):\n", desc, len); + for (i = 0; i < len; i++) { + printf("%02x ", buffer[i]); + if ((i % 16) == 15) { + printf("\n"); + } + } + if ((i % 16) != 0) { + printf("\n"); + } + printf("\n"); +} +#else +#define TEST_PRINT_BUFFER(desc, buf, len) +#endif + +/* Utility functions */ +static inline int test_bytes_to_hex(const unsigned char *bytes, size_t len, char *hex, size_t hex_size) +{ + size_t i; + + if (hex_size < (len * 2 + 1)) { + TEST_ERROR("Hex buffer too small"); + return TEST_FAILURE; + } + + for (i = 0; i < len; i++) { + sprintf(hex + (i * 2), "%02x", bytes[i]); + } + hex[len * 2] = '\0'; + + return TEST_SUCCESS; +} + +#endif /* TEST_COMMON_H */ diff --git a/test/standalone/tests/.libs/test_sha256_simple.standalone b/test/standalone/tests/.libs/test_sha256_simple.standalone new file mode 100755 index 00000000..e47d2b43 Binary files /dev/null and b/test/standalone/tests/.libs/test_sha256_simple.standalone differ diff --git a/test/standalone/tests/hardload/run.sh b/test/standalone/tests/hardload/run.sh new file mode 100755 index 00000000..17326bea --- /dev/null +++ b/test/standalone/tests/hardload/run.sh @@ -0,0 +1,137 @@ +#!/bin/bash +# Hardload test runner + +set -e + +# Get the directory of this script and find the root +TEST_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "$TEST_DIR/../../../.." && pwd)" + +# Binary should be in the test/.libs/ directory +BINARY="hardload.test" +BINARY_PATH="$ROOT_DIR/test/.libs/$BINARY" + +# Make sure we can find the binary +if [ ! -f "$BINARY_PATH" ]; then + echo "Error: Cannot find binary $BINARY_PATH" + echo "Make sure you've built the test with: make test/hardload.test" + exit 1 +fi + +# Source env-setup +if ! source "$ROOT_DIR/scripts/env-setup" >/dev/null; then + echo "Error: env-setup failed" + exit 1 +fi + +WP_USING_REPLACE_DEFAULT="0" +if [ -f "$OPENSSL_LIB_PATH/libcrypto.so" ]; then + # Check for wolfProvider symbols in libcrypto + if nm -D "$OPENSSL_LIB_PATH/libcrypto.so" 2>/dev/null | grep -q "wolfprov_provider_init"; then + WP_USING_REPLACE_DEFAULT="1" + fi +fi + +# Configure environment based on build type +if [ "$WP_USING_REPLACE_DEFAULT" = "1" ]; then + echo "Detected: --replace-default build" + unset OPENSSL_CONF + EXPECTED_PROVIDER_NAME="wolfSSL Provider" +else + EXPECTED_PROVIDER_NAME="OpenSSL Default Provider" +fi + +echo "Expected provider name: $EXPECTED_PROVIDER_NAME" + +echo "Using environment:" +echo "LD_LIBRARY_PATH: $LD_LIBRARY_PATH" +echo "OPENSSL_CONF: $OPENSSL_CONF" +echo "OPENSSL_BIN: $OPENSSL_BIN" + +# Check that wolfProvider is loaded in place of default +if [ "$WP_USING_REPLACE_DEFAULT" = "1" ]; then + if ! ${OPENSSL_BIN} list -providers | grep -q "wolf"; then + echo "Error: wolfProvider is not loaded in place of default" + exit 1 + fi +fi + +# Function to run a test scenario +run_test() { + local test_name="$1" + local should_fail="$2" + local set_force_fail="$3" + local output_file + + echo "=== $test_name ===" + + if [ "$set_force_fail" = "true" ]; then + export WOLFPROV_FORCE_FAIL=1 + echo "Setting WOLFPROV_FORCE_FAIL=1" + else + unset WOLFPROV_FORCE_FAIL + echo "WOLFPROV_FORCE_FAIL not set" + fi + + if [ "$should_fail" = "true" ]; then + expected="FAIL" + else + expected="PASS" + fi + + # Create temporary file for test output + output_file=$(mktemp) + + if "$BINARY_PATH" "$EXPECTED_PROVIDER_NAME" >"$output_file" 2>&1; then + result="PASS" + else + result="FAIL" + fi + + echo "Expected: $expected, Got: $result" + + if [ "$result" = "$expected" ]; then + echo "PASS" + rm -f "$output_file" + return 0 + else + echo "FAILED" + echo "Test output:" + cat "$output_file" + rm -f "$output_file" + return 1 + fi +} + +echo "Running hardload test: $BINARY_PATH" +echo "" + +FAILURES=0 + +# Run normal scenario - should always pass +if ! run_test "Normal operation" false false; then + FAILURES=$((FAILURES + 1)) +fi +echo "" + +# Run force-fail scenario - success criteria depends on build type +if [ "$WP_USING_REPLACE_DEFAULT" = "1" ]; then + # Replace-default: force-fail should actually fail (can't escape wolfProvider) + if ! run_test "Force fail test (should fail)" true true; then + FAILURES=$((FAILURES + 1)) + fi +else + # Normal build: force-fail should pass (hardload bypasses wolfProvider) + if ! run_test "Force fail test (should pass)" false true; then + FAILURES=$((FAILURES + 1)) + fi +fi + +echo "" +if [ $FAILURES -gt 0 ]; then + echo "$FAILURES scenarios failed" + exit 1 +else + echo "All scenarios passed" + exit 0 +fi diff --git a/test/standalone/tests/hardload/test_hardload.c b/test/standalone/tests/hardload/test_hardload.c new file mode 100644 index 00000000..db79f832 --- /dev/null +++ b/test/standalone/tests/hardload/test_hardload.c @@ -0,0 +1,200 @@ +/* test_hardload.c + * + * Copyright (C) 2006-2025 wolfSSL Inc. + * + * This file is part of wolfProvider. + * + * wolfProvider 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. + * + * wolfProvider 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 wolfProvider. If not, see . + */ + +#include +#include +#include +#include + +#ifdef WOLFPROV_USER_SETTINGS +#include +#endif +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "../../test_common.h" + +/* Test data and expected results */ +static const char test_data[] = "Hello, hardload test!"; + +int main(int argc, char *argv[]) +{ + OSSL_LIB_CTX *libctx = NULL; + OSSL_PROVIDER *default_prov = NULL; + EVP_MD_CTX *mdctx = NULL; + const EVP_MD *sha256 = NULL; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int digest_len = 0; + char digest_hex[EVP_MAX_MD_SIZE * 2 + 1]; + const char *expected_provider_name = "default"; + int ret = TEST_FAILURE; + const char *wpProviderName = NULL; + OSSL_PARAM wpParams[] = { + { OSSL_PROV_PARAM_NAME, OSSL_PARAM_UTF8_PTR, &wpProviderName, 0, 0 }, + { NULL, 0, NULL, 0, 0 } + }; + + /* Parse command line arguments */ + if (argc > 1) { + expected_provider_name = argv[1]; + } + + TEST_INFO("Expected provider name: %s", expected_provider_name); + + /* Initialize OpenSSL */ + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL); + + /* Create library context */ + libctx = OSSL_LIB_CTX_new(); + if (libctx == NULL) { + TEST_ERROR("Failed to create OpenSSL library context"); + goto cleanup; + } + + /* Hard load the default provider - ignore environment variables */ + TEST_DEBUG("Hard loading default provider (ignoring environment)"); + default_prov = OSSL_PROVIDER_load(libctx, "default"); + if (default_prov == NULL) { + TEST_ERROR("Failed to hard load default provider"); + ERR_print_errors_fp(stderr); + goto cleanup; + } + + /* Verify the default provider is loaded */ + if (!OSSL_PROVIDER_available(libctx, "default")) { + TEST_ERROR("Default provider is not available after loading"); + goto cleanup; + } + + TEST_INFO("Default provider hard loaded successfully"); + + /* Validate the provider name matches expected using OSSL_PROVIDER_get_params */ + if (OSSL_PROVIDER_get_params(default_prov, wpParams) != 1) { + TEST_ERROR("Failed to get provider parameters"); + ERR_print_errors_fp(stderr); + goto cleanup; + } + + if (wpProviderName == NULL) { + TEST_ERROR("Provider name parameter returned NULL"); + goto cleanup; + } + + TEST_INFO("Actual provider name: %s", wpProviderName); + + if (strcmp(wpProviderName, expected_provider_name) != 0) { + TEST_ERROR("Provider name mismatch - Expected: '%s', Got: '%s'", + expected_provider_name, wpProviderName); + goto cleanup; + } + + TEST_INFO("Provider name validation passed: %s", wpProviderName); + + /* Get SHA256 algorithm from the explicitly loaded default provider */ + sha256 = EVP_MD_fetch(libctx, "SHA256", NULL); + if (sha256 == NULL) { + TEST_ERROR("Failed to fetch SHA256 algorithm from default provider"); + ERR_print_errors_fp(stderr); + goto cleanup; + } + + /* Create message digest context */ + mdctx = EVP_MD_CTX_new(); + if (mdctx == NULL) { + TEST_ERROR("Failed to create MD context"); + ERR_print_errors_fp(stderr); + goto cleanup; + } + + /* Initialize digest operation */ + if (EVP_DigestInit_ex(mdctx, sha256, NULL) != 1) { + TEST_ERROR("Failed to initialize digest"); + ERR_print_errors_fp(stderr); + goto cleanup; + } + + TEST_DEBUG("Computing SHA256 of: \"%s\" (%zu bytes)", test_data, strlen(test_data)); + + /* Update digest with test data */ + if (EVP_DigestUpdate(mdctx, test_data, strlen(test_data)) != 1) { + TEST_ERROR("Failed to update digest"); + ERR_print_errors_fp(stderr); + goto cleanup; + } + + /* Finalize digest */ + if (EVP_DigestFinal_ex(mdctx, digest, &digest_len) != 1) { + TEST_ERROR("Failed to finalize digest"); + ERR_print_errors_fp(stderr); + goto cleanup; + } + + /* Convert to hex string for logging */ + if (test_bytes_to_hex(digest, digest_len, digest_hex, sizeof(digest_hex)) != TEST_SUCCESS) { + TEST_ERROR("Failed to convert digest to hex"); + goto cleanup; + } + + TEST_INFO("Computed SHA256: %s", digest_hex); + + /* Verify we got a 32-byte SHA256 result */ + if (digest_len != 32) { + TEST_ERROR("Invalid SHA256 digest length: %u (expected 32)", digest_len); + goto cleanup; + } + + TEST_PRINT_BUFFER("SHA256 digest", digest, digest_len); + + TEST_INFO("SHA256 computation successful using hard loaded default provider - got %u byte digest", digest_len); + + /* Test passed */ + ret = TEST_SUCCESS; + +cleanup: + if (mdctx != NULL) { + EVP_MD_CTX_free(mdctx); + } + if (sha256 != NULL) { + EVP_MD_free((EVP_MD*)sha256); + } + if (default_prov != NULL) { + OSSL_PROVIDER_unload(default_prov); + } + if (libctx != NULL) { + OSSL_LIB_CTX_free(libctx); + } + + if (ret == TEST_SUCCESS) { + TEST_INFO("Test PASSED"); + } else { + TEST_ERROR("Test FAILED"); + } + + return ret; +} diff --git a/test/standalone/tests/sha256_simple/run.sh b/test/standalone/tests/sha256_simple/run.sh new file mode 100755 index 00000000..3062b99d --- /dev/null +++ b/test/standalone/tests/sha256_simple/run.sh @@ -0,0 +1,159 @@ +#!/bin/bash +# SHA256 simple test runner + +set -e + +# Get the directory of this script and find the root +TEST_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "$TEST_DIR/../../../.." && pwd)" + +# Binary should be in the test/.libs/ directory +BINARY="sha256_simple.test" +BINARY_PATH="$ROOT_DIR/test/.libs/$BINARY" + +# Make sure we can find the binary +if [ ! -f "$BINARY_PATH" ]; then + echo "Error: Cannot find binary $BINARY_PATH" + echo "Make sure you've built the test with: make test/sha256_simple.test" + exit 1 +fi + +# Source env-setup +if ! source "$ROOT_DIR/scripts/env-setup" >/dev/null; then + echo "Error: env-setup failed" + exit 1 +fi + +WP_USING_REPLACE_DEFAULT="0" +if [ -f "$OPENSSL_LIB_PATH/libcrypto.so" ]; then + # Check for wolfProvider symbols in libcrypto + if nm -D "$OPENSSL_LIB_PATH/libcrypto.so" 2>/dev/null | grep -q "wolfprov_provider_init"; then + WP_USING_REPLACE_DEFAULT="1" + fi +fi + +# Configure environment based on build type +if [ "$WP_USING_REPLACE_DEFAULT" = "1" ]; then + echo "Detected: --replace-default build" + unset OPENSSL_CONF +fi + +echo "Using environment:" +echo "LD_LIBRARY_PATH: $LD_LIBRARY_PATH" +echo "OPENSSL_CONF: $OPENSSL_CONF" +echo "OPENSSL_BIN: $OPENSSL_BIN" + +# Check that wolfProvider is loaded in place of default +if [ "$WP_USING_REPLACE_DEFAULT" = "1" ]; then + if ! ${OPENSSL_BIN} list -providers | grep -q "wolf"; then + echo "Error: wolfProvider is not loaded in place of default" + exit 1 + fi +fi + +# Function to run a test scenario +run_test() { + local test_name="$1" + local should_fail="$2" + local custom_conf="$3" + local output_file + + echo "=== $test_name ===" + + if [ "$should_fail" = "true" ]; then + export WOLFPROV_FORCE_FAIL=1 + expected="FAIL" + else + unset WOLFPROV_FORCE_FAIL + expected="PASS" + fi + + # Set custom config if provided + local original_openssl_conf="$OPENSSL_CONF" + if [ -n "$custom_conf" ]; then + export OPENSSL_CONF="$custom_conf" + echo "Using custom config: $OPENSSL_CONF" + fi + + # Create temporary file for test output + output_file=$(mktemp) + + if "$BINARY_PATH" >"$output_file" 2>&1; then + result="PASS" + else + result="FAIL" + fi + + # Restore original config + if [ -n "$custom_conf" ]; then + if [ -n "$original_openssl_conf" ]; then + export OPENSSL_CONF="$original_openssl_conf" + else + unset OPENSSL_CONF + fi + fi + + echo "Expected: $expected, Got: $result" + + if [ "$result" = "$expected" ]; then + echo "PASS" + rm -f "$output_file" + return 0 + else + echo "FAILED" + echo "Test output:" + cat "$output_file" + rm -f "$output_file" + return 1 + fi +} + +echo "Running SHA256 test: $BINARY_PATH" +echo "" + +FAILURES=0 + +if [ "$WP_USING_REPLACE_DEFAULT" = "1" ]; then + echo "Replace-default build detected - running 4 test scenarios" + + if ! run_test "No config, normal operation" false; then + FAILURES=$((FAILURES + 1)) + fi + echo "" + + if ! run_test "No config, force fail" true; then + FAILURES=$((FAILURES + 1)) + fi + echo "" + + if ! run_test "Explicit default config, normal operation" false "$ROOT_DIR/test/standalone/provider-default.conf"; then + FAILURES=$((FAILURES + 1)) + fi + echo "" + + if ! run_test "Explicit default config, force fail" true "$ROOT_DIR/test/standalone/provider-default.conf"; then + FAILURES=$((FAILURES + 1)) + fi + echo "" +else + echo "Standard build - running 2 test scenarios" + + if ! run_test "Normal operation" false; then + FAILURES=$((FAILURES + 1)) + fi + echo "" + + if ! run_test "Force fail test" true; then + FAILURES=$((FAILURES + 1)) + fi + echo "" +fi + +echo "" +if [ $FAILURES -gt 0 ]; then + echo "$FAILURES scenarios failed" + exit 1 +else + echo "All scenarios passed" + exit 0 +fi diff --git a/test/standalone/tests/sha256_simple/test_sha256_simple.c b/test/standalone/tests/sha256_simple/test_sha256_simple.c new file mode 100644 index 00000000..1168b807 --- /dev/null +++ b/test/standalone/tests/sha256_simple/test_sha256_simple.c @@ -0,0 +1,143 @@ +/* test_sha256_simple.c + * + * Copyright (C) 2006-2025 wolfSSL Inc. + * + * This file is part of wolfProvider. + * + * wolfProvider 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. + * + * wolfProvider 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 wolfProvider. If not, see . + */ + +#include +#include +#include +#include + +#ifdef WOLFPROV_USER_SETTINGS +#include +#endif +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "../../test_common.h" + +/* Test data and expected results */ +static const char test_data[] = "Hello, wolfProvider!"; +static const char expected_sha256_hex[] = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; + +int main(int argc, char *argv[]) +{ + EVP_MD_CTX *mdctx = NULL; + const EVP_MD *sha256 = NULL; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int digest_len = 0; + char digest_hex[EVP_MAX_MD_SIZE * 2 + 1]; + int ret = TEST_FAILURE; + + (void)argc; + (void)argv; + + TEST_INFO("Starting SHA256 simple test"); + + /* Get SHA256 algorithm */ + sha256 = EVP_MD_fetch(NULL, "SHA256", NULL); + if (sha256 == NULL) { + TEST_ERROR("Failed to fetch SHA256 algorithm"); + ERR_print_errors_fp(stderr); + goto cleanup; + } + + /* Create message digest context */ + mdctx = EVP_MD_CTX_new(); + if (mdctx == NULL) { + TEST_ERROR("Failed to create MD context"); + ERR_print_errors_fp(stderr); + goto cleanup; + } + + /* Initialize digest operation */ + if (EVP_DigestInit_ex(mdctx, sha256, NULL) != 1) { + TEST_ERROR("Failed to initialize digest"); + ERR_print_errors_fp(stderr); + goto cleanup; + } + + TEST_DEBUG("Computing SHA256 of: \"%s\" (%zu bytes)", test_data, strlen(test_data)); + + /* Update digest with test data */ + if (EVP_DigestUpdate(mdctx, test_data, strlen(test_data)) != 1) { + TEST_ERROR("Failed to update digest"); + ERR_print_errors_fp(stderr); + goto cleanup; + } + + /* Finalize digest */ + if (EVP_DigestFinal_ex(mdctx, digest, &digest_len) != 1) { + TEST_ERROR("Failed to finalize digest"); + ERR_print_errors_fp(stderr); + goto cleanup; + } + + /* Convert to hex string for comparison */ + if (test_bytes_to_hex(digest, digest_len, digest_hex, sizeof(digest_hex)) != TEST_SUCCESS) { + TEST_ERROR("Failed to convert digest to hex"); + goto cleanup; + } + + TEST_INFO("Computed SHA256: %s", digest_hex); + TEST_DEBUG("Expected SHA256: %s", expected_sha256_hex); + + /* Verify the result */ + if (strlen(expected_sha256_hex) != digest_len * 2) { + TEST_ERROR("Digest length mismatch (expected %zu, got %u)", + strlen(expected_sha256_hex) / 2, digest_len); + goto cleanup; + } + + TEST_PRINT_BUFFER("SHA256 digest", digest, digest_len); + + /* For now, just verify we got a 32-byte SHA256 result */ + if (digest_len != 32) { + TEST_ERROR("Invalid SHA256 digest length: %u (expected 32)", digest_len); + goto cleanup; + } + + TEST_INFO("SHA256 computation successful - got %u byte digest", digest_len); + + ret = TEST_SUCCESS; + +cleanup: + if (mdctx != NULL) { + EVP_MD_CTX_free(mdctx); + } + if (sha256 != NULL) { + EVP_MD_free((EVP_MD*)sha256); + } + + if (ret == TEST_SUCCESS) { + TEST_INFO("Test PASSED"); + } else { + TEST_ERROR("Test FAILED"); + } + + return ret; +}