Skip to content

Deutsch

Install with Yocto and RAUC

For manufacturers who build their own gateway image with Yocto and update it with RAUC. One agent goes into your image: the Bootstrap-Agent, one service that runs as its own unprivileged user. It leaves starting your software, the LEDs and any data deletion to you. An overview is on Gateway overview.

Release candidate

This page describes cproto-v0.2.0-rc.2, a release candidate. The recipe inside this release still pins the previous candidate (cproto-v0.2.0-rc.1): set RELEASE, PV and the two SHA-256 pins in it to this release, using the table below, before you build an image with it. The recipe in our layer already pins this release.

What you get

A signed release archive per version, three files: the archive bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz, its signature (.sig) and its checksum (.sha256). The archive holds:

Path in the archive What
bootstrap-agent the agent (armv7, linked dynamically)
systemd/bootstrap-agent.service the one service unit
examples/ the .path and .service examples from Start your software and confirm
tmpfiles/bootstrap-agent.conf creates the state directory and the socket directory
env/bootstrap-agent.env configuration default
local-api-v1.openapi.yaml, wire-v1.md the local interface contract and the platform contract
VERSION, CHECKSUMS.sha256 the version, and a checksum for every other file

The archive holds no installer script, and the agent downloads no program: it only fetches its configuration.

Download

The three files of the release cproto-v0.2.0-rc.2, no account needed:

https://packages.pxdc.io/bootstrap-agent/cproto-v0.2.0-rc.2/bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz
https://packages.pxdc.io/bootstrap-agent/cproto-v0.2.0-rc.2/bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz.sig
https://packages.pxdc.io/bootstrap-agent/cproto-v0.2.0-rc.2/bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz.sha256
File SHA-256
bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz fad9e36e7b3b412f198effcda621d55cab0c4963aa98c8d1f8ba332c8ee65700
bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz.sig ce2d4a9d8ea9a99c707ce93f4640a0274c0e44d3252bc6ba825f073b32b117a8
bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz.sha256 fc4a8295998ceb8030e6c7ebb1f7ae4deefc21f2427c2fcc4a997f9ba1db2b47

Check the signature

The signature is Ed25519, made with the agent's own release key. The key is stable: there are no per-release keys.

You need sha256sum and OpenSSL 3. Older versions do not know the option -rawin that the check uses: OpenSSL 1.1.1 and LibreSSL 3.3 stop with unknown option -rawin; OpenSSL 3.5 and 3.6 work.

1. Save the public key as wlpc-agent-ed25519.pub. It is also in our Yocto layer under the same name.

-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEAN8+mCK4/qSV4xO6uFNHrc5+8Dje5wK609NI7WEGqYa4=
-----END PUBLIC KEY-----

2. Compare the fingerprint with the one below, which is published on this site, not in the download directory, and with the one support sends you separately. A key fetched from the same place as the archive proves nothing by itself; the second source is what makes the check worth anything.

openssl pkey -pubin -in wlpc-agent-ed25519.pub -outform DER | sha256sum
# 79c12a4d7b4cc3868129a0afac587fd2441246e5c61382bd8221bc2ec52d402a

3. Check the three files you downloaded, in one directory:

sha256sum -c bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz.sha256
openssl pkeyutl -verify -pubin -rawin -inkey wlpc-agent-ed25519.pub \
  -sigfile bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz.sig \
  -in bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz

Signature Verified Successfully is the only good answer. A changed byte in the archive, or a signature made with another key, is refused. Then check the files inside against CHECKSUMS.sha256:

mkdir agent-files
tar -xzf bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz -C agent-files
(cd agent-files && sha256sum -c CHECKSUMS.sha256)

The Yocto recipe

The recipe bootstrap-agent-c_1.0.bb in our layer downloads the archive over HTTPS, refuses it unless its SHA-256 matches the one pinned in the recipe, checks the signature against the pinned key before unpacking, checks CHECKSUMS.sha256, and installs:

Path What
/usr/bin/bootstrap-agent the agent
/usr/lib/systemd/system/bootstrap-agent.service the one unit, enabled by a preset
/usr/lib/wlpc/bootstrap-agent.env configuration default
/usr/lib/tmpfiles.d/bootstrap-agent.conf creates the state directory and the socket directory

The recipe also creates the user bootstrap-agent and the groups tss and wlpc. It installs only that one unit, and not the examples. Your software writes /run/wlpc as a member of the group wlpc; the archive's tmpfiles rule creates that directory for the group, see Who may write /run/wlpc. Choosing a new version means changing the version and the two hashes in the recipe; nothing else changes unseen.

