MISRA Compliance - aidangarske/wolfCOSE GitHub Wiki
MISRA C Compliance
wolfCOSE strives for MISRA C compliance and is checked in CI on every pull request. The project is not yet fully MISRA C:2023 compliant since there is no checker for 2023 that is publicly availible yet. We do fully test and support the 2012 Misra-C standard. Full MISRA C:2023 verification requires commercial tooling (like LDRA, Polyspace, Cppcheck Premium). The current free tooling provides around 80% coverage across syntax, essential type, and data-flow rules.
Coverage
MISRA C:2012
Verified via cppcheck's MISRA addon (--addon=misra) with all wolfCOSE algorithm and feature macros defined. Covers ~65-75% of decidable MISRA C:2023 rules including:
- Syntax rules (comments, declarations, expressions)
- Control flow rules (goto, switch, loops)
- Declaration and type rules
- Pointer and array rules
Workflow: .github/workflows/misra-2012.yml
All wolfCOSE and wolfSSL feature macros are explicitly defined so cppcheck checks the full code path rather than enumerating wolfSSL's hundreds of platform #ifdef configurations. See Macros for the complete list.
MISRA C:2023
MISRA C:2023 is essentially MISRA C:2012 plus Amendments 1-4. Since free tooling does not directly support MISRA C:2023, compliance is approximated using two approaches:
Strict Compiler Warnings 17 MISRA-adjacent GCC flags beyond the project's standard -Wall -Wextra -Wpedantic -Wshadow -Wconversion:
| Flag | MISRA Rule | Purpose |
|---|---|---|
-Wcast-qual |
Rule 11.8 | Const qualifier preservation |
-Wstrict-prototypes |
Rule 8.2 | Function declaration completeness |
-Wmissing-prototypes |
Rule 8.2 | Missing function prototypes |
-Wold-style-definition |
Rule 8.2 | Old-style function definitions |
-Wdeclaration-after-statement |
Rule 8.x | C90-style declaration ordering |
-Wundef |
Rule 20.9 | Undefined macro in #if |
-Wfloat-equal |
Rule 13.4 | Float equality comparison |
-Wpointer-arith |
Rule 18.x | Pointer arithmetic safety |
-Wredundant-decls |
Rule 8.x | Redundant declarations |
-Wnested-externs |
Rule 8.x | Nested extern declarations |
-Wformat=2 |
Rule 21.6 | Format string safety |
-Wformat-security |
Rule 21.6 | Format string security |
-Wlogical-op |
Rule 12.x | Logical vs bitwise operators |
-Wjump-misses-init |
Rule 15.1 | Goto skipping initialization |
-Wdouble-promotion |
Rule 10.x | Implicit float-to-double |
-Wnull-dereference |
Safety | Null pointer dereference |
-Wsign-conversion |
Rule 10.x | Signed/unsigned conversion |
clang-tidy Checks covers standard library safety (Amendment 3), deep data-flow analysis, and CERT C rules that map to MISRA 2023 logic:
| Check Category | Coverage |
|---|---|
bugprone-* |
Unsafe patterns (buffer overflows, integer overflows, suspicious constructs) |
cert-* |
CERT C rules mapping to MISRA 2023 logic |
clang-analyzer-* |
Inter-procedural data-flow analysis, pointer tracking |
misc-* |
Miscellaneous safety checks (excluding misc-include-cleaner) |
Workflow: .github/workflows/misra-2023.yml
Coverage Summary
| Area | cppcheck (2012) | Compiler Flags + clang-tidy (2023) | Commercial Tools |
|---|---|---|---|
| Syntax Rules | High (~90%) | High (~95%) | 100% |
| Essential Types | Medium (~50%) | High (~80%) | 100% |
| Data Flow | Low (~30%) | Medium (~50%) | 100% |
| Std Lib Safety | Low (~20%) | Medium (~60%) | 100% |
Known Deviations in wolfCOSE
wolfCOSE has the following documented MISRA C:2012 deviations. Each is suppressed in CI via cppcheck --suppress and justified below.
Rule 2.5: Unused Macro Definitions
Location: include/wolfcose/wolfcose.h (feature gate macros)
Justification: wolfCOSE feature-gate macros (WOLFCOSE_SIGN1, WOLFCOSE_SIGN1_SIGN, etc.) are defined conditionally via #if !defined(NO_X) && !defined(X) guards. When the CI passes both parent and child -D flags on the command line (e.g., -DWOLFCOSE_SIGN1 -DWOLFCOSE_SIGN1_SIGN), the child macro is pre-defined and the header guard skips the #define. cppcheck sees the guarded-away #define as "unused" — a false positive caused by the CI passing explicit flags for cppcheck path coverage.
Rule 8.7: Could Be Defined with Internal Linkage
Location: src/wolfcose.c:wolfCose_SigSize()
Justification: wolfCose_SigSize() is declared WOLFCOSE_LOCAL in wolfcose_internal.h and called from tests/test_cose.c for unit testing. cppcheck only scans src/ and include/, so it does not see the test file usage and incorrectly reports the function could be static. Making it static would break the test suite.
Rule 11.8: Cast Removes Const Qualification
Location: src/wolfcose.c (ECC/ECDH wolfSSL API calls)
Justification: wolfSSL's ECC APIs (wc_ecc_set_rng, wc_ecc_shared_secret, wc_ecc_sign_hash, wc_ecc_verify_hash) take non-const ecc_key* parameters even for operations that do not modify the key data. wolfCOSE's public API correctly uses const qualifiers on key parameters (e.g., const WOLFCOSE_KEY* key) to communicate that keys are not modified. However, when passing the internal ecc_key* from a const WOLFCOSE_KEY to wolfSSL, cppcheck flags the implicit const-to-non-const conversion through the union member access chain. This is a wolfSSL API design limitation that wolfCOSE preserves const-correctness at its own API boundary but cannot enforce it through wolfSSL's non-const function signatures.
Rule 19.2: Union Type Used
Location: include/wolfcose/wolfcose.h:WOLFCOSE_KEY struct (lines 443-464)
Justification: The WOLFCOSE_KEY struct uses a tagged union to hold pointers to wolfCrypt key types (ecc_key*, ed25519_key*, ed448_key*, RsaKey*, dilithium_key*, symmetric key bytes). The kty field discriminates the active union member. This is the standard C pattern for polymorphic types and is fundamental to supporting a multi-algorithm COSE library without dynamic allocation. Replacing the union would require either:
void*pointers (less type-safe, violates Rule 11.5)- Separate functions per algorithm (massive API bloat)
- Dynamic allocation (violates the zero-allocation design constraint)
Rule 21.15: Overlapping Memory in Copy
Location: src/wolfcose.c:wolfCose_EccSignRaw() (XMEMMOVE calls)
Justification: XMEMMOVE (memmove) is used intentionally for overlapping memory regions when right-justifying ECC r/s signature components within a single buffer. The signature buffer contains r||s where r or s may be shorter than the coordinate size and needs to be shifted right with zero-padding. memmove is the correct function for this — it handles overlapping source and destination by design. cppcheck flags the overlap as a potential issue, but this is the intended behavior per RFC 8152 Section 8.1.
MISRA C:2023 Deviations (clang-tidy)
The following clang-tidy checks are suppressed in the MISRA 2023 workflow. GCC strict MISRA warnings are fully clean (0 warnings).
bugprone-branch-clone: Identical Consecutive Switch Branches
Location: src/wolfcose.c (algorithm dispatch switches)
Justification: Different COSE algorithms intentionally map to the same wolfCrypt value. For example, ES512 and EdDSA both use WC_HASH_TYPE_SHA512, and A128GCM/A192GCM share the same nonce length. The switch branches are not bugs — they represent distinct algorithm IDs with identical cryptographic parameters.
bugprone-easily-swappable-parameters: Adjacent Parameters of Similar Types
Location: Multiple public API functions
Justification: Advisory warning about adjacent function parameters of the same type (e.g., size_t payloadLen, size_t detachedLen). Fixing requires reordering or wrapping parameters, which would break the public API. The parameter ordering follows RFC 9052 structure conventions.
Fully Compliant Rules (Notable)
| Rule | Status | Notes |
|---|---|---|
| Rule 15.1 (no goto) | Compliant | All functions use cascading if (ret == WOLFCOSE_SUCCESS) with a single return ret |
| Rule 15.5 (single exit) | Compliant | All functions have exactly one return statement |
| Rule 17.2 (no recursion) | Compliant | CBOR decoder uses iterative traversal with a bounded stack (WOLFCOSE_CBOR_MAX_DEPTH) |
| Rule 17.7 (check returns) | Compliant | All return values checked or explicitly cast to (void) |
| Rule 12.1 (explicit precedence) | Compliant | All &&/` |