Skip to content
Open
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -784,7 +784,7 @@ This repository contains additional README files with detailed information:
- [recipes-connectivity/README.md](recipes-connectivity/README.md) - BIND,
OpenSSH, Socat
- [recipes-support/README.md](recipes-support/README.md) - curl, libssh2,
strongSwan, tcpdump
strongSwan, tcpdump, libfcs (Altera Agilex 5 SDM)
- [recipes-protocols/README.md](recipes-protocols/README.md) - net-snmp
- [recipes-extended/README.md](recipes-extended/README.md) - rsyslog

Expand Down
9 changes: 9 additions & 0 deletions conf/layer.conf
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ BBFILES += "${LAYERDIR}/recipes-wolfssl/wolfssl/*.bb \
# xilinx-bootbin bbappend requires meta-xilinx-tools layer
BBFILES_DYNAMIC += "xilinx-tools:${LAYERDIR}/recipes-bsp/bootbin/*.bbappend"

# Enable with WOLFSSL_ALTERA_FCS = "1" in the build configuration.
WOLFSSL_ALTERA_FCS ?= "0"
WOLFSSL_FCS_PROVIDER ?= "libfcs"
WOLFSSL_ALTERA_FCS_BBFILES = \
"${LAYERDIR}/recipes-support/libfcs/libfcs_git.bb \
${LAYERDIR}/recipes-support/libfcs/wolfssl_%.bbappend \
${@'${LAYERDIR}/recipes-support/libfcs/gsrd-intel-fcs-lib_%.bbappend' if d.getVar('WOLFSSL_FCS_PROVIDER') == 'gsrd-intel-fcs-lib' else ''}"
BBFILES += "${@d.getVar('WOLFSSL_ALTERA_FCS_BBFILES') if d.getVar('WOLFSSL_ALTERA_FCS') == '1' else ''}"

# Uncomment if building bind with wolfSSL.
#BBFILES += "${LAYERDIR}/recipes-connectivity/bind/*.bbappend"

Expand Down
6 changes: 6 additions & 0 deletions recipes-support/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,9 @@ Zeus, Dunfell, and Gatesgarth

Then just compile the image that use's `tcpdumb` and include the `wolfSSL`
package or preform `bitbake tcpdumb`

libfcs (Altera Agilex 5 SDM crypto)
-----

See [libfcs/agilex5/README.md](libfcs/agilex5/README.md) for the complete
Agilex 5 integration, image deployment, and on-target test procedure.
279 changes: 279 additions & 0 deletions recipes-support/libfcs/agilex5/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
# wolfSSL FCS offload on Altera Agilex 5

This guide builds wolfSSL with Secure Device Manager crypto offload, includes
the result in an Agilex 5 Linux image, deploys that image, and verifies the
packaged wolfCrypt test on the board.

## Prerequisites

- An Agilex 5 GSRD Yocto build configured for the exact board and release.
- This `meta-wolfssl` layer in `BBLAYERS`.
- A kernel exposing `/sys/kernel/fcs_sysfs`.
- An owner root key hash provisioned in the SDM.

Provisioning is outside this layer's scope. Follow Altera's device-security
procedure and distinguish recoverable virtual-key programming from permanent
eFuse programming before changing a board. A virtual owner key is cleared when
the board loses power and must be reapplied before each cold-boot test. Once an
owner key is active, boot and FPGA configuration artifacts must be signed by
that owner.

Run BitBake on a Linux build server with the memory and storage required by the
GSRD release. Do not run BitBake on the target board.

