Skip to content

Commit e582de1

Browse files
authored
Add new option to enable unit testing for replace default mode (#331)
* Add new option to enable unit testing for replace default mode, directly initializing the openssl default provider * changes per review comments, name change, consistency checks, documentation. * Update simple.yml to test with new enable default replace testing option * Update replace default testing README and script checks
1 parent e6237da commit e582de1

File tree

7 files changed

+408
-6
lines changed

7 files changed

+408
-6
lines changed

.github/workflows/simple.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ jobs:
3030
'openssl-3.2.5',
3131
'openssl-3.1.8',
3232
'openssl-3.0.17']
33-
debug: ['', 'WOLFPROV_DEBUG=1']
33+
debug: ['', '--debug']
34+
replace_default: [
35+
'',
36+
'--replace-default --enable-replace-default-testing']
3437

3538
steps:
3639
- name: Checkout wolfProvider
@@ -40,7 +43,7 @@ jobs:
4043

4144
- name: Build and test wolfProvider
4245
run: |
43-
OPENSSL_TAG=${{ matrix.openssl_ref }} WOLFSSL_TAG=${{ matrix.wolfssl_ref }} ${{ matrix.debug }} ./scripts/build-wolfprovider.sh
46+
OPENSSL_TAG=${{ matrix.openssl_ref }} WOLFSSL_TAG=${{ matrix.wolfssl_ref }} ./scripts/build-wolfprovider.sh ${{ matrix.debug }} ${{ matrix.replace_default }}
4447
4548
- name: Print errors
4649
if: ${{ failure() }}

README.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,71 @@ Then use the following command to build wolfProvider with FIPS enabled.
153153
./scripts/build-wolfprovider.sh --fips-bundle="path/to/fips-bundle" --fips-check=ready --distclean
154154
```
155155

156+
## Building with Replace Default
157+
158+
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.
159+
160+
### Replace Default vs. Standard Provider Mode
161+
162+
Replace default mode is fundamentally different from the standard provider approach:
163+
164+
**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:
165+
- When an application explicitly requests a specific provider (e.g., "default") for an algorithm
166+
- When wolfProvider doesn't implement a particular algorithm, OpenSSL falls back to its built-in implementations
167+
- If the execution environment does not pick up the specified configuration file enabling
168+
use of wolfProvider
169+
170+
**Replace Default Mode:** This mode patches OpenSSL to disable many of these fallback paths.
171+
When replace default is enabled:
172+
- wolfProvider becomes the primary cryptographic provider
173+
- Requests for the "default" provider are redirected to wolfProvider
174+
- Requests for the "fips" provider are redirected to wolfProvider
175+
- Requests for the "wolfProvider" provider are redirected to wolfProvider
176+
- This ensures maximum use of wolfSSL's cryptographic implementations for testing and validation
177+
178+
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.
179+
180+
### Basic Replace Default
181+
182+
To build wolfProvider as a replacement for OpenSSL's default provider:
183+
184+
```bash
185+
./scripts/build-wolfprovider.sh --replace-default
186+
```
187+
188+
This patches OpenSSL so that wolfProvider becomes the default provider.
189+
190+
### Replace Default with Testing Support
191+
192+
For unit testing with replace-default enabled, you need additional support to load the real OpenSSL default provider alongside wolfProvider. This requires both flags:
193+
194+
```bash
195+
./scripts/build-wolfprovider.sh --replace-default --enable-replace-default-testing
196+
```
197+
198+
### Important Notes
199+
200+
**For `--replace-default`:**
201+
- Can be used standalone in production or testing environments
202+
- Makes wolfProvider the default cryptographic provider
203+
204+
**For `--enable-replace-default-testing`:**
205+
**Warning:** This option patches OpenSSL to export internal symbols that are not part of the public API. This configuration:
206+
- Should only be used for development and testing
207+
- Is not suitable for production deployments
208+
209+
### Examples
210+
211+
Build with replace-default only:
212+
```bash
213+
./scripts/build-wolfprovider.sh --replace-default
214+
```
215+
216+
Build with replace-default and unit testing support:
217+
```bash
218+
./scripts/build-wolfprovider.sh --replace-default --enable-replace-default-testing
219+
```
220+
156221
## Testing
157222

158223
### Unit Tests

scripts/build-wolfprovider.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ show_help() {
2222
echo " --debian --enable-fips Build a Debian package with FIPS support"
2323
echo " --quicktest Disable some tests for a faster testing suite"
2424
echo " --replace-default Patch OpenSSL and build it so that wolfProvider is the default provider"
25+
echo " --enable-replace-default-testing"
26+
echo " Enable direct provider loading in unit tests. This option patches openssl to export additional symbols."
27+
echo " Note: Requires --replace-default. Only for test builds, not for production."
2528
echo " --leave-silent Enable leave silent mode to suppress logging of return 0 in probing functions where expected failures may occur."
2629
echo " Note: This only affects logging; the calling function is still responsible for handling all return values appropriately."
2730
echo ""
@@ -37,6 +40,8 @@ show_help() {
3740
echo " WOLFPROV_LOG_FILE Path to log file for wolfProvider debug output (alternative to stderr)"
3841
echo " WOLFPROV_QUICKTEST If set to 1, disables some tests in the test suite to increase test speed"
3942
echo " WOLFPROV_DISABLE_ERR_TRACE If set to 1, wolfSSL will not be configured with --enable-debug-trace-errcodes=backtrace"
43+
echo " WOLFPROV_REPLACE_DEFAULT If set to 1, patches OpenSSL so wolfProvider is the default provider"
44+
echo " WOLFPROV_REPLACE_DEFAULT_TESTING If set to 1, enables direct provider loading in unit tests (requires WOLFPROV_REPLACE_DEFAULT=1)"
4045
echo " WOLFPROV_LEAVE_SILENT If set to 1, suppress logging of return 0 in functions where return 0 is expected behavior sometimes."
4146
echo ""
4247
}
@@ -118,6 +123,9 @@ for arg in "$@"; do
118123
--replace-default)
119124
WOLFPROV_REPLACE_DEFAULT=1
120125
;;
126+
--enable-replace-default-testing)
127+
WOLFPROV_REPLACE_DEFAULT_TESTING=1
128+
;;
121129
--leave-silent)
122130
WOLFPROV_LEAVE_SILENT=1
123131
;;
@@ -145,6 +153,12 @@ if [ -n "$WOLFPROV_LOG_FILE" ] && [ -z "$WOLFPROV_DEBUG" ]; then
145153
exit 1
146154
fi
147155

156+
# Check for consistency between replace-default options
157+
if [ "$WOLFPROV_REPLACE_DEFAULT_TESTING" = "1" ] && [ "$WOLFPROV_REPLACE_DEFAULT" != "1" ]; then
158+
echo "Error: --enable-replace-default-testing requires --replace-default to also be set."
159+
exit 1
160+
fi
161+
148162
if [ -n "$build_debian" ]; then
149163
set -e
150164

scripts/patch-libcrypto-exports.sh

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#!/bin/bash
2+
#
3+
# Copyright (C) 2006-2024 wolfSSL Inc.
4+
#
5+
# This file is part of wolfProvider.
6+
#
7+
# wolfProvider is free software; you can redistribute it and/or modify
8+
# it under the terms of the GNU General Public License as published by
9+
# the Free Software Foundation; either version 3 of the License, or
10+
# (at your option) any later version.
11+
#
12+
# wolfProvider is distributed in the hope that it will be useful,
13+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
# GNU General Public License for more details.
16+
#
17+
# You should have received a copy of the GNU General Public License
18+
# along with wolfProvider. If not, see <http://www.gnu.org/licenses/>.
19+
#
20+
21+
#
22+
# Patch libcrypto.num to export internal provider functions
23+
#
24+
# This script appends 6 internal provider symbols to OpenSSL's libcrypto.num
25+
# file, making them available for direct provider loading in wolfprovider unit tests.
26+
#
27+
28+
set -e
29+
30+
# OPENSSL_SOURCE_DIR should be set by the caller (utils-openssl.sh)
31+
if [ -z "$OPENSSL_SOURCE_DIR" ]; then
32+
echo "ERROR: OPENSSL_SOURCE_DIR not set"
33+
exit 1
34+
fi
35+
36+
# Source utils-openssl.sh to use is_libcrypto_num_patched function
37+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
38+
source "${SCRIPT_DIR}/utils-openssl.sh"
39+
40+
LIBCRYPTO_NUM="${OPENSSL_SOURCE_DIR}/util/libcrypto.num"
41+
42+
# Check if file exists
43+
if [ ! -f "$LIBCRYPTO_NUM" ]; then
44+
echo "ERROR: libcrypto.num not found at: $LIBCRYPTO_NUM"
45+
exit 1
46+
fi
47+
48+
# Check if already patched using shared function
49+
if is_libcrypto_num_patched; then
50+
echo "libcrypto.num already patched (provider symbols present)"
51+
exit 0
52+
fi
53+
54+
# Get the last symbol number
55+
LAST_NUM=$(awk '{print $2}' "$LIBCRYPTO_NUM" | grep -E '^[0-9]+$' | sort -n | tail -1)
56+
57+
if [ -z "$LAST_NUM" ]; then
58+
echo "ERROR: Could not determine last symbol number from libcrypto.num"
59+
exit 1
60+
fi
61+
62+
# Get the version tag from the last line (column 3)
63+
LAST_VERSION=$(tail -1 "$LIBCRYPTO_NUM" | awk '{print $3}')
64+
65+
if [ -z "$LAST_VERSION" ]; then
66+
echo "ERROR: Could not determine version tag from libcrypto.num"
67+
exit 1
68+
fi
69+
70+
# Calculate new symbol numbers
71+
NUM1=$((LAST_NUM + 1))
72+
NUM2=$((LAST_NUM + 2))
73+
NUM3=$((LAST_NUM + 3))
74+
NUM4=$((LAST_NUM + 4))
75+
NUM5=$((LAST_NUM + 5))
76+
NUM6=$((LAST_NUM + 6))
77+
78+
# Append the 6 provider symbols
79+
# Format matches existing entries: name (40 chars) TAB number TAB version TAB specification
80+
# Use printf to ensure proper tab characters
81+
{
82+
printf "ossl_provider_new %s\t%s\tEXIST::FUNCTION:\n" "${NUM1}" "${LAST_VERSION}"
83+
printf "ossl_provider_activate %s\t%s\tEXIST::FUNCTION:\n" "${NUM2}" "${LAST_VERSION}"
84+
printf "ossl_provider_deactivate %s\t%s\tEXIST::FUNCTION:\n" "${NUM3}" "${LAST_VERSION}"
85+
printf "ossl_provider_add_to_store %s\t%s\tEXIST::FUNCTION:\n" "${NUM4}" "${LAST_VERSION}"
86+
printf "ossl_provider_free %s\t%s\tEXIST::FUNCTION:\n" "${NUM5}" "${LAST_VERSION}"
87+
printf "ossl_default_provider_init %s\t%s\tEXIST::FUNCTION:\n" "${NUM6}" "${LAST_VERSION}"
88+
} >> "$LIBCRYPTO_NUM"
89+
90+
echo "Successfully patched libcrypto.num: Added symbols ${NUM1}-${NUM6} with version ${LAST_VERSION}"
91+
exit 0
92+

scripts/utils-openssl.sh

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,23 @@ is_openssl_patched() {
117117
return 1
118118
}
119119

120+
is_libcrypto_num_patched() {
121+
# Return 0 if patched with provider symbols, 1 if not
122+
local dir="${OPENSSL_SOURCE_DIR:?OPENSSL_SOURCE_DIR not set}"
123+
local file="${dir%/}/util/libcrypto.num"
124+
125+
# File must exist to be patched
126+
[[ -f "$file" ]] || return 1
127+
128+
# Check for our provider symbol exports
129+
if grep -q '^ossl_provider_new' -- "$file"; then
130+
return 0
131+
fi
132+
133+
# Not patched
134+
return 1
135+
}
136+
120137
patch_openssl_version() {
121138
# Patch the OpenSSL version (wolfProvider/openssl-source/VERSION.dat)
122139
# with our BUILD_METADATA, depending on the FIPS flag. Either "wolfProvider" or "wolfProvider-fips".
@@ -171,6 +188,41 @@ patch_openssl() {
171188
printf "Done.\n"
172189
popd &> /dev/null
173190
fi
191+
192+
# Patch libcrypto.num for replace-default-testing mode
193+
if [ "$WOLFPROV_REPLACE_DEFAULT_TESTING" = "1" ] && [ "$WOLFPROV_REPLACE_DEFAULT" = "1" ]; then
194+
if [ -d "${OPENSSL_INSTALL_DIR}" ]; then
195+
# OpenSSL already installed, skip patching
196+
return 0
197+
fi
198+
199+
printf "\tPatching libcrypto.num for provider symbol exports ... "
200+
export OPENSSL_SOURCE_DIR
201+
${SCRIPT_DIR}/patch-libcrypto-exports.sh >>$LOG_FILE 2>&1
202+
if [ $? != 0 ]; then
203+
printf "ERROR.\n"
204+
printf "\n\nLibcrypto.num patch failed. Last 40 lines of log:\n"
205+
tail -n 40 $LOG_FILE
206+
do_cleanup
207+
exit 1
208+
fi
209+
printf "Done.\n"
210+
211+
printf "\n"
212+
printf " ╔════════════════════════════════════════════════════════════════════╗\n"
213+
printf " ║ *** WARNING *** ║\n"
214+
printf " ╠════════════════════════════════════════════════════════════════════╣\n"
215+
printf " ║ OpenSSL has been PATCHED to export internal provider symbols ║\n"
216+
printf " ║ for unit testing purposes. ║\n"
217+
printf " ║ ║\n"
218+
printf " ║ >> DO NOT USE THIS BUILD IN PRODUCTION ║\n"
219+
printf " ║ >> This build is for TESTING ONLY ║\n"
220+
printf " ║ ║\n"
221+
printf " ║ Internal symbols exported: ossl_provider_new, ossl_provider_* ║\n"
222+
printf " ║ ossl_default_provider_init ║\n"
223+
printf " ╚════════════════════════════════════════════════════════════════════╝\n"
224+
printf "\n"
225+
fi
174226
}
175227

176228
check_openssl_replace_default_mismatch() {
@@ -200,11 +252,40 @@ check_openssl_replace_default_mismatch() {
200252
fi
201253
}
202254

255+
check_replace_default_testing_mismatch() {
256+
local libcrypto_is_patched=0
257+
258+
# Check if libcrypto.num was patched for --enable-replace-default-testing
259+
if is_libcrypto_num_patched; then
260+
libcrypto_is_patched=1
261+
printf "INFO: OpenSSL libcrypto.num patched with internal provider symbol exports (testing build).\n"
262+
fi
263+
264+
# Check for mismatch
265+
if [ "$WOLFPROV_REPLACE_DEFAULT_TESTING" = "1" ] && [ "$libcrypto_is_patched" = "0" ]; then
266+
printf "ERROR: --enable-replace-default-testing build mode mismatch!\n"
267+
printf "Existing OpenSSL was built WITHOUT libcrypto.num patch\n"
268+
printf "Current request: --enable-replace-default-testing build\n\n"
269+
printf "Fix: ./scripts/build-wolfprovider.sh --distclean\n"
270+
printf "Then rebuild with desired configuration.\n"
271+
exit 1
272+
elif [ "$WOLFPROV_REPLACE_DEFAULT_TESTING" != "1" ] && [ "$libcrypto_is_patched" = "1" ]; then
273+
printf "ERROR: Standard build mode mismatch!\n"
274+
printf "Existing OpenSSL was built WITH libcrypto.num patch (testing mode)\n"
275+
printf "Current request: standard build\n\n"
276+
printf "This OpenSSL build exports internal provider symbols and should NOT be used.\n"
277+
printf "Fix: ./scripts/build-wolfprovider.sh --distclean\n"
278+
printf "Then rebuild with desired configuration.\n"
279+
exit 1
280+
fi
281+
}
282+
203283
install_openssl() {
204284
printf "\nInstalling OpenSSL ${OPENSSL_TAG} ...\n"
205285
clone_openssl
206286
patch_openssl
207287
check_openssl_replace_default_mismatch
288+
check_replace_default_testing_mismatch
208289

209290
pushd ${OPENSSL_SOURCE_DIR} &> /dev/null
210291

scripts/utils-wolfprovider.sh

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ if [ "${WOLFPROV_QUICKTEST}" = "1" ]; then
4949
WOLFPROV_CONFIG_CFLAGS="${WOLFPROV_CONFIG_CFLAGS} -DWOLFPROV_QUICKTEST"
5050
fi
5151

52+
if [ "${WOLFPROV_REPLACE_DEFAULT_TESTING}" = "1" ]; then
53+
WOLFPROV_CONFIG_CFLAGS="${WOLFPROV_CONFIG_CFLAGS} -DWOLFPROV_REPLACE_DEFAULT_UNIT_TEST"
54+
fi
55+
5256
if [ "$WOLFSSL_ISFIPS" -eq "1" ] || [ -n "$WOLFSSL_FIPS_BUNDLE" ]; then
5357
WOLFPROV_CONFIG=${WOLFPROV_CONFIG:-"$WOLFPROV_SOURCE_DIR/provider-fips.conf"}
5458
else
@@ -143,8 +147,8 @@ install_wolfprov() {
143147

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

173+
# Final warning for replace-default-testing builds
174+
if [ "$WOLFPROV_REPLACE_DEFAULT_TESTING" = "1" ]; then
175+
printf "\n"
176+
printf "╔══════════════════════════════════════════════════════════════════════════╗\n"
177+
printf "║ *** TESTING BUILD COMPLETE *** ║\n"
178+
printf "╠══════════════════════════════════════════════════════════════════════════╣\n"
179+
printf "║ This OpenSSL build has been patched with INTERNAL SYMBOL EXPORTS ║\n"
180+
printf "║ for unit testing with --enable-replace-default-testing ║\n"
181+
printf "║ ║\n"
182+
printf "║ >> DO NOT DEPLOY TO PRODUCTION ║\n"
183+
printf "║ >> FOR DEVELOPMENT AND TESTING USE ONLY ║\n"
184+
printf "║ ║\n"
185+
printf "║ To build a production version, rebuild WITHOUT this flag. ║\n"
186+
printf "╚══════════════════════════════════════════════════════════════════════════╝\n"
187+
printf "\n"
188+
fi
189+
169190
popd &> /dev/null
170191
}
171192

0 commit comments

Comments
 (0)