iT邦幫忙

2025 iThome 鐵人賽

DAY 9
0
Security

裸機實作 SLH-DSA 簽章:FIPS 205 之演算法實作、測試、防禦與跨平台系列 第 9

將裸機跨平台的模擬整合進 GitHub Actions (CI)

  • 分享至 

  • xImage
  •  

本日重點: 裸機跨平台要怎麼修改 Makefile

因為 sha256 要改成用 CryptoCell 310 和 CryptoCell 312 計算,我想先在 Renode 上模擬,所以今天先說如何將不同平台的模擬整合進 GitHub CI

裸機有兩種型式,一種是完全的裸機,連基本的 memcpy 都自己刻,第二種是連結到一個最小化的 C library,這樣 memcpy 這種就不用自己重寫一個實作。本系列走的是第二種,用的是 libc_nano.a。

為了連結到 libc_nano.a,而且 不動態連結 glibc,Makefile 需要為此調整 compile-time 和 link-time 的參數,以下是幾個相關參數。

除此之外,也要增加 CC310/CC312 的路徑,讓 sha256 能夠在 link-time 直接切換不同 CryptoCell 的 implementation

不使用依賴作業系統的標準 C library

CFLAGS (compile-time)

-ffreestanding

LDFLAGS (link-time)

-specs=nano.specs -nostartfiles -Wl,--start-group -lc -lgcc -Wl,--end-group -Wl,-u,memcpy -Wl,-u,__aeabi_memcpy

然後我們試試在 Makefile 裡用 nm 檢查 ELF file,看看 memcpy 是不是真的有 link 到一份 implementation

$(NM) $(ELF) | grep -E 'memcpy|__aeabi_memcpy'

注意看每一個 function name 前面的 T,T 代表 text section,表示有一份 implementation 存在於 text section

nm sign_nrf52840.elf | grep -E 'memcpy|__aeabi_memcpy'
000014f8 T __aeabi_memcpy
000014f8 T __aeabi_memcpy4
000014f8 T __aeabi_memcpy8
000014fc T memcpy
nm sign_nrf5340.elf | grep -E 'memcpy|__aeabi_memcpy'
0000114c T __aeabi_memcpy
0000114c T __aeabi_memcpy4
0000114c T __aeabi_memcpy8
00001150 T memcpy

