Skip to content
Open
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
281 changes: 281 additions & 0 deletions .github/workflows/static-analysis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
name: Static Analysis

# START OF COMMON SECTION
on:
schedule:
# Run nightly at 2 AM UTC
- cron: '0 2 * * *'
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# END OF COMMON SECTION

jobs:
cppcheck:
name: cppcheck Static Analysis
runs-on: ubuntu-22.04
timeout-minutes: 30
steps:
- name: Checkout wolfProvider
uses: actions/checkout@v4
with:
fetch-depth: 1

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y cppcheck

- name: Build dependencies (OpenSSL and wolfSSL)
run: |
OPENSSL_TAG=openssl-3.5.4 WOLFSSL_TAG=master ./scripts/build-wolfprovider.sh 2>&1 | tail -100 || true
# We only need the build to succeed enough to have headers available

- name: Generate configure script
run: |
./autogen.sh || true

- name: Configure to generate config.h
run: |
OPENSSL_INSTALL_DIR="$PWD/openssl-install"
WOLFSSL_INSTALL_DIR="$PWD/wolfssl-install"

# Configure to generate config.h (needed for cppcheck)
./configure \
--with-openssl="$OPENSSL_INSTALL_DIR" \
--with-wolfssl="$WOLFSSL_INSTALL_DIR" \
--prefix="$PWD/wolfprov-install" \
>/dev/null 2>&1 || true

- name: Run cppcheck
run: |
# Configure include paths for cppcheck
OPENSSL_INC="$PWD/openssl-install/include"
WOLFSSL_INC="$PWD/wolfssl-install/include"
WOLFPROV_INC="$PWD/include"

# Run cppcheck on source files only (tests can be analyzed separately if needed)
# Use --force and suppress noValidConfiguration to proceed even with incomplete config
cppcheck \
--enable=all \
--suppress=missingIncludeSystem \
--suppress=unusedFunction \
--suppress=unmatchedSuppression \
--suppress=noValidConfiguration \
--inline-suppr \
--force \
--error-exitcode=0 \
-I "$OPENSSL_INC" \
-I "$WOLFSSL_INC" \
-I "$WOLFPROV_INC" \
--platform=unix64 \
src/ 2>&1 | tee cppcheck-output.txt || true

# Display output (filter out noValidConfiguration messages and progress)
grep -v "noValidConfiguration" cppcheck-output.txt | \
grep -v "^Checking " | \
grep -v "^[0-9]*/[0-9]* files checked" | \
grep -v "^nofile:0:0: information:" || true

# Count errors and warnings (count lines with error:/warning: that are actual issues)
# Use wc -l for more reliable counting, and strip whitespace
ERROR_COUNT=$(grep -E "^src/.*:[0-9]+:[0-9]+:.*error:" cppcheck-output.txt 2>/dev/null | wc -l | tr -d '[:space:]' || echo "0")
WARNING_COUNT=$(grep -E "^src/.*:[0-9]+:[0-9]+:.*warning:" cppcheck-output.txt 2>/dev/null | wc -l | tr -d '[:space:]' || echo "0")

# Ensure we have valid integers (default to 0 if empty)
ERROR_COUNT=${ERROR_COUNT:-0}
WARNING_COUNT=${WARNING_COUNT:-0}

echo "cppcheck found $ERROR_COUNT errors and $WARNING_COUNT warnings"

# Fail only if critical errors found (adjust threshold as needed)
if [ "${ERROR_COUNT}" -gt 0 ] 2>/dev/null; then
echo "cppcheck found errors"
exit 1
fi

- name: Upload cppcheck results
if: always()
uses: actions/upload-artifact@v4
with:
name: cppcheck-results
path: cppcheck-output.txt
retention-days: 7

scan-build:
name: clang Static Analyzer (scan-build)
runs-on: ubuntu-22.04
timeout-minutes: 45
steps:
- name: Checkout wolfProvider
uses: actions/checkout@v4
with:
fetch-depth: 1

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang clang-tools build-essential autoconf automake libtool pkg-config

- name: Build dependencies (OpenSSL and wolfSSL)
run: |
OPENSSL_TAG=openssl-3.5.4 WOLFSSL_TAG=master ./scripts/build-wolfprovider.sh 2>&1 | tail -100 || true