The 26.1 GSRD source and board-specific build instructions are published in
Altera's
[DK-A5E013BM16AEA GSRD guide](https://altera-fpga.github.io/rel-26.1/embedded-designs/agilex-5/e-series/013B/gsrd/ug-gsrd-agx5e-013b/).
Install `python3-venv` and Kas as described there. If the build server cannot
install Python packages, the official Kas container is an alternative:

```sh
docker pull ghcr.io/siemens/kas/kas:4.8
```

The 26.1 GSRD kernel append uses Bash conditionals in a BitBake task that runs
under `/bin/sh`. Make those conditionals portable before building:

```sh
sed -i \
-e 's/if \[\[/if [/g' \
-e 's/\]\]; then/]; then/g' \
-e 's/" == "/" = "/g' \
meta-altera-fpga/meta-altera-bsp/recipes-kernel/linux/\
linux-socfpga-lts_%.bbappend
```

Without this correction, `linux-socfpga-lts:do_deploy` reports `[[: not
found` and selects a nonexistent `fit_agilex5_kernel_no_rbf.its` file.

## Add the layer to an Agilex 5 GSRD build

The 26.1 GSRD for the DK-A5E013BM16AEA uses Kas. Add `meta-wolfssl` to the
GSRD `kas.yml` or to a Kas configuration fragment:

```yaml
header:
version: 17

repos:
meta-wolfssl:
url: https://github.com/wolfSSL/meta-wolfssl.git
branch: master
layers:
.:

local_conf_header:
wolfssl-altera-fcs: |
WOLFSSL_ALTERA_FCS = "1"
WOLFSSL_FCS_PROVIDER = "gsrd-intel-fcs-lib"
IMAGE_INSTALL:append = " wolfssl wolfcrypttest wolfcryptbenchmark "
```

Save the fragment as `wolfssl-fcs.yml`. Kas configurations can be combined
without changing the GSRD's supplied `kas.yml`.

For a local `meta-wolfssl` checkout under the GSRD Yocto directory, replace the
repository URL and branch with:

```yaml
meta-wolfssl:
path: meta-wolfssl
layers:
.:
```

The 26.1 GSRD already provides the required headers and versioned runtime
library through `gsrd-intel-fcs-lib`. This layer adds the unversioned
`libFCS.so` linker name required by dependent recipes. Selecting the GSRD
provider prevents two recipes from installing the same library. A non-GSRD
build can omit the override and use meta-wolfssl's `libfcs` recipe instead.

```bitbake
WOLFSSL_FCS_PROVIDER = "gsrd-intel-fcs-lib"
```

Use only one provider for `libFCS.so`.

## Build the Agilex 5 image

From the 26.1 DK-A5E013BM16AEA GSRD `software/yocto_linux` directory, build the
same `gsrd-console-image` target documented by Altera:

```sh
source venv/bin/activate
kas build kas.yml:wolfssl-fcs.yml gsrd-console-image
```

With the Kas container, run the equivalent command from the same directory:

```sh
docker run --rm --user "$(id -u):$(id -g)" \
-e HOME=/work -v "$PWD:/work" -w /work \
ghcr.io/siemens/kas/kas:4.8 \
build kas.yml:wolfssl-fcs.yml gsrd-console-image
```

The expected SD card image is:

```text
build/tmp/deploy/images/agilex5e_013b/gsrd-console-image-agilex5e_013b.rootfs.wic
```

Fail the validation if that file is absent or empty:

```sh
test -s build/tmp/deploy/images/agilex5e_013b/\
gsrd-console-image-agilex5e_013b.rootfs.wic
sha256sum build/tmp/deploy/images/agilex5e_013b/\
gsrd-console-image-agilex5e_013b.rootfs.wic
```

Inspect the partition table and the installed test from an initialized
OpenEmbedded shell:

```sh
(
source poky/oe-init-build-env build
image=tmp/deploy/images/agilex5e_013b/\
gsrd-console-image-agilex5e_013b.rootfs.wic
native="$(find "$PWD/tmp/work" -type d \
-path '*/gsrd-console-image/*/recipe-sysroot-native' \
-print -quit)"
test -n "$native"
wic ls -n "$native" "$image"
wolfcrypt_bins="$(wic ls -n "$native" "$image:2/usr/bin/")"
printf '%s\n' "$wolfcrypt_bins"
printf '%s\n' "$wolfcrypt_bins" | grep -q 'wolfcrypttest'
printf '%s\n' "$wolfcrypt_bins" | grep -q 'wolfcryptbenchmark'
oe-pkgdata-util find-path /usr/bin/wolfcrypttest
)
```

When the image was built with the Kas container, run the same checks through
`kas shell` so Yocto's native tools retain the `/work` path used at build time:

```sh
docker run --rm --user "$(id -u):$(id -g)" \
-e HOME=/work -v "$PWD:/work" -w /work \
ghcr.io/siemens/kas/kas:4.8 \
shell kas.yml:wolfssl-fcs.yml -c '
image=tmp/deploy/images/agilex5e_013b/\
gsrd-console-image-agilex5e_013b.rootfs.wic
native="$(find "$PWD/tmp/work" -type d \
-path "*/gsrd-console-image/*/recipe-sysroot-native" \
-print -quit)"
test -n "$native"
wic ls -n "$native" "$image"
wolfcrypt_bins="$(wic ls -n "$native" "$image:2/usr/bin/")"
printf "%s\n" "$wolfcrypt_bins"
printf "%s\n" "$wolfcrypt_bins" | grep -q wolfcrypttest
printf "%s\n" "$wolfcrypt_bins" | grep -q wolfcryptbenchmark
oe-pkgdata-util find-path /usr/bin/wolfcrypttest
'
```

The image must contain a FAT boot partition and an ext4 root partition. The
second `wic ls` command must show both `wolfcrypttest` and
`wolfcryptbenchmark`, and the package lookup must report `wolfssl`.

Confirm that BitBake also staged the packaged test:

```sh
test -n "$(find build/tmp/work \
-path '*/wolfssl/*/packages-split/*/usr/bin/wolfcrypttest' \
-print -quit)"
```

## Deploy the image

Power off the board and remove its microSD card. Attach the card to the build
server, identify the whole device by its capacity, and unmount any mounted
partitions. Device names vary: USB readers commonly appear as `/dev/sdX`, while
built-in readers may appear as `/dev/mmcblkN`. The example below uses the
device observed on the build server; replace it only after checking `lsblk`:

```sh
image=build/tmp/deploy/images/agilex5e_013b/\
gsrd-console-image-agilex5e_013b.rootfs.wic
card=/dev/mmcblk0

lsblk -o NAME,SIZE,TYPE,TRAN,RM,MODEL,MOUNTPOINTS
test -b "$card"
for part in $(lsblk -lnpo NAME "$card" | tail -n +2); do
if findmnt -rn -S "$part" >/dev/null; then
sudo umount "$part"
fi
done

sudo dd if="$image" of="$card" bs=4M status=progress conv=fsync
image_size=$(stat -Lc %s "$image")
sudo cmp -n "$image_size" "$image" "$card" && echo "WIC verified"
sync
sudo blockdev --flushbufs "$card"
```

Verify the destination with `lsblk` before writing. This operation replaces the
card contents. Do not use a disk containing the build server's root filesystem.
Use a spare card or make a full-device backup first if the existing image must
be recoverable. `cmp` is silent on success; do not remove the card unless it
returns zero and prints `WIC verified`. A built-in MMC reader may not implement
the `eject` command. Once the partitions are unmounted and `blockdev` has
flushed the device, it is safe to remove the card physically.

If the target image enables a package manager and a compatible package feed,
an incremental update is also valid:

```sh
bitbake wolfssl wolfcrypttest
bitbake package-index
```

Publish the generated package feed, refresh the target package index, and
install or upgrade `wolfssl` and `wolfcrypttest` with the target's package
manager. Do not copy a package from a different machine, tune, C library, or
Yocto release.

## Verify on the board

Boot the deployed image and confirm that its packaged files are present:

```sh
test -x /usr/bin/wolfcrypttest
/lib/ld-linux-aarch64.so.1 --list /usr/bin/wolfcrypttest
test -e /sys/kernel/fcs_sysfs
```

The DHCP address can change after booting a replacement image. Use the serial
console, the DHCP server's leases, or a local subnet scan to find the target
rather than assuming its previous address is retained.

The GSRD image does not install `ldd` by default. Invoking the AArch64 dynamic
loader with `--list` performs the same runtime dependency check without adding
a diagnostic package to the image.

Run the installed test:

```sh
/usr/bin/wolfcrypttest
```

The run must exit with status 0 and print:

```text
ALTERA-FCS test passed!
```

The Altera subtests require successful hardware operations for RNG, SHA-256,
and AES. They cannot pass solely through wolfSSL software fallback. Device
resident ECDSA and ECDH keys and HMAC verification are also exercised.

If only the Altera test fails, check SDM provisioning status `0x85`. Status
`0x84` indicates session exhaustion and requires a board power cycle.

## Developer-only smoke test

Copying `${B}/wolfcrypt/test/.libs/testwolfcrypt` directly to a running target
is useful while developing the recipe. It is not the final integration test
because it bypasses image construction, package installation, and runtime
dependency resolution. Use the packaged `/usr/bin/wolfcrypttest` flow above
for release validation.
13 changes: 13 additions & 0 deletions recipes-support/libfcs/gsrd-intel-fcs-lib_%.bbappend
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# The Agilex 5 GSRD recipe installs only the versioned runtime library. Add the
# development linker name so dependent recipes can use -lFCS from their
# recipe-specific sysroots.
do_install:append() {
if [ -e ${D}${prefix}/lib/libFCS.so.3 ]; then
install -d ${D}${libdir}
if [ "${libdir}" = "${prefix}/lib" ]; then
ln -sfn libFCS.so.3 ${D}${libdir}/libFCS.so
else
ln -sfn ../lib/libFCS.so.3 ${D}${libdir}/libFCS.so
fi
fi
}
48 changes: 48 additions & 0 deletions recipes-support/libfcs/libfcs_git.bb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
SUMMARY = "Altera FPGA Crypto Services library"
DESCRIPTION = "Userspace library for the FPGA Crypto Services of Altera \
SoCFPGA devices, exposing the Secure Device Manager crypto mailbox through \
/sys/kernel/fcs_sysfs."
HOMEPAGE = "https://github.com/altera-fpga/libfcs"
LICENSE = "MIT-0"
LIC_FILES_CHKSUM = "file://LICENSE;md5=6f25b4c3a6d23285f956387ab54830ad"

SRC_URI = "git://github.com/altera-fpga/libfcs.git;protocol=https;branch=main"
SRCREV = "87b4b726f4981be102fc8f09feab051fe3578334"
PV = "3.01+git"

DEPENDS = "dtc"

COMPATIBLE_HOST = "aarch64.*-linux"

python () {
if d.getVar('UNPACKDIR', False):
d.setVar('S', '${UNPACKDIR}/${BP}')
else:
d.setVar('S', '${WORKDIR}/git')
}

inherit cmake

EXTRA_OECMAKE = "-DARCH=linux_aarch64"

# upstream install() destinations are relative, so they nest under ${prefix}
wolfssl_fcs_fixup_install() {
if [ -d ${D}${prefix}${prefix} ]; then
cp -a ${D}${prefix}${prefix}/. ${D}${prefix}/
rm -rf ${D}${prefix}${prefix}
fi

# libfcs hardcodes /usr/lib. Move the library to Yocto's configured libdir,
# then supply the linker name expected by consumers such as wolfSSL.
if [ "${prefix}/lib" != "${libdir}" ] && \
[ -e ${D}${prefix}/lib/libFCS.so.3 ]; then
install -d ${D}${libdir}
mv ${D}${prefix}/lib/libFCS.so.3 ${D}${libdir}/
rmdir ${D}${prefix}/lib
fi
if [ -e ${D}${libdir}/libFCS.so.3 ]; then
ln -sfn libFCS.so.3 ${D}${libdir}/libFCS.so
fi
}

do_install[postfuncs] += "wolfssl_fcs_fixup_install"
20 changes: 20 additions & 0 deletions recipes-support/libfcs/wolfssl_%.bbappend
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Altera Agilex 5 SDM crypto offload; needs an FCS provisioned device at
# runtime. GSRD stacks that already build the library can point this at
# their own recipe, e.g. WOLFSSL_FCS_PROVIDER = "gsrd-intel-fcs-lib".

def wolfssl_fcs_is_target(d):
return (d.getVar('CLASSOVERRIDE') == 'class-target' and
(d.getVar('HOST_SYS') or '').startswith('aarch64-'))

WOLFSSL_FCS_CONFIGURE = "${@'--enable-alterafcs --enable-aesctr' if wolfssl_fcs_is_target(d) else ''}"
WOLFSSL_FCS_DEPENDS = "${@d.getVar('WOLFSSL_FCS_PROVIDER') if wolfssl_fcs_is_target(d) else ''}"

EXTRA_OECONF += "${WOLFSSL_FCS_CONFIGURE}"
DEPENDS += "${WOLFSSL_FCS_DEPENDS}"

python () {
if (d.getVar('CLASSOVERRIDE') == 'class-target' and
not d.getVar('MLPREFIX') and
not (d.getVar('HOST_SYS') or '').startswith('aarch64-')):
bb.fatal('WOLFSSL_ALTERA_FCS requires an AArch64 target')
}