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
77 changes: 77 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Copilot instructions for wolfCOSE

wolfCOSE is a strictly zero-allocation C library implementing CBOR (RFC 8949)
and COSE (RFC 9052/9053), plus RFC 8230 (RSA keys) and RFC 9964 (ML-DSA), on
top of wolfCrypt. It runs on constrained and FIPS-bounded targets and parses
untrusted, attacker-controlled bytes (CBOR/COSE messages and keys).

When reviewing a pull request, act as a security and correctness reviewer
performing the primary pre-merge gate, in the spirit of a focused
security-review pass. Prioritize real vulnerabilities and behavioral bugs the
diff introduces. Be precise, high-confidence, and brief. A short list of solid
findings is far more useful than a long list of nits.

## How to review

1. Triage the diff by risk. Treat as HIGH RISK anything touching CBOR/COSE
parsing of untrusted input, buffer and length handling, key/secret handling,
algorithm selection and verification, and error paths. Spend your attention
there.
2. For each changed region, reason about the behavioral delta: what did the
code do before, what does it do now, and what new attack surface or weakened
check does the change introduce. If the diff removes a check or a previously
added security fix, call that out as a likely regression.
3. Report a finding only when you can name the concrete failure and, where it
applies, the input that triggers it. Assign a severity (Critical, High,
Medium, Low) and include the relevant CWE.

## What to look for

- Memory safety: out-of-bounds reads and writes, missing or wrong length checks
before copies, pointer arithmetic into caller-provided buffers, off-by-one on
bstr/array/map lengths (CWE-120, CWE-125, CWE-787).
- Integer issues: overflow or underflow in size and length math, signed and
unsigned confusion, and truncation when casting lengths to `word32` (CWE-190,
CWE-191).
- NULL and uninitialized use: missing NULL checks on parameters and return
values, use of a buffer before it is populated (CWE-476).
- CBOR and COSE parsing of untrusted input: unchecked element counts, lengths,
or nesting depth; trusting a header or a decoded length without validating it
against the remaining buffer; accepting non-preferred or trailing CBOR.
- Cryptographic correctness and misuse: nonce or IV reuse, algorithm confusion
(dispatching on an unauthenticated `alg`), comparing secrets or MAC tags with
non-constant-time `memcmp`, and unchecked crypto return codes (CWE-327,
CWE-208, CWE-347).
- Zeroization: sensitive data (keys, seeds, shared secrets, plaintext, crypto
intermediates) must be cleared with `wolfCose_ForceZero` (wolfCOSE's secure
scrub helper) on every exit path, including error and early-return paths. Flag
missing or wrong-size scrubs and untracked temporary copies.
- Logic and contracts: inverted conditions, wrong enum or label, copy-paste
errors, missing error checks, error paths that skip cleanup, and API misuse
(wrong call order, use after a failed call).
- Spec conformance: deviations from RFC 9052/9053, RFC 8949 deterministic
encoding, RFC 8230 (RSA key parameters), or RFC 9964 (ML-DSA / AKP) message
and key formats.

## Do not report

These are out of scope here. Other tooling owns them, and raising them adds
noise rather than safety.

- Style, formatting, naming, or comment-density observations. Code style is
enforced by the project's own rules and by cppcheck, clang-tidy, and MISRA
checks in CI.
- Maintainability nits such as "function is too long" or "poorly documented
function". Do not flag comment ratios or function length.
- Any suggestion that introduces dynamic allocation. wolfCOSE is strictly
zero-allocation. Never propose `malloc`, `calloc`, `realloc`, `free`, or the
`XMALLOC`/`XFREE`/`XREALLOC` wrappers. Large objects use scoped or static
storage, never the heap.
- C++ idioms or constructs outside C89/C99. The library targets C99 and its
public headers must also compile as C++.
- `wolfCose_ForceZero` replaced by `memset` or a plain loop (the project
deliberately uses `wolfCose_ForceZero` so the scrub is not optimized away);
do not suggest the reverse.

