diff --git a/.github/workflows/docs-site.yml b/.github/workflows/docs-site.yml new file mode 100644 index 00000000..d212766f --- /dev/null +++ b/.github/workflows/docs-site.yml @@ -0,0 +1,73 @@ +name: Build manual with documentation tooling + +on: + pull_request: + paths: + - 'docs/**' + - 'mkdocs.yml' + - 'tools/docs_manual.py' + - 'tools/docs-manual/**' + - 'docker/docs/**' + - '.github/workflows/docs-site.yml' + push: + branches: [main] + paths: + - 'docs/**' + - 'mkdocs.yml' + - 'tools/docs_manual.py' + - 'tools/docs-manual/**' + - 'docker/docs/**' + - '.github/workflows/docs-site.yml' + workflow_dispatch: + +permissions: + contents: read + packages: read + +jobs: + build: + runs-on: ubuntu-24.04 + timeout-minutes: 60 + steps: + - uses: actions/checkout@v4 + - name: Select documentation revision + id: documentation + run: echo "sha=$(cat tools/docs-manual/documentation-rev)" >> "$GITHUB_OUTPUT" + - uses: actions/checkout@v4 + with: + repository: wolfSSL/documentation + ref: ${{ steps.documentation.outputs.sha }} + path: build/documentation + submodules: recursive + persist-credentials: false + - uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Pull documentation builder + run: | + set -euo pipefail + image_sha=$(sha256sum docker/docs/Dockerfile docker/docs/requirements.txt | sha256sum | cut -c1-16) + image="ghcr.io/wolfssl/wolfcose-docs:sha-$image_sha" + if ! docker pull "$image"; then + docker build --pull -t "$image" docker/docs + fi + echo "DOCS_IMAGE=$image" >> "$GITHUB_ENV" + - name: Build and validate HTML and PDF + run: | + tools/check-docs-no-internal-links.sh + docker run --rm --user "$(id -u):$(id -g)" --env HOME=/tmp \ + --mount "type=bind,source=$GITHUB_WORKSPACE,target=/work/wolfCOSE" \ + --workdir /work/wolfCOSE "$DOCS_IMAGE" \ + sh -c 'python3 tools/docs_manual.py build --documentation-root /work/wolfCOSE/build/documentation --source-root /work/wolfCOSE --target all && cd build/documentation/wolfCOSE && mkdocs build --strict -f mkdocs.yml' + test -s build/documentation/wolfCOSE/html/index.html + test -s build/documentation/wolfCOSE/wolfCOSE-Manual.pdf + - uses: actions/upload-artifact@v4 + with: + name: wolfcose-manual + path: | + build/documentation/wolfCOSE/html/ + build/documentation/wolfCOSE/wolfCOSE-Manual.pdf + if-no-files-found: error + retention-days: 14 diff --git a/.github/workflows/misra-2023.yml b/.github/workflows/misra-2023.yml index a1772a47..32c4dea7 100644 --- a/.github/workflows/misra-2023.yml +++ b/.github/workflows/misra-2023.yml @@ -206,8 +206,7 @@ jobs: - name: Run clang-tidy run: | export WOLFSSL_DIR=$HOME/wolfssl-install - # Deviations (documented at - # https://github.com/wolfSSL/wolfCOSE/wiki/MISRA-Compliance): + # Deviations (documented in docs/MISRA-Compliance.md): # # -bugprone-branch-clone: Different COSE algorithms intentionally # map to the same wolfCrypt value (e.g. ES512 and EdDSA both diff --git a/.github/workflows/publish-docs-image.yml b/.github/workflows/publish-docs-image.yml new file mode 100644 index 00000000..51b7907c --- /dev/null +++ b/.github/workflows/publish-docs-image.yml @@ -0,0 +1,42 @@ +name: Publish documentation image + +on: + push: + branches: [main] + paths: + - 'docker/docs/**' + - '.github/workflows/publish-docs-image.yml' + workflow_dispatch: + +permissions: + contents: read + packages: write + +concurrency: + group: publish-wolfcose-docs-image + cancel-in-progress: false + +jobs: + publish: + if: github.repository == 'wolfSSL/wolfCOSE' + runs-on: ubuntu-24.04 + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + - name: Select image tag + id: image + run: | + image_sha=$(sha256sum docker/docs/Dockerfile docker/docs/requirements.txt | sha256sum | cut -c1-16) + echo "tag=ghcr.io/wolfssl/wolfcose-docs:sha-$image_sha" >> "$GITHUB_OUTPUT" + - uses: docker/setup-buildx-action@v3 + - uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - uses: docker/build-push-action@v6 + with: + context: docker/docs + file: docker/docs/Dockerfile + push: true + tags: ${{ steps.image.outputs.tag }} diff --git a/.github/workflows/wiki-sync.yml b/.github/workflows/wiki-sync.yml deleted file mode 100644 index 7785d7d5..00000000 --- a/.github/workflows/wiki-sync.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Sync docs to wiki - -# The wiki is a generated mirror of docs/. Edit docs/ via pull requests; -# this publishes them to the GitHub wiki on every merge to main. -on: - push: - branches: [main] - paths: ['docs/**'] - workflow_dispatch: - -permissions: - contents: write - -concurrency: - group: wiki-sync - cancel-in-progress: true - -defaults: - run: - shell: bash -e {0} - -jobs: - sync: - runs-on: ubuntu-latest - container: - image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc - steps: - - uses: actions/checkout@v4 - - - name: Trust workspace - if: runner.os == 'Linux' - run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - - - name: Publish docs/ to wiki - uses: Andrew-Chen-Wang/github-wiki-action@50650fccf3a10f741995523cf9708c53cec8912a # v4 - with: - path: docs/ diff --git a/.gitignore b/.gitignore index 62acc949..7ca05baa 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,9 @@ experimental-check.err *.dSYM/ .wolfcose-build-config +# Docs manual build output (see DOCS-BUILD.md) +/build/ + # Binaries tests/test_wolfcose tests/test_wolfcose_eat_psa diff --git a/ChangeLog.md b/ChangeLog.md index 1f7e79b8..8cea0501 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -187,7 +187,7 @@ MAC, and key distribution, and standardized post-quantum ML-DSA signatures * Minimal footprint: an ES256 `COSE_Sign1` build is ~5.1 KB verify-only and ~6.8 KB sign + verify for the wolfCOSE COSE + CBOR engine; see the - [Footprint](https://github.com/wolfSSL/wolfCOSE/wiki/Footprint) page for + [Footprint](https://www.wolfssl.com/documentation/manuals/wolfcose/Footprint.html) page for total-flash numbers including wolfCrypt. * MISRA C:2012 and C:2023 checked. * API hardening: `COSE_Encrypt` and `wc_CoseMac_Create` direct mode now require diff --git a/IDE/STM32Cube/README.md b/IDE/STM32Cube/README.md index db20529a..d3738119 100644 --- a/IDE/STM32Cube/README.md +++ b/IDE/STM32Cube/README.md @@ -41,5 +41,5 @@ wolfCOSE is configured through the wolfSSL `user_settings.h` (included before wolfCrypt features (`HAVE_ECC`, `WOLFSSL_SHA384/512`, `WOLFSSL_HAVE_MLDSA`). See the wolfCOSE `examples/` for sign1, mac0, and encrypt0 usage, and the -[STM32Cube wiki page](https://github.com/wolfSSL/wolfCOSE/wiki/STM32Cube) for +[STM32Cube manual page](https://www.wolfssl.com/documentation/manuals/wolfcose/STM32Cube.html) for the full walkthrough including a ready to run NUCLEO-H563ZI project. diff --git a/README.md b/README.md index 5b811f9d..e7292cd6 100644 --- a/README.md +++ b/README.md @@ -23,12 +23,12 @@ wolfCOSE is a lightweight and fast C library implementing core CBOR and COSE sta * **Post-Quantum Cryptography:** * ML-DSA (FIPS 204 / RFC 9964) at all security levels. * HSS/LMS stateful hash-based signing (RFC 8778 / CNSA 2.0). -* **Fast Performance:** On an Intel i9-11950H, end-to-end `COSE_Sign1` reaches 66,538 sign/s and 26,437 verify/s with ES256, and 21,986 sign/s and 53,686 verify/s with ML-DSA-44. See the [performance and footprint details](https://github.com/wolfSSL/wolfCOSE/wiki/Footprint) and [wolfCOSE vs. The Field](https://www.wolfssl.com/wolfcose-vs-the-field-the-smallest-and-fastest-cose-library-now-with-post-quantum-ml-dsa-at-the-same-cost/). +* **Fast Performance:** On an Intel i9-11950H, end-to-end `COSE_Sign1` reaches 66,538 sign/s and 26,437 verify/s with ES256, and 21,986 sign/s and 53,686 verify/s with ML-DSA-44. See the [performance and footprint details](https://www.wolfssl.com/documentation/manuals/wolfcose/Footprint.html) and [wolfCOSE vs. The Field](https://www.wolfssl.com/wolfcose-vs-the-field-the-smallest-and-fastest-cose-library-now-with-post-quantum-ml-dsa-at-the-same-cost/). * **PSA Attestation:** EAT / PSA Token issuance and verification with delegated HSM signing support. * **41 Cryptographic Algorithms:** Broad algorithm coverage across signing, encryption, MAC, and key distribution. * **Embedded-First Design:** Zero dynamic memory allocation (no heap, zero `.data`/`.bss`). Operates on caller-supplied buffers with bounded stack usage. * **FIPS 140-3 Path:** Uses wolfCrypt (FIPS Certificate #4718) as its sole cryptographic dependency. -* **STM32 Integrated:** Drop-in STM32Cube pack (`I-CUBE-wolfCOSE`) available for STM32CubeMX / IDE ([Details](https://github.com/wolfSSL/wolfCOSE/wiki/STM32Cube)). +* **STM32 Integrated:** Drop-in STM32Cube pack (`I-CUBE-wolfCOSE`) available for STM32CubeMX / IDE ([Details](https://www.wolfssl.com/documentation/manuals/wolfcose/STM32Cube.html)). ## Supported Algorithms @@ -71,7 +71,7 @@ the corresponding `wc_Cose_VerifyCounterSignature*()` API. wolfCOSE requires [wolfSSL](https://www.wolfssl.com/) as its crypto backend. **Minimum supported version: v5.8.0-stable**. Some optional algorithms require -newer releases; see [Getting Started](docs/Getting-Started.md#prerequisites) for +newer releases; see [Getting Started](https://www.wolfssl.com/documentation/manuals/wolfcose/Getting-Started.html#prerequisites) for feature-specific dependency floors and build instructions. HSS/LMS (RFC 8778) requires v5.9.2-stable or later. @@ -104,7 +104,7 @@ stack and disable the algorithms a Sign1 + Encrypt0 build never uses: --disable-errorstrings ``` -See [Tuning for Size](docs/Macros.md#tuning-for-size) and [Tuning for Speed](docs/Macros.md#tuning-for-speed) +See [Tuning for Size](https://www.wolfssl.com/documentation/manuals/wolfcose/Macros.html#tuning-for-size) and [Tuning for Speed](https://www.wolfssl.com/documentation/manuals/wolfcose/Macros.html#tuning-for-speed) for squeezing wolfCOSE and wolfCrypt further on MCUs. ### Minimal Build (Post-Quantum / ML-DSA only) @@ -213,19 +213,25 @@ make coverage-force-failure # Include crypto failure path testing ## Documentation -Full documentation is available in the [Wiki](https://github.com/wolfSSL/wolfCOSE/wiki): - -- [Getting Started](https://github.com/wolfSSL/wolfCOSE/wiki/Getting-Started): Build instructions and first steps -- [Message Types](https://github.com/wolfSSL/wolfCOSE/wiki/Message-Types): All six RFC 9052 messages (Sign1, Sign, Encrypt0, Encrypt, Mac0, Mac) and RFC 9338 countersignatures with code samples -- [Algorithms](https://github.com/wolfSSL/wolfCOSE/wiki/Algorithms): Complete list of 41 supported algorithms with COSE IDs -- [API Reference](https://github.com/wolfSSL/wolfCOSE/wiki/API-Reference): Function signatures, data structures, error codes -- [Macros](https://github.com/wolfSSL/wolfCOSE/wiki/Macros): Compile-time configuration, size tuning, and ECDSA nonce policy -- [PSA-EAT](https://github.com/wolfSSL/wolfCOSE/wiki/PSA-EAT): RFC 9783 PSA token profiles, APIs, macros, and security guidance -- [Footprint](https://github.com/wolfSSL/wolfCOSE/wiki/Footprint): Size and speed numbers, desktop and on-device -- [Testing](https://github.com/wolfSSL/wolfCOSE/wiki/Testing): Test infrastructure, coverage, and failure injection -- [MISRA Compliance](https://github.com/wolfSSL/wolfCOSE/wiki/MISRA-Compliance): MISRA C:2012 and C:2023 compliance status and deviation rationale -- [Project Structure](https://github.com/wolfSSL/wolfCOSE/wiki/Project-Structure): Source file layout -- [STM32Cube](https://github.com/wolfSSL/wolfCOSE/wiki/STM32Cube): Install and run wolfCOSE as an STM32Cube pack on device +The official wolfCOSE manual is published at +[wolfssl.com/documentation/manuals/wolfcose](https://www.wolfssl.com/documentation/manuals/wolfcose/index.html): + +- [Getting Started](https://www.wolfssl.com/documentation/manuals/wolfcose/Getting-Started.html): Build instructions and first steps +- [Message Types](https://www.wolfssl.com/documentation/manuals/wolfcose/Message-Types.html): All six RFC 9052 messages (Sign1, Sign, Encrypt0, Encrypt, Mac0, Mac) and RFC 9338 countersignatures with code samples +- [Algorithms](https://www.wolfssl.com/documentation/manuals/wolfcose/Algorithms.html): Complete list of 41 supported algorithms with COSE IDs +- [API Reference](https://www.wolfssl.com/documentation/manuals/wolfcose/API-Reference.html): Function signatures, data structures, error codes +- [Macros](https://www.wolfssl.com/documentation/manuals/wolfcose/Macros.html): Compile-time configuration, size tuning, and ECDSA nonce policy +- [PSA-EAT](https://www.wolfssl.com/documentation/manuals/wolfcose/PSA-EAT.html): RFC 9783 PSA token profiles, APIs, macros, and security guidance +- [Footprint](https://www.wolfssl.com/documentation/manuals/wolfcose/Footprint.html): Size and speed numbers, desktop and on-device +- [Testing](https://www.wolfssl.com/documentation/manuals/wolfcose/Testing.html): Test infrastructure, coverage, and failure injection +- [MISRA Compliance](https://www.wolfssl.com/documentation/manuals/wolfcose/MISRA-Compliance.html): MISRA C:2012 and C:2023 compliance status and deviation rationale +- [Project Structure](https://www.wolfssl.com/documentation/manuals/wolfcose/Project-Structure.html): Source file layout +- [STM32Cube](https://www.wolfssl.com/documentation/manuals/wolfcose/STM32Cube.html): Install and run wolfCOSE as an STM32Cube pack on device + +The manual sources live in [`docs/`](docs/); `mkdocs.yml` defines the navigation +and the shared [`wolfSSL/documentation`](https://github.com/wolfSSL/documentation) +tooling builds the HTML and PDF. See [docs/dev/DOCS-BUILD.md](docs/dev/DOCS-BUILD.md) +for local previews and how changes reach the website. ## Release Notes diff --git a/docker/docs/Dockerfile b/docker/docs/Dockerfile new file mode 100644 index 00000000..b5e806e1 --- /dev/null +++ b/docker/docs/Dockerfile @@ -0,0 +1,15 @@ +FROM python:3.12-slim-bookworm + +LABEL org.opencontainers.image.source="https://github.com/wolfSSL/wolfCOSE" + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + bash git make patch perl librsvg2-bin \ + pandoc texlive-xetex texlive-latex-extra texlive-fonts-recommended \ + fonts-noto-core fonts-noto-mono lmodern \ + && rm -rf /var/lib/apt/lists/* + +COPY requirements.txt /tmp/requirements-docs.txt +RUN python -m pip install --no-cache-dir -r /tmp/requirements-docs.txt + +WORKDIR /work diff --git a/docker/docs/requirements.txt b/docker/docs/requirements.txt new file mode 100644 index 00000000..f2caded5 --- /dev/null +++ b/docker/docs/requirements.txt @@ -0,0 +1 @@ +mkdocs==1.6.1 diff --git a/docs/API-Reference.md b/docs/API-Reference.md index 3bf051f2..ba2acb59 100644 --- a/docs/API-Reference.md +++ b/docs/API-Reference.md @@ -1164,7 +1164,7 @@ pin the same algorithm. ## PSA/EAT API Available only when `WOLFCOSE_ENABLE_EAT_PSA` and the selected profile and -envelope gates are defined. Include ``. See [[PSA-EAT]] +envelope gates are defined. Include ``. See [PSA-EAT](PSA-EAT.md) for configuration and security requirements. ### wc_CoseEatPsaToken_Verify @@ -1415,7 +1415,7 @@ numeric `crit` is rejected. `wc_CoseKey_Decode()` and ## See Also -- [[Getting Started]]: Build instructions and examples -- [[Algorithms]]: Supported algorithms -- [[Macros]]: Compile-time configuration -- [[PSA-EAT]]: RFC 9783 PSA attestation support +- [Getting Started](Getting-Started.md): Build instructions and examples +- [Algorithms](Algorithms.md): Supported algorithms +- [Macros](Macros.md): Compile-time configuration +- [PSA-EAT](PSA-EAT.md): RFC 9783 PSA attestation support diff --git a/docs/Algorithms.md b/docs/Algorithms.md index 881be826..f4e39c5f 100644 --- a/docs/Algorithms.md +++ b/docs/Algorithms.md @@ -1,6 +1,6 @@ # Supported Algorithms -wolfCOSE supports 46 algorithms across signing, encryption, MAC, and key distribution. This page provides the complete list with COSE algorithm IDs and required wolfSSL compile-time guards. All algorithms are usable in both single-actor messages (Sign1/Encrypt0/Mac0) and multi-actor messages (Sign/Encrypt/Mac). See [[Message Types]] for details. +wolfCOSE supports 46 algorithms across signing, encryption, MAC, and key distribution. This page provides the complete list with COSE algorithm IDs and required wolfSSL compile-time guards. All algorithms are usable in both single-actor messages (Sign1/Encrypt0/Mac0) and multi-actor messages (Sign/Encrypt/Mac). See [Message Types](Message-Types.md) for details. ## COSE_Sign1 (Digital Signatures) @@ -224,6 +224,6 @@ Future algorithm support planned: ## See Also -- [[Getting Started]]: Build instructions and examples -- [[API Reference]]: Function documentation -- [[Macros]]: Compile-time configuration +- [Getting Started](Getting-Started.md): Build instructions and examples +- [API Reference](API-Reference.md): Function documentation +- [Macros](Macros.md): Compile-time configuration diff --git a/docs/Footprint.md b/docs/Footprint.md index 18d8057d..56710251 100644 --- a/docs/Footprint.md +++ b/docs/Footprint.md @@ -28,7 +28,7 @@ The verify-only profile is the common on-device case: a device verifies signed f ## Build-profile footprint -The lean profiles (see [[Macros]] → Build Profiles). *Glue* is the wolfCOSE engine alone; *total* adds the minimal wolfCrypt backend. +The lean profiles (see [Macros](Macros.md) -> Build Profiles). *Glue* is the wolfCOSE engine alone; *total* adds the minimal wolfCrypt backend. | Profile | Algorithm | wolfCOSE glue | Total + wolfCrypt | |---------|-----------|---------------|-------------------| @@ -78,6 +78,6 @@ Desktop: x86_64 Intel i9-11950H, GCC 14.2. ES256 was measured in June 2026 using ## See Also -- [[Macros]]: build profiles and configuration -- [[Testing]]: memory and stack-bound enforcement in CI -- [[Getting Started]]: building wolfCOSE +- [Macros](Macros.md): build profiles and configuration +- [Testing](Testing.md): memory and stack-bound enforcement in CI +- [Getting Started](Getting-Started.md): building wolfCOSE diff --git a/docs/Getting-Started.md b/docs/Getting-Started.md index 78e5e072..420db298 100644 --- a/docs/Getting-Started.md +++ b/docs/Getting-Started.md @@ -482,7 +482,7 @@ Related strictness that surprises integrators for the same reason: - Trailing bytes after the encoded object are rejected. `inSz` must be exactly the object length, not the capacity of the buffer holding it. Use - [`wc_CBOR_SkipItem()`](API-Reference.md#wc_cbor_skipitem) to carve out the + [`wc_CBOR_SkipItem()`](API-Reference.md#decoding-functions) to carve out the exact byte range of an embedded item. - Two-byte simple values below 32 are malformed, per RFC 8949. - All encountered CBOR text strings are validated as UTF-8. This also applies @@ -534,7 +534,7 @@ Per-function stack usage (from `-fstack-usage`, GCC, `-Os`, aarch64): ## Next Steps -- [[Algorithms]]: See all supported algorithms -- [[API Reference]]: Complete function documentation -- [[Macros]]: Configure compile-time options -- [[Testing]]: Run tests and measure coverage +- [Algorithms](Algorithms.md): See all supported algorithms +- [API Reference](API-Reference.md): Complete function documentation +- [Macros](Macros.md): Configure compile-time options +- [Testing](Testing.md): Run tests and measure coverage diff --git a/docs/Home.md b/docs/Home.md deleted file mode 100644 index 673a727b..00000000 --- a/docs/Home.md +++ /dev/null @@ -1,69 +0,0 @@ -# wolfCOSE Documentation - -Welcome to the wolfCOSE wiki. This is the complete documentation for wolfCOSE, a lightweight CBOR and COSE library for embedded systems. - -## What is wolfCOSE? - -wolfCOSE is a C library implementing: -- **CBOR** (RFC 8949): Concise Binary Object Representation -- **COSE** (RFC 9052/9053): CBOR Object Signing and Encryption, with the RFC 9864 fully-specified signature algorithms - -It uses [wolfSSL](https://www.wolfssl.com/) as the cryptographic backend and is designed for constrained IoT devices, FIPS-bounded deployments, and anywhere you need authenticated CBOR payloads in minimal RAM. - -## Key Features - -| Feature | Description | -|---------|-------------| -| Complete RFC 9052 | All six COSE message types — Sign1, Sign, Encrypt0, Encrypt, Mac0, Mac | -| Multi-signer / multi-recipient | Full `COSE_Sign`, `COSE_Encrypt`, and `COSE_Mac` support | -| Post-quantum signing | ML-DSA (FIPS 204) at all three security levels — first COSE library to ship native PQC | -| PSA attestation | Optional RFC 9783 EAT / PSA token verifier and issuer, including Sign1, Mac0, legacy consumption, and PSA/HSM delegated signing | -| Zero dynamic allocation | Heap-allocation-free, non-recursive; caller-provided buffers within a bounded, target-customizable stack ceiling — zero `.data`/`.bss` | -| Tiny footprint | 3.5–5.1 KB COSE engine, 5.1–6.8 KB with the built-in CBOR engine (verify-only → sign + verify); 26.2 KB → 34.6 KB total with wolfCrypt — ES256 `COSE_Sign1`, dead-code-eliminated | -| 41 algorithms | Signing, encryption, MAC, and key distribution — classical and post-quantum | -| FIPS 140-3 path | Sole crypto dependency is wolfCrypt FIPS Certificate #4718 | -| CNSA 2.0 ready | ML-DSA-44/65/87 for quantum-resistant signatures | -| MISRA-C:2023 | compliance striving, Single-exit pattern, no recursion, deviation-logged | - -## Documentation - -| Page | Description | -|------|-------------| -| [[Getting Started]] | Prerequisites, building, and quick start examples | -| [[Message Types]] | All six RFC 9052 messages (Sign1/Sign, Encrypt0/Encrypt, Mac0/Mac) with code samples | -| [[Algorithms]] | Complete list of supported algorithms with COSE IDs | -| [[API Reference]] | Full API documentation for all functions | -| [[Macros]] | Configuration macros and compile-time options | -| [[Experimental]] | Draft feature status, supported scope, and graduation plan | -| [[PSA-EAT]] | RFC 9783 PSA attestation profiles, APIs, and integration guidance | -| [[Footprint]] | Size and speed numbers, desktop and on-device | -| [[Testing]] | Unit tests, coverage, and failure injection | -| [[Project Structure]] | Source code layout and file descriptions | -| [[STM32Cube]] | Install and run wolfCOSE as an STM32Cube pack on device | -| [[Release Notes]] | Per-version changelog and release highlights | - -## Supported Message Types - -wolfCOSE implements all six COSE message types from RFC 9052: - -| Message Type | Tag | Description | -|--------------|-----|-------------| -| COSE_Sign1 | 18 | Single signer digital signature | -| COSE_Sign | 98 | Multiple signers | -| COSE_Encrypt0 | 16 | Symmetric encryption (single key) | -| COSE_Encrypt | 96 | Multi-recipient encryption | -| COSE_Mac0 | 17 | Symmetric MAC (single key) | -| COSE_Mac | 97 | Multi-recipient MAC | - -## Quick Links - -- [GitHub Repository](https://github.com/wolfSSL/wolfCOSE) -- [wolfSSL Website](https://www.wolfssl.com/) -- [RFC 8949 (CBOR)](https://www.rfc-editor.org/rfc/rfc8949) -- [RFC 9052 (COSE Structures)](https://www.rfc-editor.org/rfc/rfc9052) -- [RFC 9053 (COSE Algorithms)](https://www.rfc-editor.org/rfc/rfc9053) -- [RFC 9864 (Fully-Specified Algorithms)](https://www.rfc-editor.org/rfc/rfc9864) - -## License - -wolfCOSE is free software licensed under GPLv3. For commercial licensing and support, contact [wolfSSL](https://www.wolfssl.com/contact/). diff --git a/docs/MISRA-Compliance.md b/docs/MISRA-Compliance.md index 85d42963..a6be1c98 100644 --- a/docs/MISRA-Compliance.md +++ b/docs/MISRA-Compliance.md @@ -15,7 +15,7 @@ Verified via cppcheck's MISRA addon (`--addon=misra`) with all wolfCOSE algorith **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. This includes all four default-off experimental COSE-HPKE operation gates, `WOLFCOSE_EXPERIMENTAL`, wolfSSL HPKE support, and `WOLFCOSE_ENABLE_DEPRECATED_ALGS`, so draft HPKE code and opt-in RFC 9053 algorithm paths are analyzed rather than silently excluded. See [[Macros]] for the complete list. +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. This includes all four default-off experimental COSE-HPKE operation gates, `WOLFCOSE_EXPERIMENTAL`, wolfSSL HPKE support, and `WOLFCOSE_ENABLE_DEPRECATED_ALGS`, so draft HPKE code and opt-in RFC 9053 algorithm paths are analyzed rather than silently excluded. See [Macros](Macros.md) for the complete list. ### MISRA C:2023 diff --git a/docs/Macros.md b/docs/Macros.md index 7cf68cf3..5a287385 100644 --- a/docs/Macros.md +++ b/docs/Macros.md @@ -122,7 +122,7 @@ and one RFC 9783 Sign1 or Mac0 creation path can issue a correctly labelled `#tfm` token. A selective current-profile verifier still rejects `#tfm` with `WOLFCOSE_E_EAT_PSA_PROFILE` and must not advertise full receiver conformance. -See [[PSA-EAT]] for examples, profile boundaries, and security guidance. +See [PSA-EAT](PSA-EAT.md) for examples, profile boundaries, and security guidance. ## Algorithm Gates @@ -487,7 +487,7 @@ wolfSSL release. ### `WOLFCOSE_MIN_BUFFERS` -One define that trims the caller working set to the minimum that still fits the enabled algorithms. It tightens the CBOR parsing limits (`WOLFCOSE_CBOR_MAX_DEPTH` 8→6, `WOLFCOSE_MAX_MAP_ITEMS` 16→8) and keeps the algorithm-driven signature/scratch floors, which track the largest enabled signature algorithm: +One define that trims the caller working set to the minimum that still fits the enabled algorithms. It tightens the CBOR parsing limits (`WOLFCOSE_CBOR_MAX_DEPTH` 8->6, `WOLFCOSE_MAX_MAP_ITEMS` 16->8) and keeps the algorithm-driven signature/scratch floors, which track the largest enabled signature algorithm: | Enabled signature algorithm | `WOLFCOSE_MAX_SIG_SZ` | `WOLFCOSE_MAX_SCRATCH_SZ` | |---|---|---| @@ -504,7 +504,7 @@ Because the floor follows the algorithm, `WOLFCOSE_MIN_BUFFERS` stays valid with ## Tuning for Size -Four levers, smallest impact last. See the [[Footprint]] page for the resulting numbers. +Four levers, smallest impact last. See the [Footprint](Footprint.md) page for the resulting numbers. 1. **Pick a build profile.** `WOLFCOSE_LEAN` is the lean ES256 core (6.8 KB glue); `WOLFCOSE_LEAN_VERIFY` is verify-only (5.1 KB); the ML-DSA profiles are post-quantum (see [Build Profiles](#build-profiles)). One define selects a curated gate set. 2. **Drop individual features** with `WOLFCOSE_NO_` (e.g. `WOLFCOSE_NO_ENCRYPT0`, `WOLFCOSE_NO_SIGN`, `WOLFCOSE_NO_RECIPIENTS`), or in a lean build add only what you need with `WOLFCOSE_ENABLE_`. @@ -535,7 +535,7 @@ Convenience macros that select a curated set of feature gates for a common deplo ### Footprint -What each profile costs (code + rodata, ES256/ML-DSA-44 `COSE_Sign1`, built from source with dead-code elimination). *Glue* is the wolfCOSE COSE + CBOR engine alone; *total* adds the minimal wolfCrypt backend. Full cross-library and on-device numbers are on the [[Footprint]] page. +What each profile costs (code + rodata, ES256/ML-DSA-44 `COSE_Sign1`, built from source with dead-code elimination). *Glue* is the wolfCOSE COSE + CBOR engine alone; *total* adds the minimal wolfCrypt backend. Full cross-library and on-device numbers are on the [Footprint](Footprint.md) page. | Profile | Algorithm | wolfCOSE glue | Total + wolfCrypt | |---------|-----------|---------------|-------------------| @@ -544,7 +544,7 @@ What each profile costs (code + rodata, ES256/ML-DSA-44 `COSE_Sign1`, built from | `WOLFCOSE_LEAN_MLDSA` | ML-DSA-44 sign + verify | 6.6 KB | 35.8 KB | | `WOLFCOSE_LEAN_VERIFY_MLDSA` | ML-DSA-44 verify-only | 4.6 KB | 20.8 KB | -Post-quantum sign + verify is within ~1 KB of classical ES256 (35.8 vs 34.6 KB), and PQ verify-only is actually *smaller* than classical ES256 verify-only (20.8 vs 26.2 KB): ML-DSA skips the DER signature conversion ECDSA needs. Full numbers (desktop, on-device, and speed) are on the [[Footprint]] page. +Post-quantum sign + verify is within ~1 KB of classical ES256 (35.8 vs 34.6 KB), and PQ verify-only is actually *smaller* than classical ES256 verify-only (20.8 vs 26.2 KB): ML-DSA skips the DER signature conversion ECDSA needs. Full numbers (desktop, on-device, and speed) are on the [Footprint](Footprint.md) page. ### `WOLFCOSE_LEAN_VERIFY` — minimal verify-only @@ -681,6 +681,6 @@ Sub-gates within tests: ## See Also -- [[Getting Started]]: Build instructions -- [[Algorithms]]: Supported algorithms with guards -- [[Testing]]: Test configuration +- [Getting Started](Getting-Started.md): Build instructions +- [Algorithms](Algorithms.md): Supported algorithms with guards +- [Testing](Testing.md): Test configuration diff --git a/docs/Message-Types.md b/docs/Message-Types.md index 2772f062..fa8e1508 100644 --- a/docs/Message-Types.md +++ b/docs/Message-Types.md @@ -12,7 +12,7 @@ wolfCOSE implements the complete RFC 9052 message set — all six COSE structure | `COSE_Mac` | Sec. 6.1 | 97 | `wc_CoseMac_Create` / `wc_CoseMac_Verify` | | `COSE_Key` / `COSE_KeySet` | Sec. 7 | (none) | `wc_CoseKey_Encode` / `wc_CoseKey_Decode` | -Every message can be built attached or detached, with optional external AAD, and every algorithm in [[Algorithms]] is available to every message type that accepts it. +Every message can be built attached or detached, with optional external AAD, and every algorithm in [Algorithms](Algorithms.md) is available to every message type that accepts it. ## COSE_Sign1 — single-signer signature (RFC 9052 Sec. 4.2) @@ -238,7 +238,7 @@ You only pay for the message types you use. Strip whole message types with the m -DWOLFCOSE_NO_MAC0 -DWOLFCOSE_NO_MAC /* drop all MAC */ ``` -For common minimal builds, use a build profile instead of hand-listing macros — these are the supported, CI-tested configurations (see [[Macros]] → Build Profiles): +For common minimal builds, use a build profile instead of hand-listing macros — these are the supported, CI-tested configurations (see [Macros](Macros.md) -> Build Profiles): | Profile | Result | |---------|--------| @@ -251,7 +251,7 @@ A minimal Sign1-verify-only build (`WOLFCOSE_LEAN_VERIFY`) is about **5.1 KB** o ## See also -- [[Algorithms]] — full algorithm list with COSE IDs and wolfCrypt guards -- [[API Reference]] — function signatures, structures, and error codes -- [[Macros]] — every `WOLFCOSE_*` and `WOLFCOSE_NO_*` compile-time toggle +- [Algorithms](Algorithms.md) — full algorithm list with COSE IDs and wolfCrypt guards +- [API Reference](API-Reference.md) — function signatures, structures, and error codes +- [Macros](Macros.md) — every `WOLFCOSE_*` and `WOLFCOSE_NO_*` compile-time toggle - [`examples/scenarios/`](https://github.com/wolfSSL/wolfCOSE/tree/main/examples/scenarios) — `multi_party_approval.c`, `iot_fleet_config.c`, `group_broadcast_mac.c` show real multi-actor flows diff --git a/docs/PSA-EAT.md b/docs/PSA-EAT.md index 6894d578..ec77e1bd 100644 --- a/docs/PSA-EAT.md +++ b/docs/PSA-EAT.md @@ -87,7 +87,7 @@ Current ES256 Sign1 issuer without the PSA/EAT verifier: Replace the last gate with `WOLFCOSE_ENABLE_EAT_PSA_MAC0_ISSUE` for an HMAC256 Mac0 issuer. The same decode opt-outs apply. The algorithm gates can -then replace ES256 or HMAC256 independently as described in [[Macros]]. +then replace ES256 or HMAC256 independently as described in [Macros](Macros.md). These selective examples are useful COSE building blocks, but they are not RFC 9783 `#tfm` receivers: Section 5.2 requires a `#tfm` receiver to accept diff --git a/docs/Project-Structure.md b/docs/Project-Structure.md index 467c6279..9c3c7681 100644 --- a/docs/Project-Structure.md +++ b/docs/Project-Structure.md @@ -174,7 +174,7 @@ Test harness that: ### tests/force_failure.c / force_failure.h -Failure injection system for coverage testing. See [[Testing]] for details. +Failure injection system for coverage testing. See [Testing](Testing.md) for details. --- @@ -269,6 +269,6 @@ Do NOT include in production firmware: ## See Also -- [[Getting Started]]: Build instructions -- [[API Reference]]: Function documentation -- [[Testing]]: Test organization +- [Getting Started](Getting-Started.md): Build instructions +- [API Reference](API-Reference.md): Function documentation +- [Testing](Testing.md): Test organization diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index dc20216a..00000000 --- a/docs/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# wolfCOSE documentation - -These Markdown files are the **source of truth** for the -[wolfCOSE wiki](https://github.com/wolfSSL/wolfCOSE/wiki). - -GitHub wikis cannot take pull requests, so the wiki is a generated, read-only -mirror. Edit the docs here through normal pull requests; on merge to `main`, -`.github/workflows/wiki-sync.yml` publishes them to the wiki. - -## Conventions - -- One file per wiki page. The filename maps to the page title: - `Getting-Started.md` -> "Getting Started", `Home.md` -> wiki landing page, - `_Sidebar.md` -> the wiki sidebar. -- Do not edit pages in the wiki web UI; changes there are overwritten on the - next sync. Edit the file here instead. diff --git a/docs/Release-Notes.md b/docs/Release-Notes.md index 396931d2..237fc8b3 100644 --- a/docs/Release-Notes.md +++ b/docs/Release-Notes.md @@ -125,7 +125,7 @@ initializes keys with `wc_CoseKey_Init()` and attaches keys through the messages using `ES256`, `ES384`, `ES512`, or `EdDSA` require `WOLFCOSE_ENABLE_DEPRECATED_ALGS`; changing a protected algorithm ID also requires re-signing the message. See - [[Algorithms#Migrating from RFC 9053 Signature IDs]]. + [Migrating from RFC 9053 Signature IDs](Algorithms.md#migrating-from-rfc-9053-signature-ids). - COSE-HPKE is experimental. Its wire format and API may change until the IETF specification is finalized. - `LIBWOLFCOSE_VERSION_STRING` is now `"2.0.0"` and @@ -151,12 +151,12 @@ MAC, and key distribution, and standardized post-quantum ML-DSA signatures or trailing input on decode. - All six COSE message types (RFC 9052): `COSE_Sign1`, `COSE_Sign`, `COSE_Encrypt0`, `COSE_Encrypt`, `COSE_Mac0`, and `COSE_Mac`, including the - multi-signer and multi-recipient variants. See [[Message Types]]. + multi-signer and multi-recipient variants. See [Message Types](Message-Types.md). - 40 algorithms across signing, encryption, MAC, and key distribution (RFC 9053): ES256/384/512, EdDSA (Ed25519/Ed448), PS256/384/512, ML-DSA-44/65/87, AES-GCM (128/192/256), ChaCha20-Poly1305, AES-CCM variants, HMAC-SHA256/384/512, AES-MAC, Direct, AES Key Wrap, and ECDH-ES+HKDF. See - [[Algorithms]]. + [Algorithms](Algorithms.md). - Standardized post-quantum signatures: ML-DSA (FIPS 204) at all three security levels, conformant to RFC 9964 ("ML-DSA for JOSE and COSE"). COSE keys use the RFC 9964 AKP key type (`kty` 7) with a required `alg`, the public key in `pub` @@ -173,7 +173,7 @@ MAC, and key distribution, and standardized post-quantum ML-DSA signatures against sign-disabled wolfCrypt (`NO_ECC_SIGN`, `NO_ASN`, no `mp_int`); the ECC signing helpers are gated out so a verify-only image never pulls in sign code, enforced in CI without `-ffunction-sections` garbage collection. See - [[Macros]]. + [Macros](Macros.md). - `LIBWOLFCOSE_VERSION_STRING` / `LIBWOLFCOSE_VERSION_HEX` in `wolfcose/version.h` for compile-time version checks. @@ -190,8 +190,8 @@ MAC, and key distribution, and standardized post-quantum ML-DSA signatures ### Improvements/Optimizations - Minimal footprint: an ES256 `COSE_Sign1` build is ~5.1 KB verify-only and - ~6.8 KB sign + verify for the wolfCOSE COSE + CBOR engine. See [[Footprint]]. -- MISRA C:2012 and C:2023 checked. See [[MISRA Compliance]]. + ~6.8 KB sign + verify for the wolfCOSE COSE + CBOR engine. See [Footprint](Footprint.md). +- MISRA C:2012 and C:2023 checked. See [MISRA Compliance](MISRA-Compliance.md). - API hardening: `COSE_Encrypt` and `wc_CoseMac_Create` direct mode now require an explicit `WOLFCOSE_ALG_DIRECT` and reject a zero-initialized algorithm id; `wc_CoseMac_Verify` classifies the recipient algorithm and enforces the algId @@ -208,7 +208,7 @@ MAC, and key distribution, and standardized post-quantum ML-DSA signatures `-fanalyzer`, Coverity), security scanning (CodeQL, Semgrep) and house-style gates, sanitizers (ASan/UBSan), a wolfCOSE <-> t_cose wire-interop conformance suite, and a wolfSSL version matrix with explicit ML-DSA/PQC rows. See - [[Testing]]. + [Testing](Testing.md). - Expanded negative and boundary coverage: 4 KB large-payload round-trips for `COSE_Encrypt0`/`COSE_Mac0`, empty-payload round-trips across AES-GCM/AES-CCM/ChaCha20-Poly1305, CBOR integer argument-width boundaries @@ -224,4 +224,4 @@ Assurance](https://www.wolfssl.com/about/wolfssl-software-development-process-qu page) and successfully passed the quality criteria. Requires wolfSSL 5.8.0 or later as the crypto backend; ML-DSA support requires -wolfSSL 5.9.2 or later. See [[Getting Started]] for build instructions. +wolfSSL 5.9.2 or later. See [Getting Started](Getting-Started.md) for build instructions. diff --git a/docs/Testing.md b/docs/Testing.md index 07030c61..096bab47 100644 --- a/docs/Testing.md +++ b/docs/Testing.md @@ -103,7 +103,7 @@ gate combinations. It also checks the 384, 521, and above-P-521 structural floors. `psa-eat-lean-verify` runs the RFC Sign1 and Mac0 vectors against a verify-only, full-`#tfm` receiver build. `psa-eat-demo` runs a complete issue, challenge verification, and software-component appraisal workflow. -See [[PSA-EAT]]. +See [PSA-EAT](PSA-EAT.md). ### Deprecated Algorithm ID Tests @@ -172,7 +172,7 @@ also covers missing, duplicate, wrong-type, wrong-length, and wrongly placed `ek`, prohibited `psk_id`, detached ciphertext, and cleared outputs on failed decrypts and encrypts. GitHub Actions runs the same coverage in -[Experimental COSE-HPKE](../.github/workflows/cose-hpke.yml). +[Experimental COSE-HPKE](https://github.com/wolfSSL/wolfCOSE/blob/main/.github/workflows/cose-hpke.yml). ### Comprehensive Algorithm Tests @@ -221,7 +221,7 @@ interoperability. t_cose verifies wolfCOSE's envelope bytes; wolfCOSE verifies the t_cose envelope and validates the RFC 9783 claims. t_cose and QCBOR are BSD-3-Clause and are not vendored; the -[Interop CI job](../.github/workflows/interop.yml) fetches them at pinned +[Interop CI job](https://github.com/wolfSSL/wolfCOSE/blob/main/.github/workflows/interop.yml) fetches them at pinned SHAs. See `tests/interop/t_cose/README.md` for the fixed test-key provenance. ### Complete upstream t_cose suite @@ -397,7 +397,7 @@ wolfCOSE is zero-heap (no `malloc`/`XMALLOC` on any path) and bounded-stack, bot - **Bounded stack**: built with `-fstack-usage`, then `scripts/check_stack_usage.sh` fails the build if any wolfCOSE frame exceeds 6144 bytes or is `dynamic` (unbounded); `-Werror=vla` bans VLAs/`alloca`. - **Zero heap**: sources, tests, tools, and examples are grepped for allocator calls. -- **`WOLFCOSE_MIN_BUFFERS`**: constrained-target profile that shrinks the caller working buffers (not the library frames) — see [[Macros]]. +- **`WOLFCOSE_MIN_BUFFERS`**: constrained-target profile that shrinks the caller working buffers (not the library frames) — see [Macros](Macros.md). - **Minimal Build matrix**: builds and tests against single-purpose minimal wolfCrypt configs (ECC-only, EdDSA-only, AEAD-only, MAC-only, …) plus a `WOLFCOSE_LEAN` core build. ### Lean and Post-Quantum Builds @@ -425,8 +425,6 @@ on-device build profiles: Nightly defect analysis via [Coverity Scan](https://scan.coverity.com/projects/wolfcose). -[![Coverity Scan Build Status](https://scan.coverity.com/projects/32918/badge.svg)](https://scan.coverity.com/projects/wolfcose) - --- ## Test File Structure @@ -472,6 +470,6 @@ Vector format is typically CBOR diagnostic notation or hex dumps with expected o ## See Also -- [[Getting Started]]: Build instructions -- [[Macros]]: Test configuration macros -- [[Project Structure]]: Source file layout +- [Getting Started](Getting-Started.md): Build instructions +- [Macros](Macros.md): Test configuration macros +- [Project Structure](Project-Structure.md): Source file layout diff --git a/docs/_Sidebar.md b/docs/_Sidebar.md deleted file mode 100644 index 6dc8afdd..00000000 --- a/docs/_Sidebar.md +++ /dev/null @@ -1,16 +0,0 @@ -### Documentation - -- [[Home]] -- [[Getting Started]] -- [[Message Types]] -- [[Algorithms]] -- [[API Reference]] -- [[Macros]] -- [[Experimental]] -- [[PSA-EAT]] -- [[Footprint]] -- [[Testing]] -- [[MISRA Compliance]] -- [[Project Structure]] -- [[STM32Cube]] -- [[Release Notes]] diff --git a/docs/assets/logo.png b/docs/assets/logo.png new file mode 100644 index 00000000..4f4db603 Binary files /dev/null and b/docs/assets/logo.png differ diff --git a/docs/assets/skin.css b/docs/assets/skin.css new file mode 100644 index 00000000..3ad8a7ef --- /dev/null +++ b/docs/assets/skin.css @@ -0,0 +1,25 @@ +/* Match the public wolfSSL manual colors without depending on its build repo. */ +.md-header { + background-color: #fff; + color: #1fbeca; +} + +.md-header__title, +.md-nav__link--active { + color: #1fbeca; +} + +.md-typeset a, +.md-nav__link { + color: #c46715; +} + +.md-typeset a:hover, +.md-nav__link:hover { + color: #1fbeca; +} + +.md-header__button.md-logo img { + height: 2.5rem; + width: auto; +} diff --git a/docs/dev/DOCS-BUILD.md b/docs/dev/DOCS-BUILD.md new file mode 100644 index 00000000..7d6041f7 --- /dev/null +++ b/docs/dev/DOCS-BUILD.md @@ -0,0 +1,68 @@ +# Building and publishing the wolfCOSE manual + +The top-level `docs/*.md` files are the manual source, one per page in +`mkdocs.yml`. The adapter in `tools/docs_manual.py` passes those pages to the +shared MkDocs theme and Pandoc/LaTeX PDF rules in +[`wolfSSL/documentation`](https://github.com/wolfSSL/documentation). Keep manual +content and its navigation in wolfCOSE; generated files stay under `build/`. + +Anything that is not a manual page goes under `docs/dev/`: maintainer notes +(like this file), drafts, scripts, or diagrams not referenced by a page. +`mkdocs.yml` (`exclude_docs`) and the adapter (`tools/docs_manual.py`) keep that +directory out of the published HTML and PDF. Never place a non-manual file +directly in `docs/`: the build requires every top-level `docs/*.md` to be a page +in `mkdocs.yml`, so a stray file there fails the build. + +## Local build + +Clone the documentation build tools at the revision used by wolfCOSE CI: + +```sh +git clone --recurse-submodules https://github.com/wolfSSL/documentation.git build/documentation +git -C build/documentation checkout "$(cat tools/docs-manual/documentation-rev)" +docker build --pull -t wolfcose-docs:local docker/docs +docker run --rm --user "$(id -u):$(id -g)" --env HOME=/tmp \ + --mount "type=bind,source=$PWD,target=/work/wolfCOSE" \ + --workdir /work/wolfCOSE wolfcose-docs:local \ + python3 tools/docs_manual.py build \ + --documentation-root /work/wolfCOSE/build/documentation \ + --source-root /work/wolfCOSE --target all +``` + +The outputs are `build/documentation/wolfCOSE/html/` and +`build/documentation/wolfCOSE/wolfCOSE-Manual.pdf`. The container includes +MkDocs, Pandoc, LaTeX, and the fonts used by the shared build rules. On a +wolfCOSE pull request, `docs-site.yml` checks out the pinned documentation +revision, builds both outputs, runs MkDocs in strict mode, and uploads them as +one artifact. It also runs after documentation changes merge to `main`. +CI pulls the versioned builder image from GHCR, or builds it from +`docker/docs/` if that image is unavailable. No host package installation or +website credentials are needed for this check. + +For an HTML preview, first run the build above, then run: + +```sh +docker run --rm --user "$(id -u):$(id -g)" --env HOME=/tmp -p 8000:8000 \ + --mount "type=bind,source=$PWD,target=/work/wolfCOSE" \ + --workdir /work/wolfCOSE/build/documentation/wolfCOSE \ + wolfcose-docs:local mkdocs serve -a 0.0.0.0:8000 -f mkdocs.yml +``` + +## Website update + +The one-time integration in `wolfSSL/documentation` adds a `wolfCOSE` manual +target beside wolfBoot and wolfHSM. It clones `wolfSSL/wolfCOSE` **main**, runs +the adapter from that checkout, and exports `wolfCOSE-html/` and +`wolfCOSE-Manual.pdf` through the documentation repository's existing Docker +build. Merge the wolfCOSE adapter before that integration so its source is +available on `main`. + +After both changes are merged, the existing nightly documentation build should +pick up `wolfcose` through the documentation repository's `all` target. No +manual trigger is needed for the normal update. Check the first nightly result +at `https://www.wolfssl.com/documentation/manuals/wolfcose/` and its +`wolfCOSE-Manual.pdf`. The website upload rules are outside these public +repositories; if the nightly publishes an explicit list of manuals instead of +all build output, that list will need a one-time addition. Subsequent merged +wolfCOSE documentation changes are read from wolfCOSE `main` on the next +nightly run. Pull requests only build review artifacts. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..bacd125e --- /dev/null +++ b/docs/index.md @@ -0,0 +1,84 @@ +# wolfCOSE + +wolfCOSE is a lightweight CBOR and COSE library for embedded systems. It implements: + +- **CBOR** (RFC 8949): Concise Binary Object Representation +- **COSE** (RFC 9052/9053): CBOR Object Signing and Encryption + +It uses [wolfSSL](https://www.wolfssl.com/) as the cryptographic backend and is designed for constrained IoT devices, FIPS-bounded deployments, and anywhere you need authenticated CBOR payloads in minimal RAM. + +## Standards + +**Core specifications** + +- [RFC 8949](https://www.rfc-editor.org/rfc/rfc8949): Concise Binary Object Representation (CBOR) +- [RFC 9052](https://www.rfc-editor.org/rfc/rfc9052): CBOR Object Signing and Encryption (COSE) structures +- [RFC 9053](https://www.rfc-editor.org/rfc/rfc9053): COSE initial algorithms +- [RFC 9864](https://www.rfc-editor.org/rfc/rfc9864): Fully-specified algorithms for JOSE and COSE +- [RFC 9338](https://www.rfc-editor.org/rfc/rfc9338): COSE countersignatures + +**Post-quantum cryptography** + +- [RFC 9964](https://www.rfc-editor.org/rfc/rfc9964): ML-DSA for COSE +- [RFC 8778](https://www.rfc-editor.org/rfc/rfc8778): HSS/LMS hash-based signatures for COSE + +**Attestation** + +- [RFC 9783](https://www.rfc-editor.org/rfc/rfc9783): PSA attestation token profile of EAT + +## Key Features + +| Feature | Description | +|---------|-------------| +| Complete RFC 9052 | All six COSE message types — Sign1, Sign, Encrypt0, Encrypt, Mac0, Mac | +| Multi-signer / multi-recipient | Full `COSE_Sign`, `COSE_Encrypt`, and `COSE_Mac` support | +| Post-quantum signing | ML-DSA (FIPS 204) at all three security levels — first COSE library to ship native PQC | +| PSA attestation | Optional RFC 9783 EAT / PSA token verifier and issuer, including Sign1, Mac0, legacy consumption, and PSA/HSM delegated signing | +| Zero dynamic allocation | Heap-allocation-free, non-recursive; caller-provided buffers within a bounded, target-customizable stack ceiling — zero `.data`/`.bss` | +| Tiny footprint | 3.5–5.1 KB COSE engine, 5.1–6.8 KB with the built-in CBOR engine (verify-only -> sign + verify); 26.2 KB -> 34.6 KB total with wolfCrypt — ES256 `COSE_Sign1`, dead-code-eliminated | +| 41 algorithms | Signing, encryption, MAC, and key distribution — classical and post-quantum | +| FIPS 140-3 path | Sole crypto dependency is wolfCrypt FIPS Certificate #4718 | +| CNSA 2.0 ready | ML-DSA-44/65/87 for quantum-resistant signatures | +| MISRA-C:2023 | compliance striving, Single-exit pattern, no recursion, deviation-logged | + +## Documentation + +| Page | Description | +|------|-------------| +| [Getting Started](Getting-Started.md) | Prerequisites, building, and quick start examples | +| [Message Types](Message-Types.md) | All six RFC 9052 messages (Sign1/Sign, Encrypt0/Encrypt, Mac0/Mac) with code samples | +| [Algorithms](Algorithms.md) | Complete list of supported algorithms with COSE IDs | +| [API Reference](API-Reference.md) | Full API documentation for all functions | +| [Macros](Macros.md) | Configuration macros and compile-time options | +| [Experimental](Experimental.md) | Draft feature status, supported scope, and graduation plan | +| [PSA and EAT](PSA-EAT.md) | RFC 9783 PSA attestation profiles, APIs, and integration guidance | +| [Footprint](Footprint.md) | Size and speed numbers, desktop and on-device | +| [Testing](Testing.md) | Unit tests, coverage, and failure injection | +| [MISRA Compliance](MISRA-Compliance.md) | MISRA C:2012 and C:2023 compliance status and deviation rationale | +| [Project Structure](Project-Structure.md) | Source code layout and file descriptions | +| [STM32Cube](STM32Cube.md) | Install and run wolfCOSE as an STM32Cube pack on device | +| [Release Notes](Release-Notes.md) | Per-version changelog and release highlights | + +## Supported Message Types + +wolfCOSE implements all six COSE message types from RFC 9052: + +| Message Type | Tag | Description | +|--------------|-----|-------------| +| COSE_Sign1 | 18 | Single signer digital signature | +| COSE_Sign | 98 | Multiple signers | +| COSE_Encrypt0 | 16 | Symmetric encryption (single key) | +| COSE_Encrypt | 96 | Multi-recipient encryption | +| COSE_Mac0 | 17 | Symmetric MAC (single key) | +| COSE_Mac | 97 | Multi-recipient MAC | + +## Quick Links + +- [GitHub Repository](https://github.com/wolfSSL/wolfCOSE) +- [wolfSSL Website](https://www.wolfssl.com/) + +See [Standards](#standards) above for the full list of implemented RFCs. + +## License + +wolfCOSE is free software licensed under GPLv3. For commercial licensing and support, contact [wolfSSL](https://www.wolfssl.com/contact/). diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 00000000..e84f3b44 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,63 @@ +site_name: wolfCOSE Manual +site_description: Lightweight CBOR and COSE library for embedded systems +site_url: https://www.wolfssl.com/documentation/manuals/wolfcose/ +repo_url: https://github.com/wolfSSL/wolfCOSE +edit_uri: edit/main/docs/ +docs_dir: docs +site_dir: build/docs-site +copyright: Copyright © 2026 wolfSSL Inc. +use_directory_urls: false + +# docs/dev/ holds maintainer notes (build process, etc.), not manual pages. +# Keep non-manual docs under docs/dev/ so they never enter the published manual. +exclude_docs: | + dev/ + +nav: + - Overview: + - wolfCOSE: index.md + - Get started: + - Getting Started: Getting-Started.md + - Message Types: Message-Types.md + - Algorithms: Algorithms.md + - Reference: + - API Reference: API-Reference.md + - Build Options: Macros.md + - Project Structure: Project-Structure.md + - Attestation: + - PSA and EAT: PSA-EAT.md + - Compliance and size: + - MISRA Compliance: MISRA-Compliance.md + - Footprint: Footprint.md + - Testing: Testing.md + - Platforms: + - STM32Cube: STM32Cube.md + - Status: + - Experimental: Experimental.md + - Release Notes: Release-Notes.md + +theme: + name: material + logo: assets/logo.png + favicon: assets/logo.png + features: + - navigation.sections + - navigation.top + - content.code.copy + palette: + primary: white + accent: deep orange + +extra_css: + - assets/skin.css + +markdown_extensions: + - tables + - admonition + - pymdownx.details + - pymdownx.superfences + - toc: + permalink: true + +plugins: + - search diff --git a/tools/check-docs-no-internal-links.sh b/tools/check-docs-no-internal-links.sh new file mode 100755 index 00000000..cdbeb0b1 --- /dev/null +++ b/tools/check-docs-no-internal-links.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +# Docs guard. docs/ is published as the manual, so the public tree must never +# point at an internal ledger or at a developer's home directory. +# +# tools/check-docs-no-internal-links.sh [path...] +# default paths: docs README.md +# tools/check-docs-no-internal-links.sh --selftest +set -u + +root="$(cd "$(dirname "$0")/.." && pwd)" +PATTERN='internal-docs|/Users/[A-Za-z]|/home/[A-Za-z]|~/[A-Za-z]' + +selftest() { + local dir fails=0 + dir="$(mktemp -d)" + printf 'See ~/wolfcose-internal-docs/task-list.md for the rows.\n' > "$dir/bad1.md" + printf 'Logs live in /home/aidangarske/wolfcose-work.\n' > "$dir/bad2.md" + printf 'Run `make test` first.\n' > "$dir/ok.md" + if grep -qE "$PATTERN" "$dir/ok.md"; then + echo "SELFTEST FAIL: clean doc flagged"; fails=$((fails + 1)); fi + if ! grep -qE "$PATTERN" "$dir/bad1.md"; then + echo "SELFTEST FAIL: internal ledger link missed"; fails=$((fails + 1)); fi + if ! grep -qE "$PATTERN" "$dir/bad2.md"; then + echo "SELFTEST FAIL: home directory path missed"; fails=$((fails + 1)); fi + rm -rf "$dir" + if [ "$fails" -ne 0 ]; then echo "SELFTEST: $fails failure(s)"; exit 1; fi + echo "SELFTEST: ok" + exit 0 +} + +[ "${1:-}" = "--selftest" ] && selftest + +cd "$root" || exit 2 +if [ $# -gt 0 ]; then paths=("$@"); else paths=(docs README.md); fi + +echo "docs guard: no internal-ledger or home-directory references in: ${paths[*]}" +hits="$(grep -rnE "$PATTERN" "${paths[@]}")" +rc=$? +if [ "$rc" -eq 1 ]; then + echo "OK: no internal references." + exit 0 +fi +if [ "$rc" -ne 0 ]; then + echo "FAIL: grep error $rc (missing path?)" + exit 2 +fi +printf '%s\n' "$hits" +echo "FAIL: $(printf '%s\n' "$hits" | wc -l | tr -d ' ') reference(s) to internal material in the public tree." +exit 1 diff --git a/tools/docs-manual/Makefile b/tools/docs-manual/Makefile new file mode 100644 index 00000000..18c2a39b --- /dev/null +++ b/tools/docs-manual/Makefile @@ -0,0 +1,15 @@ +.DEFAULT_GOAL := all +include ../common/common.am +include build/order.mk + +SRC := src +PDF := wolfCOSE-Manual.pdf + +.PHONY: all html-prep pdf-prep +all: pdf html + +html-prep: + @true + +pdf-prep: + python3 "$(WC_SOURCE)/tools/docs_manual.py" pdf-links --documentation-root .. diff --git a/tools/docs-manual/documentation-rev b/tools/docs-manual/documentation-rev new file mode 100644 index 00000000..66273b3c --- /dev/null +++ b/tools/docs-manual/documentation-rev @@ -0,0 +1 @@ +9455a759732a45c2ec1d408956105019ec9ced21 diff --git a/tools/docs_manual.py b/tools/docs_manual.py new file mode 100755 index 00000000..a64fd639 --- /dev/null +++ b/tools/docs_manual.py @@ -0,0 +1,181 @@ +#!/usr/bin/env python3 +"""Build the wolfCOSE manual with wolfSSL/documentation's shared tooling.""" + +import argparse +import json +import re +import shutil +import subprocess +from pathlib import Path + +import yaml +from markdown.extensions.toc import slugify + + +MANUAL = "wolfCOSE" +PDF = "wolfCOSE-Manual.pdf" +HEADING = re.compile(r"^(#{1,6})[ \t]+(.+?)[ \t]*#*[ \t]*$") +LINK = re.compile(r"\]\((?:([^)#]+\.md))?(?:#([^)]+))?\)") + + +def pages_from_nav(value): + if isinstance(value, str): + yield value + elif isinstance(value, list): + for item in value: + yield from pages_from_nav(item) + elif isinstance(value, dict): + for item in value.values(): + yield from pages_from_nav(item) + + +def page_key(filename): + return "wc-" + slugify(Path(filename).stem, "-") + + +def heading_slug(title): + title = re.sub(r"[`*]", "", title) + title = re.sub(r"\[([^]]+)\]\([^)]+\)", r"\1", title) + return slugify(title, "-") + + +def stage(documentation_root, source_root): + manual = documentation_root / MANUAL + source_docs = source_root / "docs" + shared = documentation_root / "common" / "common.am" + if not source_docs.is_dir() or not shared.is_file(): + raise RuntimeError("wolfCOSE docs or documentation/common.am is missing") + + config = yaml.safe_load((source_root / "mkdocs.yml").read_text()) + pages = list(pages_from_nav(config["nav"])) + if not pages or pages[0] != "index.md" or len(set(pages)) != len(pages): + raise RuntimeError("manual navigation must start at index.md and contain unique pages") + source_pages = {path.name for path in source_docs.glob("*.md")} + if set(pages) != source_pages: + raise RuntimeError( + f"manual navigation mismatch: missing={sorted(source_pages - set(pages))}, " + f"unknown={sorted(set(pages) - source_pages)}" + ) + + manual.mkdir(exist_ok=True) + for name in ("src", "build", "html"): + path = manual / name + if path.exists(): + shutil.rmtree(path) + shutil.copytree(source_docs, manual / "src", ignore=shutil.ignore_patterns("dev")) + shutil.copyfile(manual / "src" / "index.md", manual / "src" / "Home.md") + (manual / "build").mkdir() + ordered_sources = ["Home.md" if page == "index.md" else page for page in pages] + (manual / "build" / "order.mk").write_text( + "SOURCES := " + " ".join(ordered_sources) + "\nAPPENDIX :=\n" + ) + (manual / "build" / "order.json").write_text(json.dumps(pages) + "\n") + shutil.copyfile(source_root / "tools" / "docs-manual" / "Makefile", manual / "manual.generated.mk") + + config["docs_dir"] = "build/html" + config["site_dir"] = "html" + config["theme"] = { + "name": None, + "custom_dir": "../mkdocs-material/material", + "language": "en", + "palette": {"primary": "indigo", "accent": "indigo"}, + "font": {"text": "Roboto", "code": "Roboto Mono"}, + "icon": "logo.png", + "logo": "logo.png", + "favicon": "logo.png", + "feature": {"tabs": True}, + } + config["extra_css"] = ["skin.css"] + config["markdown_extensions"] = ["tables", "fenced_code", "toc"] + config["plugins"] = ["search"] + config["use_directory_urls"] = False + (manual / "mkdocs.yml").write_text(yaml.safe_dump(config, sort_keys=False)) + + header = (documentation_root / "wolfBoot" / "header.txt").read_text() + header = header.replace("wolfBoot Documentation", "wolfCOSE Manual") + header = re.sub(r"(\\copyright\s+)\d{4}", r"\g<1>2026", header) + (manual / "header.txt").write_text(header) + return manual + + +def prepare_pdf(documentation_root): + manual = documentation_root / MANUAL + pdf_dir = manual / "build" / "pdf" + pages = json.loads((manual / "build" / "order.json").read_text()) + headers = {} + for page in pages: + staged = pdf_dir / ("Home.md" if page == "index.md" else page) + found = set() + in_fence = False + for line in staged.read_text().splitlines(): + if line.lstrip().startswith(("```", "~~~")): + in_fence = not in_fence + if not in_fence: + match = HEADING.match(line) + if match: + found.add(heading_slug(match.group(2))) + headers[page] = found + + for page in pages: + staged = pdf_dir / ("Home.md" if page == "index.md" else page) + output = [f"[]{{#{page_key(page)}}}\n\n"] + in_fence = False + seen = set() + for line in staged.read_text().splitlines(keepends=True): + anchor = "" + if line.lstrip().startswith(("```", "~~~")): + in_fence = not in_fence + if not in_fence: + match = HEADING.match(line.rstrip("\n")) + if match: + slug = heading_slug(match.group(2)) + unique = slug + counter = 1 + while unique in seen: + counter += 1 + unique = f"{slug}-{counter}" + seen.add(unique) + anchor = f"[]{{#{page_key(page)}-{unique}}}\n\n" + + def rewrite(link): + md = link.group(1) + fragment = link.group(2) + if md is None and fragment is None: + return link.group(0) + target = page if md is None else Path(md).name + if target not in headers: + return link.group(0) + if fragment and fragment not in headers[target]: + raise RuntimeError(f"unresolved PDF link: {page} -> {target}#{fragment}") + anchor = page_key(target) + (f"-{fragment}" if fragment else "") + return f"](#{anchor})" + + line = LINK.sub(rewrite, line) + output.append(anchor + line) + staged.write_text("".join(output)) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("command", choices=("build", "pdf-links")) + parser.add_argument("--documentation-root", required=True, type=Path) + parser.add_argument("--source-root", type=Path) + parser.add_argument("--target", choices=("all", "html", "pdf"), default="all") + args = parser.parse_args() + documentation_root = args.documentation_root.resolve() + if args.command == "pdf-links": + prepare_pdf(documentation_root) + return + if args.source_root is None: + parser.error("build requires --source-root") + source_root = args.source_root.resolve() + manual = stage(documentation_root, source_root) + subprocess.run( + ["make", "-C", str(manual), "-f", "manual.generated.mk", args.target, + f"WC_SOURCE={source_root}"], + check=True, + ) + + +if __name__ == "__main__": + main()