- name: Generate configure script
run: |
./autogen.sh

- name: Configure project for scan-build
run: |
OPENSSL_INSTALL_DIR="$PWD/openssl-install"
WOLFSSL_INSTALL_DIR="$PWD/wolfssl-install"

# Configure with clang (scan-build will wrap it later)
CC=clang ./configure \
--with-openssl="$OPENSSL_INSTALL_DIR" \
--with-wolfssl="$WOLFSSL_INSTALL_DIR" \
--prefix="$PWD/wolfprov-install"

- name: Build library with scan-build
run: |
# Clean any previous build artifacts
make clean || true

# Build only the library with scan-build wrapping clang
# scan-build intercepts compiler calls, so we need to ensure CC is set to clang
# Use --use-cc and --use-c++ to explicitly tell scan-build which compiler to wrap
scan-build -o scan-build-output \
--use-cc=clang \
--use-c++=clang++ \
make -j$(nproc) CC=clang libwolfprov.la 2>&1 | tee scan-build-log.txt || true

# scan-build returns 0 even if build fails, so we check exit status explicitly
echo "Build completed (scan-build may have reports even if build partially failed)"

- name: Check scan-build results
run: |
# Find the latest scan-build report directory
REPORT_DIR=$(find scan-build-output -maxdepth 1 -type d -name "scan-build-*" | sort -r | head -1)

if [ -z "$REPORT_DIR" ] || [ ! -d "$REPORT_DIR" ]; then
echo "No scan-build report directory found"
exit 0
fi

# Count bugs found
BUG_COUNT=$(find "$REPORT_DIR" -name "*.html" | wc -l)
echo "scan-build found $BUG_COUNT potential issues"

# Display summary
if [ -f "$REPORT_DIR/index.html" ]; then
echo "View detailed report in scan-build-output/index.html"
# Extract text summary if possible
grep -o '<title>.*</title>' "$REPORT_DIR/index.html" || true
fi

# Fail if critical bugs found (adjust threshold as needed)
if [ "$BUG_COUNT" -gt 50 ]; then
echo "Too many issues found by scan-build"
exit 1
fi

- name: Upload scan-build results
if: always()
uses: actions/upload-artifact@v4
with:
name: scan-build-results
path: scan-build-output/
retention-days: 7

infer:
name: Facebook Infer Static Analysis
runs-on: ubuntu-22.04
timeout-minutes: 60
steps:
- name: Checkout wolfProvider
uses: actions/checkout@v4
with:
fetch-depth: 1

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y build-essential autoconf automake libtool pkg-config python3 opam

# Install Infer
VERSION=1.1.0
cd /tmp
wget https://github.com/facebook/infer/releases/download/v${VERSION}/infer-linux64-v${VERSION}.tar.xz
tar xf infer-linux64-v${VERSION}.tar.xz
sudo mv infer-linux64-v${VERSION} /opt/infer
sudo ln -sf /opt/infer/bin/infer /usr/local/bin/infer

- name: Build dependencies (OpenSSL and wolfSSL)
run: |
OPENSSL_TAG=openssl-3.5.4 WOLFSSL_TAG=master ./scripts/build-wolfprovider.sh 2>&1 | tail -100 || true

- name: Generate configure script
run: |
./autogen.sh

- name: Configure project
run: |
OPENSSL_INSTALL_DIR="$PWD/openssl-install"
WOLFSSL_INSTALL_DIR="$PWD/wolfssl-install"

./configure \
--with-openssl="$OPENSSL_INSTALL_DIR" \
--with-wolfssl="$WOLFSSL_INSTALL_DIR" \
--prefix="$PWD/wolfprov-install" \
CC=clang

- name: Clean build for Infer
run: |
make clean || true
rm -rf infer-out

- name: Run Infer analysis
run: |
# Run infer on the build (it wraps the compilation)
# Build only the library to avoid test compilation issues
# Explicitly set CC=clang for make
infer run -- make -j$(nproc) CC=clang libwolfprov.la 2>&1 | tee infer-log.txt || true

# Generate text report
if [ -d infer-out ]; then
infer report --issues-csv infer-report.csv 2>&1 || true
infer report --issues-txt infer-report.txt 2>&1 || true

# Display summary
if [ -f infer-report.txt ]; then
echo "=== Infer Analysis Summary ==="
cat infer-report.txt