Keep comments few, concrete, and security or correctness focused. If you are
not confident a finding is real, leave it out.
66 changes: 66 additions & 0 deletions .github/semgrep-rules.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# wolfCOSE deterministic security rules (Semgrep).
#
# These encode wolfCOSE invariants that are decidable by pattern and currently
# have zero hits, so they pass today and fail the build on any future
# violation. Run with: semgrep scan --config .github/semgrep-rules.yml --error
#
# Style/maintainability is intentionally out of scope (owned by cppcheck,
# clang-tidy, and MISRA checks). These rules only enforce security invariants.

rules:
- id: wolfcose-no-dynamic-allocation
languages: [c]
severity: ERROR
message: >-
wolfCOSE is strictly zero-allocation. Dynamic memory
(malloc/calloc/realloc/free, alloca, strdup, or the XMALLOC/XFREE/XREALLOC
wrappers) must never appear in the core library. Use a caller-provided
buffer or scoped/static storage instead.
paths:
include:
- src/
- include/wolfcose/
pattern-either:
- pattern: malloc(...)
- pattern: calloc(...)
- pattern: realloc(...)
- pattern: free(...)
- pattern: aligned_alloc(...)
- pattern: alloca(...)
- pattern: strdup(...)
- pattern: XMALLOC(...)
- pattern: XFREE(...)
- pattern: XREALLOC(...)

- id: wolfcose-unsafe-libc
languages: [c]
severity: ERROR
message: >-
Unbounded C library function. Use a length-bounded alternative
(XMEMCPY/XMEMMOVE with an explicit size, snprintf) so a length cannot run
past the destination buffer.
paths:
include:
- src/
- include/wolfcose/
pattern-either:
- pattern: gets(...)
- pattern: strcpy(...)
- pattern: strcat(...)
- pattern: sprintf(...)
- pattern: vsprintf(...)

- id: wolfcose-non-constant-time-compare
languages: [c]
severity: ERROR
message: >-
memcmp/XMEMCMP is not constant-time. In the core library, comparing a
MAC tag, key, or shared secret with a variable-time compare leaks timing
information (CWE-208). Use ConstantCompare for secret-dependent
comparisons.
paths:
include:
- src/
pattern-either:
- pattern: memcmp(...)
- pattern: XMEMCMP(...)
71 changes: 71 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: CodeQL

on:
push:
branches: [ 'main', 'release/**' ]
pull_request:
branches: [ '*' ]
schedule:
- cron: '0 7 * * 1'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read
# Required so CodeQL can upload findings to the Security tab.
security-events: write

jobs:
analyze:
name: CodeQL (C, security)
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y autoconf automake libtool

# Full-feature wolfSSL so every wolfCOSE code path is compiled and
# therefore visible to CodeQL.
- name: Build wolfSSL
run: |
cd ~
git clone --depth 1 https://github.com/wolfSSL/wolfssl.git
cd wolfssl
./autogen.sh
./configure --enable-ecc --enable-ed25519 --enable-ed448 \
--enable-curve25519 --enable-curve448 \
--enable-aesgcm --enable-aesccm --enable-aescbc \
--enable-sha384 --enable-sha512 \
--enable-keygen --enable-hkdf --enable-aeskeywrap \
--enable-chacha --enable-poly1305 \
--enable-mldsa --enable-rsapss \
--prefix=$HOME/wolfssl-install
make -j$(nproc)
make install

- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: c-cpp
build-mode: manual
# security-extended runs only the security query suites. The default
# "security-and-quality" pack also flags maintainability nits (long
# functions, comment density), which we intentionally exclude here.
queries: security-extended

- name: Build wolfCOSE
run: |
export WOLFSSL_DIR=$HOME/wolfssl-install
make CFLAGS="-std=c99 -DHAVE_ANONYMOUS_INLINE_AGGREGATES=1 -Os -Wall -Wextra -Wpedantic -Wshadow -Wconversion -I./include -isystem $WOLFSSL_DIR/include" \
LDFLAGS="-L$WOLFSSL_DIR/lib -lwolfssl"

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:c-cpp"
24 changes: 24 additions & 0 deletions .github/workflows/house-style.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: House Style