如果是 U(Undefined,代表 implementation 不存在,會造成連結失敗.

雖然 x86 的 memcpy 的連結是 U(Undefined),不過其實 x86 的環境不一樣,因為我在 x86 並不打算 bare-metal,所以讓他動態連結 glibc

nm sign_x86.elf | grep -E 'memcpy|__aeabi_memcpy'
                 U __aeabi_memcpy
                 U __memcpy_chk@GLIBC_2.3.4
                 U memcpy@GLIBC_2.14

還有另一個方法能檢查連結的結果,就是在 LDFLAGS 加 -Wl,-Map,然後在 map file 裡檢查

-Wl,-Map,sign_nrf52840.map

如果在 sign_nrf52840.map 看到 libc_a-aeabi_memcpy.o,表示 memcpy 真的有連結到 implementation

/opt/hostedtoolcache/arm-gnu-toolchain-13.2.rel1/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m/nofp/libc_nano.a(libc_a-aeabi_memcpy.o)
                              (__aeabi_memcpy)
/opt/hostedtoolcache/arm-gnu-toolchain-13.2.rel1/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m/nofp/libc_nano.a(libc_a-memcpy-stub.o)
                              /tmp/cc3xD4qJ.o (memcpy)

支援 CryptoCell-310 和 CryptoCell-312

為了能連結到 cc310/cc312,所以 ci.yml 要增加這幾行

    env:
      NRFXLIB_DIR: ${{ github.workspace }}/third_party/nrfxlib
      NRFXLIB_TAG: v3.1-branch

    steps:
      - name: Cache nrfxlib
        id: cache-nrfxlib
        uses: actions/cache@v4
        with:
          path: ${{ env.NRFXLIB_DIR }}
          key: nrfxlib-${{ env.NRFXLIB_TAG }}

      - name: Fetch nrfxlib (cache miss only)
        if: steps.cache-nrfxlib.outputs.cache-hit != 'true'
        uses: actions/checkout@v4
        with:
          repository: nrfconnect/sdk-nrfxlib
          ref: ${{ env.NRFXLIB_TAG }}
          path: ${{ env.NRFXLIB_DIR }}
          fetch-depth: 1

這個也要加到 LDFLAGS

$(NRFXLIB_DIR)/crypto/nrf_cc310_bl/lib/cortex-m4/soft-float/libnrf_cc310_bl_0.9.12.a -Wl,--no-whole-archive

NRFXLIB_DIR 也可以透過 ci.yml 指定, 我用的是 ?= 而不是 :=,所以,如果 ci.yml 沒有指定 NRFXLIB_DIR,那 Makefile 就會對其設一個初始值 third_party/nrfxlib。然而,如果 ci.yml 有指定,那麼 Makefile 的這一行就不會生效

NRFXLIB_DIR ?= $(abspath third_party/nrfxlib)

ci.yml 要注意的是這 3 行,這樣做的好處是 ci.yml 可以將自己尋找 CC310/CC312 的 header files,cc310_bl static libs 的路徑 (NRFXLIB_DIR) 提供給 Makefile,然後 Makefile 和 ci.yml 就能對於 NRFXLIB_DIR 的路徑有共識

NRFXLIB_DIR: ${{ github.workspace }}/third_party/nrfxlib
...
make TARGET=nrf52840 NRFXLIB_DIR="${NRFXLIB_DIR}"
...
make TARGET=nrf5340 NRFXLIB_DIR="${NRFXLIB_DIR}"

ci.yml 的修改不是本系列的主題,所以我就不在 ci.yml 上有過多的說明,有興趣的朋友可以看這裡 check nrfxlib present, Find cc310_bl static libsFind CC310/CC312 C/H files

CFLAGS 還要加上,因為是在 renode 上模擬,所以用 -mfloat-abi=soft

-mfloat-abi=soft -mfpu=fpv4-sp-d16

如果 CC310 連結成功,sign_nrf52840.map 會看到

/home/runner/work/bare-simple-sha2-128/bare-simple-sha2-128/third_party/nrfxlib/crypto/nrf_cc310_bl/lib/cortex-m4/soft-float/libnrf_cc310_bl_0.9.12.a(nrf_cc310_bl_hash.c.obj)
                              (--whole-archive)
/home/runner/work/bare-simple-sha2-128/bare-simple-sha2-128/third_party/nrfxlib/crypto/nrf_cc310_bl/lib/cortex-m4/soft-float/libnrf_cc310_bl_0.9.12.a(nrf_cc310_bl_hash_sha256.c.obj)
                              (--whole-archive)
/home/runner/work/bare-simple-sha2-128/bare-simple-sha2-128/third_party/nrfxlib/crypto/nrf_cc310_bl/lib/cortex-m4/soft-float/libnrf_cc310_bl_0.9.12.a(nrf_cc310_bl_init.c.obj)
                              (--whole-archive)

我想在 GitHub 的 Actions 就能看到 nrf 的 crypto 是不是真實存在,也想知道 CC310/CC312 的 header file 和 cc310_bl static libs 各自放在什麼地方,所以我在 ci.yml 加了一些 step name,執行後會是這個結果
https://ithelp.ithome.com.tw/upload/images/20250922/20140129b3E8CX4h7H.png

這些資訊對於 compile-time 和 link-time 發生的錯誤很有幫助,能讓我在第一時間就確定到底是參數的問題,還是檔案自始不存在。

Makefile 對於 nrf52840 要指定 CFLAGS 和 LDFLAGS,總結如下

...
ifeq ($(TARGET),nrf52840)
  CFLAGS := -mcpu=cortex-m4 -mthumb -mfloat-abi=soft -mfpu=fpv4-sp-d16 -O2 -ffreestanding -Wall -Wextra -DCRYPTO_BACKEND_CC310_BL -Wl,--gc-sections
  LDFLAGS := -T $(LDS) -Wl,-Map,sign_nrf52840.map -Wl,--whole-archive $(NRFXLIB_DIR)/crypto/nrf_cc310_bl/lib/cortex-m4/soft-float/libnrf_cc310_bl_0.9.12.a -Wl,--no-whole-archive -specs=nano.specs -nostartfiles
...
endif

最後是執行 Renode,參考 Makefile

RENODE_IMG = antmicro/renode@sha256:1a4879e047b22827205f4fb1d1e5474d5fdce17eb69f22726ab1afed479f5e22
WORKDIR     ?= $(shell pwd)
RESC        ?= run_sign.resc

ci-run-nrf52840: $(ELF) $(RESC)
	docker run --rm -v "$(WORKDIR):/w" $(RENODE_IMG) \
	  sh -lc 'cd /w && renode --console --disable-xwt -e "set ansi false; include @$(RESC); sleep 2; q"' | sed 's/\x1B\[[0-9;]*[A-Za-z]//g' 

run_sign.resc 是 renode 的 script,這是用於 nrf52840,如果是 nrf5340 就要另外寫一個,本系列會在之後提到 nrf5340 的 repl 怎麼產生,目前先用 nrf52840.repl

set ansi false

mach create "nrf52840_sign"

machine LoadPlatformDescription @platforms/cpus/nrf52840.repl
sysbus LoadELF @sign_nrf52840.elf

showAnalyzer sysbus.uart0

start

上一篇
Day 8 計算 FORS private key
下一篇
Day 10 產生 FORS signature (fors_sign)
系列文
裸機實作 SLH-DSA 簽章:FIPS 205 之演算法實作、測試、防禦與跨平台15
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言