# Count issues
ISSUE_COUNT=$(grep -c "Found.*issue" infer-report.txt || echo "0")
echo "Infer found issues (check infer-report.txt for details)"

# Fail if too many critical issues (adjust threshold as needed)
if [ "$ISSUE_COUNT" -gt 100 ]; then
echo "Too many issues found by Infer"
exit 1
fi
fi
else
echo "Infer did not produce output directory"
fi

- name: Upload Infer results
if: always()
uses: actions/upload-artifact@v4
with:
name: infer-results
path: |
infer-out/
infer-report.txt
infer-report.csv
infer-log.txt
retention-days: 7
if-no-files-found: ignore
2 changes: 1 addition & 1 deletion src/wp_aes_aead.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ static int wp_aead_tls_init(wp_AeadCtx* ctx, unsigned char* aad, size_t aadLen)
{
int ok = 1;
unsigned char *buf = ctx->buf;
size_t len;
size_t len = 0;
/* CCM will have a tag length set. */
size_t tagLen = (ctx->tagLen != UNINITIALISED_SIZET) ? ctx->tagLen :
EVP_GCM_TLS_TAG_LEN;
Expand Down
4 changes: 2 additions & 2 deletions src/wp_dec_epki2pki.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,11 @@ static int wp_epki2pki_decode(wp_Epki2Pki* ctx, OSSL_CORE_BIO* coreBio,
{
int ok = 1;
int done = 0;
int rc;
int rc = 0;
unsigned char* data = NULL;
word32 len = 0;
char password[1024];
size_t passwordLen;
size_t passwordLen = 0;
word32 tradIdx = 0;

WOLFPROV_ENTER(WP_LOG_COMP_PK, "wp_epki2pki_decode");
Expand Down
8 changes: 4 additions & 4 deletions src/wp_dec_pem2der.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,12 +207,12 @@ static int wp_pem2der_decode_data(const unsigned char* data, word32 len,
{
int ok = 1;
int done = 0;
int rc;
int algoId;
int type;
int rc = 0;
int algoId = 0;
int type = 0;
const char* dataType = NULL;
const char* dataFormat = NULL;
int obj;
int obj = 0;
EncryptedInfo info;
DerBuffer* der = NULL;
OSSL_PARAM params[5];
Expand Down
4 changes: 2 additions & 2 deletions src/wp_ecc_kmgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -2222,9 +2222,9 @@ static int wp_ecc_decode_pki(wp_Ecc* ecc, unsigned char* data, word32 len)
/* Keys decoded from pki should always have public key */
if (ecc->key.type == ECC_PRIVATEKEY_ONLY) {
#ifdef ECC_TIMING_RESISTANT
rc = wc_ecc_make_pub_ex(&ecc->key, NULL, &ecc->rng);
(void)wc_ecc_make_pub_ex(&ecc->key, NULL, &ecc->rng);
#else
rc = wc_ecc_make_pub_ex(&ecc->key, NULL, NULL);
(void)wc_ecc_make_pub_ex(&ecc->key, NULL, NULL);
#endif
}
ecc->hasPub = 1;
Expand Down
8 changes: 4 additions & 4 deletions src/wp_mac_sig.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,10 @@ static int wp_mac_digest_sign_init(wp_MacSigCtx *ctx, const char *mdName,
wp_Mac *mac, const OSSL_PARAM params[])
{
int ok = 1;
unsigned char* priv;
size_t privLen;
const char* cipherName;
const char* properties;
unsigned char* priv = NULL;
size_t privLen = 0;
const char* cipherName = NULL;
const char* properties = NULL;
OSSL_PARAM lParams[4];
int lParamSz = 0;

Expand Down
4 changes: 2 additions & 2 deletions src/wp_rsa_kem.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,8 @@ static int wp_rsasve_generate(wp_RsaKemCtx* ctx, unsigned char* out,
size_t* outLen, unsigned char* secret, size_t* secretLen)
{
int ok = 1;
word32 nLen;
word32 oLen;
word32 nLen = 0;
word32 oLen = 0;
RsaKey* rsa = NULL;

WOLFPROV_ENTER(WP_LOG_COMP_RSA, "wp_rsasve_generate");
Expand Down
Loading
Loading