on:
push:
branches: [ 'main', 'release/**' ]
pull_request:
branches: [ '*' ]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
house-style:
name: wolfCOSE house-style conventions
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- name: Check conventions (no goto, C-style comments, banner style, no tabs/trailing space)
run: sh scripts/check_house_style.sh
34 changes: 34 additions & 0 deletions .github/workflows/semgrep.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Semgrep

on:
push:
branches: [ 'main', 'release/**' ]
pull_request:
branches: [ '*' ]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
semgrep:
name: Semgrep (wolfCOSE security rules)
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: '3.x'

- name: Install Semgrep
run: pip install --quiet semgrep

# --error makes the job fail on any finding. The rules self-scope via
# their `paths:` blocks, so scanning the whole tree is fine.
- name: Run wolfCOSE security rules
run: semgrep scan --config .github/semgrep-rules.yml --error --quiet .
45 changes: 45 additions & 0 deletions scripts/check_house_style.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/bin/sh
# wolfCOSE house-style check.
#
# Enforces the repo's C conventions across all tracked C sources (the vendored
# lightpanda tree is excluded). Comment and whitespace conventions are text, not
# code structure, so git grep is the right tool here. Run from the repo root:
# sh scripts/check_house_style.sh
# Exits non-zero on any deviation.

status=0
PATHS='*.c *.h :(exclude)lightpanda/'
tab=$(printf '\t')

report() {
matches=$(cat)
if [ -n "$matches" ]; then
printf '\nFAIL: %s\n' "$1"
printf '%s\n' "$matches"
status=1
fi
}

# No goto anywhere; new code uses fallthrough cleanup with a single exit.
git grep -nw goto -- $PATHS | report "goto is banned (use fallthrough cleanup gated on 'if (ret == WOLFCOSE_SUCCESS)')"

# C-style comments only; // line comments are not allowed (URLs in strings/headers excepted).
git grep -nE '//' -- $PATHS | grep -vE 'https?://|s?ftp://|file://' | report "C++ // comments are banned; use /* ... */"

# Section banners use the /* ----- ... ----- */ style, not ===== / ##### / **** runs.
git grep -nE '/\*[* ]*(={4,}|#{4,}|\*{4,})' -- $PATHS | report "section banners must use the /* ----- ... ----- */ style"

# Null-check pointers with != NULL, not if (!ptr).
git grep -nE 'if \(![A-Za-z_]' -- $PATHS | report "null-check pointers with '!= NULL', not 'if (!ptr)'"

# Spaces, no tabs.
git grep -nE "$tab" -- $PATHS | report "tabs are banned in C sources; use spaces"

# No trailing whitespace.
git grep -nE ' +$' -- $PATHS | report "trailing whitespace"

if [ "$status" -ne 0 ]; then
printf '\nHouse-style check failed.\n'
exit 1
fi
printf 'House-style check passed.\n'
8 changes: 3 additions & 5 deletions tests/test_cose.c
Original file line number Diff line number Diff line change
Expand Up @@ -13289,10 +13289,8 @@ static void test_force_failure_crypto(void)
}
#endif /* WOLFCOSE_FORCE_FAILURE */

/* ========================================================
* Negative Test Coverage - Phases 1-10
* Tests for validation/error handling code paths
* ======================================================== */
/* ----- Negative Test Coverage - Phases 1-10
* Tests for validation/error handling code paths ----- */

/* ----- Phase 1: Buffer Too Small Tests ----- */
#ifdef WOLFCOSE_HAVE_ES256
Expand Down Expand Up @@ -16491,7 +16489,7 @@ int test_cose(void)
test_cose_key_ecc_public_only();
#endif

/* ======== Negative Test Coverage - Phases 1-10 ======== */
/* ----- Negative Test Coverage - Phases 1-10 ----- */
TEST_LOG("\n--- Negative Test Coverage (Phases 1-10) ---\n");

/* Phase 1: Buffer Too Small Tests */
Expand Down
Loading