Skip to content

Add nat20 integration test suite for linux examples#105

Open
werwurm wants to merge 66 commits into
mainfrom
werwurm/linux_example_integration_test
Open

Add nat20 integration test suite for linux examples#105
werwurm wants to merge 66 commits into
mainfrom
werwurm/linux_example_integration_test

Conversation

@werwurm
Copy link
Copy Markdown
Contributor

@werwurm werwurm commented May 14, 2026

Adds a C integration test binary (nat20_integration_test) that exercises
the full DICE service stack via /dev/nat200. The test generates certificate
chains across all supported key type (P-256, P-384) and format (X.509,
COSE) permutations, verifies cryptographic signatures at each link, and
confirms that parent_path-based issuance produces identical results to
direct issuance after promote.

Test structure:

  • Phase 1 (level 1): Generate CDI1, CDI2, ECA, ECA_EE certs and
    signatures using parent paths of varying depth from the UDS level.
    Verify all X.509 and COSE chains cryptographically.
  • Phase 2 (level 2): After one promote, regenerate CDI2/ECA/ECA_EE/sign
    with reduced parent path depth and assert byte-for-byte equality.
  • Phase 3 (level 3): After second promote, regenerate ECA/ECA_EE/sign
    with no parent path and assert equality.

Also includes:

  • test_helpers.c: OpenSSL-based X.509 signature verification, public key
    extraction, COSE_Sign1 parsing and verification, CWT subject public
    key extraction, and compressed input computation.
  • nat20_qemu_init.sh: init wrapper for running tests in QEMU CI.
  • GitHub Action steps to build the rootfs and run the test suite in QEMU.
  • Buildroot package (nat20test) with OpenSSL dependency.

werwurm added 30 commits April 29, 2026 09:34
Add a kernel module that provides libnat20 functionality to linux kernel
modules. Also add a configuration to build a minimal linux image with
buildroot and run in on qemu and a workflow to test build nat20lib.ko
This module creates a new character device class intended to implement
the nat20 service protocol implementing DICE based device state
attestation and an embedded CA.
The nat20crypto module implements the libnat20 crypto interface
in terms of linux kernel crypto primitives.
The module implements
- deterministic ECDSA with curves P256 and P384.
- Bytewise SHA-2 224/256/384/512
- HMAC
- HKDF

ED25519 is currently not supported.
@werwurm werwurm force-pushed the werwurm/linux_example_integration_test branch from 783f03c to eaf904a Compare May 14, 2026 23:18
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 14, 2026

LCOV of commit a194dff during lcov-test-coverage-report #233

Summary coverage rate:
  lines......: 95.6% (3048 of 3188 lines)
  functions..: 99.1% (232 of 234 functions)
  branches...: 87.1% (1658 of 1904 branches)

Files changed coverage rate: n/a

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a Buildroot-packaged Linux/QEMU integration test suite for the nat20 service stack, including a new C test binary that exercises /dev/nat200, certificate issuance, signatures, parent paths, and promote behavior.

Changes:

  • Adds nat20_integration_test plus OpenSSL/libnat20-based verification helpers.
  • Adds QEMU/rootfs test launch scripts and Buildroot package wiring.
  • Extends CI to build the rootfs and run the integration test in QEMU.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 16 comments.

Show a summary per file
File Description
examples/linux/nat20test/test/test_helpers.h Declares helper APIs for test cryptographic verification and parsing.
examples/linux/nat20test/test/test_helpers.c Implements OpenSSL, CBOR, COSE, and compression helpers.
examples/linux/nat20test/test/nat20_integration_test.c Adds the main nat20 service integration test suite.
examples/linux/nat20test/nat20test.sh Adds the test runner script for loading the module and launching the binary.
examples/linux/nat20test/nat20_qemu_init.sh Adds the QEMU init wrapper for running tests and emitting result markers.
examples/linux/nat20test/CMakeLists.txt Builds and installs the integration test binary and scripts.
examples/linux/br_external/utils/envsetup.sh Adds nat20test override and rebuild support.
examples/linux/br_external/package/nat20test/nat20test.mk Adds the Buildroot package definition for nat20test.
examples/linux/br_external/package/nat20test/Config.in Adds the Buildroot config option for nat20test.
examples/linux/br_external/package/nat20cli/nat20cli.mk Documents nat20cli override-source behavior.
examples/linux/br_external/configs/qemu_br_defconfig Enables nat20test in the QEMU Buildroot config.
examples/linux/br_external/Config.in Sources the new nat20test Buildroot config.
.github/workflows/linux-kmod-build.yml Adds rootfs build and QEMU integration-test execution steps.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread examples/linux/br_external/package/nat20test/Config.in Outdated
Comment thread examples/linux/br_external/package/nat20test/Config.in
Comment thread examples/linux/br_external/package/nat20test/Config.in Outdated
Comment thread examples/linux/br_external/package/nat20test/nat20test.mk
Comment thread examples/linux/nat20test/nat20_qemu_init.sh Outdated
Comment thread examples/linux/nat20test/test/nat20_integration_test.c Outdated
Comment thread examples/linux/nat20test/test/nat20_integration_test.c Outdated
Comment thread examples/linux/nat20test/test/nat20_integration_test.c
Comment thread .github/workflows/linux-kmod-build.yml Outdated
Comment thread examples/linux/nat20test/test/test_helpers.h
  Adds a C integration test binary (nat20_integration_test) that exercises
  the full DICE service stack via /dev/nat200. The test generates certificate
  chains across all supported key type (P-256, P-384) and format (X.509,
  COSE) permutations, verifies cryptographic signatures at each link, and
  confirms that parent_path-based issuance produces identical results to
  direct issuance after promote.

  Test structure:
  - Phase 1 (level 1): Generate CDI1, CDI2, ECA, ECA_EE certs and
    signatures using parent paths of varying depth from the UDS level.
    Verify all X.509 and COSE chains cryptographically.
  - Phase 2 (level 2): After one promote, regenerate CDI2/ECA/ECA_EE/sign
    with reduced parent path depth and assert byte-for-byte equality.
  - Phase 3 (level 3): After second promote, regenerate ECA/ECA_EE/sign
    with no parent path and assert equality.

  Also includes:
  - test_helpers.c: OpenSSL-based X.509 signature verification, public key
    extraction, COSE_Sign1 parsing and verification, CWT subject public
    key extraction, and compressed input computation.
  - nat20_qemu_init.sh: init wrapper for running tests in QEMU CI.
  - GitHub Action steps to build the rootfs and run the test suite in QEMU.
  - Buildroot package (nat20test) with OpenSSL dependency.
