diff --git a/README.md b/README.md index 75cc656..7b74d57 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/conf/layer.conf b/conf/layer.conf index 24ac926..2d699e4 100644 --- a/conf/layer.conf +++ b/conf/layer.conf @@ -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" diff --git a/recipes-support/README.md b/recipes-support/README.md index bdcd5a1..bd027e4 100644 --- a/recipes-support/README.md +++ b/recipes-support/README.md @@ -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. diff --git a/recipes-support/libfcs/agilex5/README.md b/recipes-support/libfcs/agilex5/README.md new file mode 100644 index 0000000..df28961 --- /dev/null +++ b/recipes-support/libfcs/agilex5/README.md @@ -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. diff --git a/recipes-support/libfcs/gsrd-intel-fcs-lib_%.bbappend b/recipes-support/libfcs/gsrd-intel-fcs-lib_%.bbappend new file mode 100644 index 0000000..3296805 --- /dev/null +++ b/recipes-support/libfcs/gsrd-intel-fcs-lib_%.bbappend @@ -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 +} diff --git a/recipes-support/libfcs/libfcs_git.bb b/recipes-support/libfcs/libfcs_git.bb new file mode 100644 index 0000000..69a11cf --- /dev/null +++ b/recipes-support/libfcs/libfcs_git.bb @@ -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" diff --git a/recipes-support/libfcs/wolfssl_%.bbappend b/recipes-support/libfcs/wolfssl_%.bbappend new file mode 100644 index 0000000..bf9af2e --- /dev/null +++ b/recipes-support/libfcs/wolfssl_%.bbappend @@ -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') +}