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
7 changes: 5 additions & 2 deletions .github/workflows/simple.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ jobs:
'openssl-3.2.5',
'openssl-3.1.8',
'openssl-3.0.17']
debug: ['', 'WOLFPROV_DEBUG=1']
debug: ['', '--debug']
replace_default: [
'',
'--replace-default --enable-replace-default-testing']

steps:
- name: Checkout wolfProvider
Expand All @@ -40,7 +43,7 @@ jobs:

- name: Build and test wolfProvider
run: |
OPENSSL_TAG=${{ matrix.openssl_ref }} WOLFSSL_TAG=${{ matrix.wolfssl_ref }} ${{ matrix.debug }} ./scripts/build-wolfprovider.sh
OPENSSL_TAG=${{ matrix.openssl_ref }} WOLFSSL_TAG=${{ matrix.wolfssl_ref }} ./scripts/build-wolfprovider.sh ${{ matrix.debug }} ${{ matrix.replace_default }}

- name: Print errors
if: ${{ failure() }}
Expand Down
65 changes: 65 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,71 @@ Then use the following command to build wolfProvider with FIPS enabled.
./scripts/build-wolfprovider.sh --fips-bundle="path/to/fips-bundle" --fips-check=ready --distclean
```

## Building with Replace Default

wolfProvider can be configured to replace OpenSSL's default provider, making wolfProvider the default cryptographic provider for all OpenSSL operations. This is useful for applications that want to use wolfSSL's cryptographic implementations without modifying their code.

### Replace Default vs. Standard Provider Mode

Replace default mode is fundamentally different from the standard provider approach:

**Standard Provider Mode:** When wolfProvider is loaded as a standard provider alongside OpenSSL's default provider, applications can still access OpenSSL's native crypto implementations in several ways:
- When an application explicitly requests a specific provider (e.g., "default") for an algorithm
- When wolfProvider doesn't implement a particular algorithm, OpenSSL falls back to its built-in implementations
- If the execution environment does not pick up the specified configuration file enabling
use of wolfProvider

**Replace Default Mode:** This mode patches OpenSSL to disable many of these fallback paths.
When replace default is enabled:
- wolfProvider becomes the primary cryptographic provider
- Requests for the "default" provider are redirected to wolfProvider
- Requests for the "fips" provider are redirected to wolfProvider
- Requests for the "wolfProvider" provider are redirected to wolfProvider
- This ensures maximum use of wolfSSL's cryptographic implementations for testing and validation

This makes replace default mode particularly useful for comprehensive testing scenarios where you want to ensure that wolfSSL's implementations are being used throughout the entire system.

### Basic Replace Default

To build wolfProvider as a replacement for OpenSSL's default provider:

```bash
./scripts/build-wolfprovider.sh --replace-default
```

This patches OpenSSL so that wolfProvider becomes the default provider.

### Replace Default with Testing Support

For unit testing with replace-default enabled, you need additional support to load the real OpenSSL default provider alongside wolfProvider. This requires both flags:

```bash
./scripts/build-wolfprovider.sh --replace-default --enable-replace-default-testing
```

### Important Notes

**For `--replace-default`:**
- Can be used standalone in production or testing environments
- Makes wolfProvider the default cryptographic provider

**For `--enable-replace-default-testing`:**
**Warning:** This option patches OpenSSL to export internal symbols that are not part of the public API. This configuration:
- Should only be used for development and testing
- Is not suitable for production deployments

### Examples

Build with replace-default only:
```bash
./scripts/build-wolfprovider.sh --replace-default
```

Build with replace-default and unit testing support:
```bash
./scripts/build-wolfprovider.sh --replace-default --enable-replace-default-testing
```

## Testing

### Unit Tests
Expand Down
14 changes: 14 additions & 0 deletions scripts/build-wolfprovider.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ show_help() {
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 " --enable-replace-default-testing"
echo " Enable direct provider loading in unit tests. This option patches openssl to export additional symbols."
echo " Note: Requires --replace-default. Only for test builds, not for production."
echo " --leave-silent Enable leave silent mode to suppress logging of return 0 in probing functions where expected failures may occur."
echo " Note: This only affects logging; the calling function is still responsible for handling all return values appropriately."
echo ""
Expand All @@ -37,6 +40,8 @@ show_help() {
echo " WOLFPROV_LOG_FILE Path to log file for wolfProvider debug output (alternative to stderr)"
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"
echo " WOLFPROV_REPLACE_DEFAULT If set to 1, patches OpenSSL so wolfProvider is the default provider"
echo " WOLFPROV_REPLACE_DEFAULT_TESTING If set to 1, enables direct provider loading in unit tests (requires WOLFPROV_REPLACE_DEFAULT=1)"
echo " WOLFPROV_LEAVE_SILENT If set to 1, suppress logging of return 0 in functions where return 0 is expected behavior sometimes."
echo ""
}
Expand Down Expand Up @@ -118,6 +123,9 @@ for arg in "$@"; do
--replace-default)
WOLFPROV_REPLACE_DEFAULT=1
;;
--enable-replace-default-testing)
WOLFPROV_REPLACE_DEFAULT_TESTING=1
;;
--leave-silent)
WOLFPROV_LEAVE_SILENT=1
;;
Expand Down Expand Up @@ -145,6 +153,12 @@ if [ -n "$WOLFPROV_LOG_FILE" ] && [ -z "$WOLFPROV_DEBUG" ]; then
exit 1
fi

# Check for consistency between replace-default options
if [ "$WOLFPROV_REPLACE_DEFAULT_TESTING" = "1" ] && [ "$WOLFPROV_REPLACE_DEFAULT" != "1" ]; then
echo "Error: --enable-replace-default-testing requires --replace-default to also be set."
exit 1
fi

if [ -n "$build_debian" ]; then
set -e

Expand Down
92 changes: 92 additions & 0 deletions scripts/patch-libcrypto-exports.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#!/bin/bash
#
# 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 <http://www.gnu.org/licenses/>.
#

#
# Patch libcrypto.num to export internal provider functions
#
# This script appends 6 internal provider symbols to OpenSSL's libcrypto.num
# file, making them available for direct provider loading in wolfprovider unit tests.
#

set -e

# OPENSSL_SOURCE_DIR should be set by the caller (utils-openssl.sh)
if [ -z "$OPENSSL_SOURCE_DIR" ]; then
echo "ERROR: OPENSSL_SOURCE_DIR not set"
exit 1
fi

# Source utils-openssl.sh to use is_libcrypto_num_patched function
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/utils-openssl.sh"

LIBCRYPTO_NUM="${OPENSSL_SOURCE_DIR}/util/libcrypto.num"

# Check if file exists
if [ ! -f "$LIBCRYPTO_NUM" ]; then
echo "ERROR: libcrypto.num not found at: $LIBCRYPTO_NUM"
exit 1
fi

# Check if already patched using shared function
if is_libcrypto_num_patched; then
echo "libcrypto.num already patched (provider symbols present)"
exit 0
fi

# Get the last symbol number
LAST_NUM=$(awk '{print $2}' "$LIBCRYPTO_NUM" | grep -E '^[0-9]+$' | sort -n | tail -1)

if [ -z "$LAST_NUM" ]; then
echo "ERROR: Could not determine last symbol number from libcrypto.num"
exit 1
fi

# Get the version tag from the last line (column 3)
LAST_VERSION=$(tail -1 "$LIBCRYPTO_NUM" | awk '{print $3}')

if [ -z "$LAST_VERSION" ]; then
echo "ERROR: Could not determine version tag from libcrypto.num"
exit 1
fi

# Calculate new symbol numbers
NUM1=$((LAST_NUM + 1))
NUM2=$((LAST_NUM + 2))
NUM3=$((LAST_NUM + 3))
NUM4=$((LAST_NUM + 4))
NUM5=$((LAST_NUM + 5))
NUM6=$((LAST_NUM + 6))

# Append the 6 provider symbols
# Format matches existing entries: name (40 chars) TAB number TAB version TAB specification
# Use printf to ensure proper tab characters
{
printf "ossl_provider_new %s\t%s\tEXIST::FUNCTION:\n" "${NUM1}" "${LAST_VERSION}"
printf "ossl_provider_activate %s\t%s\tEXIST::FUNCTION:\n" "${NUM2}" "${LAST_VERSION}"
printf "ossl_provider_deactivate %s\t%s\tEXIST::FUNCTION:\n" "${NUM3}" "${LAST_VERSION}"
printf "ossl_provider_add_to_store %s\t%s\tEXIST::FUNCTION:\n" "${NUM4}" "${LAST_VERSION}"
printf "ossl_provider_free %s\t%s\tEXIST::FUNCTION:\n" "${NUM5}" "${LAST_VERSION}"
printf "ossl_default_provider_init %s\t%s\tEXIST::FUNCTION:\n" "${NUM6}" "${LAST_VERSION}"
} >> "$LIBCRYPTO_NUM"

echo "Successfully patched libcrypto.num: Added symbols ${NUM1}-${NUM6} with version ${LAST_VERSION}"
exit 0

81 changes: 81 additions & 0 deletions scripts/utils-openssl.sh
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,23 @@ is_openssl_patched() {
return 1
}

is_libcrypto_num_patched() {
# Return 0 if patched with provider symbols, 1 if not
local dir="${OPENSSL_SOURCE_DIR:?OPENSSL_SOURCE_DIR not set}"
local file="${dir%/}/util/libcrypto.num"

# File must exist to be patched
[[ -f "$file" ]] || return 1

# Check for our provider symbol exports
if grep -q '^ossl_provider_new' -- "$file"; then
return 0
fi

# Not patched
return 1
}

patch_openssl_version() {
# Patch the OpenSSL version (wolfProvider/openssl-source/VERSION.dat)
# with our BUILD_METADATA, depending on the FIPS flag. Either "wolfProvider" or "wolfProvider-fips".
Expand Down Expand Up @@ -171,6 +188,41 @@ patch_openssl() {
printf "Done.\n"
popd &> /dev/null
fi

# Patch libcrypto.num for replace-default-testing mode
if [ "$WOLFPROV_REPLACE_DEFAULT_TESTING" = "1" ] && [ "$WOLFPROV_REPLACE_DEFAULT" = "1" ]; then
if [ -d "${OPENSSL_INSTALL_DIR}" ]; then
# OpenSSL already installed, skip patching
return 0
fi

printf "\tPatching libcrypto.num for provider symbol exports ... "
export OPENSSL_SOURCE_DIR
${SCRIPT_DIR}/patch-libcrypto-exports.sh >>$LOG_FILE 2>&1
if [ $? != 0 ]; then
printf "ERROR.\n"
printf "\n\nLibcrypto.num patch failed. Last 40 lines of log:\n"
tail -n 40 $LOG_FILE
do_cleanup
exit 1
fi
printf "Done.\n"

printf "\n"
printf " ╔════════════════════════════════════════════════════════════════════╗\n"
printf " ║ *** WARNING *** ║\n"
printf " ╠════════════════════════════════════════════════════════════════════╣\n"
printf " ║ OpenSSL has been PATCHED to export internal provider symbols ║\n"
printf " ║ for unit testing purposes. ║\n"
printf " ║ ║\n"
printf " ║ >> DO NOT USE THIS BUILD IN PRODUCTION ║\n"
printf " ║ >> This build is for TESTING ONLY ║\n"
printf " ║ ║\n"
printf " ║ Internal symbols exported: ossl_provider_new, ossl_provider_* ║\n"
printf " ║ ossl_default_provider_init ║\n"
printf " ╚════════════════════════════════════════════════════════════════════╝\n"
printf "\n"
fi
}

check_openssl_replace_default_mismatch() {
Expand Down Expand Up @@ -200,11 +252,40 @@ check_openssl_replace_default_mismatch() {
fi
}

check_replace_default_testing_mismatch() {
local libcrypto_is_patched=0

# Check if libcrypto.num was patched for --enable-replace-default-testing
if is_libcrypto_num_patched; then
libcrypto_is_patched=1
printf "INFO: OpenSSL libcrypto.num patched with internal provider symbol exports (testing build).\n"
fi

# Check for mismatch
if [ "$WOLFPROV_REPLACE_DEFAULT_TESTING" = "1" ] && [ "$libcrypto_is_patched" = "0" ]; then
printf "ERROR: --enable-replace-default-testing build mode mismatch!\n"
printf "Existing OpenSSL was built WITHOUT libcrypto.num patch\n"
printf "Current request: --enable-replace-default-testing build\n\n"
printf "Fix: ./scripts/build-wolfprovider.sh --distclean\n"
printf "Then rebuild with desired configuration.\n"
exit 1
elif [ "$WOLFPROV_REPLACE_DEFAULT_TESTING" != "1" ] && [ "$libcrypto_is_patched" = "1" ]; then
printf "ERROR: Standard build mode mismatch!\n"
printf "Existing OpenSSL was built WITH libcrypto.num patch (testing mode)\n"
printf "Current request: standard build\n\n"
printf "This OpenSSL build exports internal provider symbols and should NOT be used.\n"
printf "Fix: ./scripts/build-wolfprovider.sh --distclean\n"
printf "Then rebuild with desired configuration.\n"
exit 1
fi
}

install_openssl() {
printf "\nInstalling OpenSSL ${OPENSSL_TAG} ...\n"
clone_openssl
patch_openssl
check_openssl_replace_default_mismatch
check_replace_default_testing_mismatch

pushd ${OPENSSL_SOURCE_DIR} &> /dev/null

Expand Down
25 changes: 23 additions & 2 deletions scripts/utils-wolfprovider.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ if [ "${WOLFPROV_QUICKTEST}" = "1" ]; then
WOLFPROV_CONFIG_CFLAGS="${WOLFPROV_CONFIG_CFLAGS} -DWOLFPROV_QUICKTEST"
fi

if [ "${WOLFPROV_REPLACE_DEFAULT_TESTING}" = "1" ]; then
WOLFPROV_CONFIG_CFLAGS="${WOLFPROV_CONFIG_CFLAGS} -DWOLFPROV_REPLACE_DEFAULT_UNIT_TEST"
fi

if [ "$WOLFSSL_ISFIPS" -eq "1" ] || [ -n "$WOLFSSL_FIPS_BUNDLE" ]; then
WOLFPROV_CONFIG=${WOLFPROV_CONFIG:-"$WOLFPROV_SOURCE_DIR/provider-fips.conf"}
else
Expand Down Expand Up @@ -143,8 +147,8 @@ install_wolfprov() {

# Build the replacement default library after wolfprov to avoid linker errors
# but before testing so that the library is present if needed
if [ "$WOLFPROV_REPLACE_DEFAULT" = "1" ]; then
printf "\tWARNING: Skipping tests in replace mode...\n"
if [ "$WOLFPROV_REPLACE_DEFAULT" = "1" ] && [ "$WOLFPROV_REPLACE_DEFAULT_TESTING" != "1" ]; then
printf "\tWARNING: Skipping tests in replace mode (use --enable-replace-default-testing to enable)...\n"
else
# Setup the environment to ensure we use the local builds of wolfprov, wolfssl, and openssl.
if ! source ${SCRIPT_DIR}/env-setup >/dev/null 2>&1; then
Expand All @@ -166,6 +170,23 @@ install_wolfprov() {
printf "Done.\n"
fi

# Final warning for replace-default-testing builds
if [ "$WOLFPROV_REPLACE_DEFAULT_TESTING" = "1" ]; then
printf "\n"
printf "╔══════════════════════════════════════════════════════════════════════════╗\n"
printf "║ *** TESTING BUILD COMPLETE *** ║\n"
printf "╠══════════════════════════════════════════════════════════════════════════╣\n"
printf "║ This OpenSSL build has been patched with INTERNAL SYMBOL EXPORTS ║\n"
printf "║ for unit testing with --enable-replace-default-testing ║\n"
printf "║ ║\n"
printf "║ >> DO NOT DEPLOY TO PRODUCTION ║\n"
printf "║ >> FOR DEVELOPMENT AND TESTING USE ONLY ║\n"
printf "║ ║\n"
printf "║ To build a production version, rebuild WITHOUT this flag. ║\n"
printf "╚══════════════════════════════════════════════════════════════════════════╝\n"
printf "\n"
fi

popd &> /dev/null
}

Expand Down
Loading
Loading