Libraries and known problems of the recipe

The agent is linked dynamically, so your image must provide these libraries, and the recipe lists them as dependencies: libtss2-esys.so.0, libtss2-mu.so.0, libcurl.so.4, libssl.so.3, libcrypto.so.3, libjson-c.so.5 and glibc (the highest symbol version the binary needs is GLIBC_2.34).

What was and was not verified for the recipe:

  • Verified: download, hash pin, signature check and do_install from an empty build directory, against the recipe on the development branch, with the build dependencies removed.
  • Open problem 1, the work directory. In a full test build (Yocto scarthgap, qemuarm), the recipe stopped in do_package: S set to ${WORKDIR}/pkg also hides ${WORKDIR}/pkgdata from the tool that tracks file ownership. A test copy with another directory name got past it. The recipe is not changed yet.
  • Open problem 2, a version tag of the curl library. After that, the package check (file-rdeps) reported that the program needs libcurl.so.4(CURL_OPENSSL_4) and no package provides it: the program was linked against a curl library with versioned symbols, the one built by Yocto has none. Not solved; whether the program runs against that library was not measured.
  • Not done: no image build (do_rootfs) and no start on a Yocto image.

Updates with RAUC

The agent writes only /etc/iot-config (its state) and /run/bootstrap-agent; everything else can be read-only. The unit says RequiresMountsFor=/etc/iot-config, so the agent starts after that mount. The state must survive reboots and RAUC slot switches:

  • If /etc lies on the data partition, nothing more is needed.
  • If /etc on your image is part of the root file system, bind-mount /etc/iot-config from the data partition. systemd only accepts the mount unit under the name derived from the path, etc-iot\x2dconfig.mount (systemd-escape -p --suffix=mount /etc/iot-config); under any other name it ignores the unit and the state stays in the slot.
  • A state directory inside the slot is empty after the switch, and the device provisions itself again.

This agent has not been run through a RAUC A/B switch or a rollback. Test it on your image.

Settings

The platform address goes into /etc/bootstrap-agent/agent.env, never into the image, so the same image works with your own platform instance. The unit reads the defaults from /usr/lib/wlpc/bootstrap-agent.env first and this file second.

BOOTSTRAP_AGENT_URL=https://bootstrap.ztd.dev.pxdc.io
BOOTSTRAP_AGENT_TRUST_BUNDLE=
Setting Required Meaning
BOOTSTRAP_AGENT_URL Required The platform's address for gateways. Without it the agent starts and serves its local interface, but reports state: error.
BOOTSTRAP_AGENT_TRUST_BUNDLE Optional Empty: check the platform's certificate against the image's list of trusted authorities. The shipped default points to /etc/bootstrap-agent/platform-ca.pem; if that file does not exist, the agent logs reading trust bundle and cannot reach the platform. Only use a file if support gave you one.
BOOTSTRAP_AGENT_NTP_SERVERS Optional Time servers, comma separated. The agent waits for the clock to agree with one of them before it opens any TLS connection. Empty: it only rejects an obviously unset clock.
BOOTSTRAP_AGENT_AK_HANDLE Optional The TPM handle of the attestation key, see The TPM.

The TPM

The agent keeps its attestation key (AK) as one persistent object in the TPM, so a start reads the key instead of deriving it again.

  • One handle, set by you. BOOTSTRAP_AGENT_AK_HANDLE in /etc/bootstrap-agent/agent.env: a persistent handle in the TPM's owner range. Empty uses the default handle, which we agree with you. off keeps the key transient.
  • Only that handle, only while it is empty. The first start makes the key persistent there with one TPM2_EvictControl call and records its TPM name in /etc/iot-config/ak. If the handle holds anything else, the agent leaves it untouched and works with a transient key.
  • Owner authorization. With an owner hierarchy authorization set, the agent persists nothing.
  • Factory reset. Before your reset wipes the data partition, stop the agent and run bootstrap-agent --release-ak. It evicts the agent's key, and only if the object at the recorded handle carries the recorded name.
  • Cleaning at start. At start the agent removes its own leftover key objects (the shape of an endorsement or attestation key) that it can see through /dev/tpmrm0. It does not remove anything else and does not touch the raw device /dev/tpm0, see TPM slots.

What is yours

Starting and supervising your gateway software, the LEDs, and deleting data (a factory reset) belong to your image. The agent does none of it; for its key in the TPM, your reset runs bootstrap-agent --release-ak first (above). How your software starts and confirms its target: Start your software and confirm. How it reads its configuration: Local API reference.