@werwurm werwurm force-pushed the werwurm/linux_example_integration_test branch from eaf904a to 47500a2 Compare May 14, 2026 23:45
werwurm and others added 2 commits May 14, 2026 16:50
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@werwurm werwurm requested review from seidelrj and smacdude May 15, 2026 15:33
@werwurm werwurm marked this pull request as ready for review May 15, 2026 15:44
@werwurm werwurm requested a review from a team as a code owner May 15, 2026 15:44
@werwurm werwurm changed the base branch from werwurm/linux_example_nat20cli to werwurm/linux_example_libnat20 May 15, 2026 15:52
Comment on lines +157 to +190
- name: Build rootfs image
env:
NAT20LIB_OVERRIDE_SRCDIR: ${{ github.workspace }}
NAT20DEVICE_OVERRIDE_SRCDIR: ${{ github.workspace }}
NAT20CRYPTO_OVERRIDE_SRCDIR: ${{ github.workspace }}
NAT20SW_OVERRIDE_SRCDIR: ${{ github.workspace }}
LIBNAT20_OVERRIDE_SRCDIR: ${{ github.workspace }}
NAT20TEST_OVERRIDE_SRCDIR: ${{ github.workspace }}
run: make -C ${{ runner.temp }}/buildroot.build/buildroot -j $(( $(nproc) + 1 ))

- name: Run integration tests in QEMU
timeout-minutes: 5
run: |
BUILDROOT_DIR="${{ runner.temp }}/buildroot.build/buildroot"
KERNEL="${BUILDROOT_DIR}/output/images/bzImage"
ROOTFS="${BUILDROOT_DIR}/output/images/rootfs.ext2"

qemu-system-x86_64 \
-M pc \
-kernel "${KERNEL}" \
-drive file="${ROOTFS}",if=virtio,format=raw \
-append "rootwait root=/dev/vda console=ttyS0 init=/usr/bin/nat20test_qemu_init.sh" \
-nographic \
-no-reboot \
-net none \
2>&1 | tee qemu_output.log

if grep -q "INTEGRATION_TESTS_PASSED" qemu_output.log; then
echo "Integration tests passed."
else
echo "Integration tests failed. QEMU output:"
cat qemu_output.log
exit 1
fi
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes are also present in #104. Based on the PR title, I think they should be here.. can you please separate them out so it's more clear?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are correct, however, this PR is correct, so you should have approved this one and not #104.

Ultimately, both are correct in this respect, I just forgot to change the base on #104 which is supposed to land after this one. I corrected this now.

@werwurm werwurm changed the base branch from werwurm/linux_example_libnat20 to main May 18, 2026 15:09
@werwurm werwurm requested a review from timhirsh May 18, 2026 15:10
uint8_t* compressed_out,
size_t compressed_out_size) {
n20_crypto_digest_context_t* digest_ctx = NULL;
n20_error_t err = n20_crypto_nat20_open(&digest_ctx);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically re-iterating what copilot said below. We don't close this in the success path or in any of the error paths.

/* CDI1: subject_key_type × format, issuer = P-256, no parent path */
for (size_t si = 0; si < NUM_KEY_TYPES; si++) {
for (size_t fi = 0; fi < NUM_CDI_FORMATS; fi++) {
level1_artifacts.cdi1_valid[si][fi] = issue_cdi_cert(n20_crypto_key_type_secp256r1_e,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the code below it looks like we are OK with some of these failing and other succeeding, but it's hard to derive the actual expectations just by looking at the code. It could be that the expectations will vary across devices/implementations, but this integration test is already pretty tightly coupled to the reference implementation.

Obviously Copilots suggestion of expecting them all to succeed is wrong, do it would be nice if we could at least validate that the expectations are met.

The same comment applies to cdi2_valid, eca_valid, eca_ee_valid, and signature valid.

for (size_t fi = 0; fi < NUM_CDI_FORMATS; fi++) {
cert_buffer_t cert;
bool ok =
issue_cdi_cert(KEY_TYPES[ii], KEY_TYPES[si], CDI_FORMATS[fi], no_path, &cert);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So each of these cases are expected to pass? Aren't these the same calls as were made in the level 1 test? Or does the promotion change their behavior from level1?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants