Super mini S3を使って、Secure Boot V2をテストしてみる。
プロジェクトは動作確認に使ったsupermini_rgb48_testをそのまま使う。
Secure Boot V2は、趣味のプロダクトをビルドするときには、まったく気にする必要がないのだけれど、商用の商品をリリースする場合には必須の項目になる。
Secure Boot V2とは
PCのブートプロセスほど厳格ではないけれど、マイコンであるESP32にもSecure Bootの仕組みがある。
ドキュメントはこのあたり。
Secure Boot v2 - ESP32-S3 - — ESP-IDF Programming Guide v5.5.2 documentation
https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/security/secure-boot-v2.html
Secure Bootは、デバイス上で未署名・不正署名のコードを起動しないようにして、アプリケーションの改ざんや差し替えを防ぐ機能。
ROM上にあるブートローダーである1st stage bootloaderが、eFuseに書かれた公開鍵のダイジェストを使って2nd stage bootloaderの署名ブロックの公開鍵のダイジェストが一致するかを検証し、さらに2nd stage bootloaderの署名検証を行う。2nd stage bootloaderは、アプリ側の署名ブロックに入っている公開鍵を使い、そのダイジェストがeFuse登録済みのものと一致することを確認した上で、その公開鍵を使ってアプリケーションイメージやOTAイメージの署名を検証して、マッチしない場合は起動しないようにする。
ただ、アプリケーションなどに署名はされていても、eFuseに鍵が書き込まれ、Secure Boot V2を使用する設定になっていない場合は、署名がされたバイナリでも普通に起動できるので、署名そのものは開発の初期からやるように設定しておいたほうがよい。
eFuseへの鍵のダイジェストの書き込みは、一度行うと書き換えができず、開発時には不自由な環境を強いられるため初期からやるべきではない。製品の製造や出荷時に行うのがよい。
公開鍵のダイジェストを書き込むeFuse領域は3つあるので、未使用エリアをrevoke設定していない限り、ダイジェストは3種類保持することができる。署名検証の検索は順に行われるため、いずれかの鍵で署名されたイメージを起動することができる。
このような機能は、鍵の漏洩時や漏洩リスクの低減などで、鍵ローテーションを行う場合に利用できる。アップデートで、アプリケーション側からもう使わない鍵のrevokeを行うことはできるが、起動不能になるリスクを伴うので、製造時の管理などで利用することを想定している。一度revokeしてしまうと、そのエリアは使用できなくなるので注意。
Secure BootはV1とV2があって、検索して出てくる日本語での解説はV1についての内容がほどんどであり、V2とは状況が異なるのであまり参考にならないので注意。
SecureBoot鍵を事前に作成する
製品共通のSecure Boot v2署名鍵(RSA-3072)を作成する。
サンプルの鍵の内容は、普通は公開しないものなのだけど、ここではそのまま書いておく。
鍵の管理は、流出対策にはリポジトリの外に置くのが妥当なのだろうけど、今回はそんなに気にしないのでプロジェクトにkeysディレクトリを掘って、gitignoreを設定しておく。
% mkdir keys
% vi .gitignore
/keys/*.pem
/keys/*.key
鍵は、ESP-IDFの環境が入っている端末で「idf.py secure-generate-signing-key」やopensslコマンドを使って作成する。
% idf.py secure-generate-signing-key --version 2 ./keys/secure_boot_signing_key.pem
Executing action: secure-generate-signing-key
Running espsecure in directory /Users/kinneko/Downloads/esp/supermini/supermini_rgb48_test
Executing "/Users/kinneko/.espressif/python_env/idf5.5_py3.13_env/bin/python -m espsecure generate_signing_key --version 2 ./keys/secure_boot_signing_key.pem"...
espsecure.py v4.11.dev1
RSA 3072 private key in PEM format written to ./keys/secure_boot_signing_key.pem
% ls -al ./keys/
total 8
drwxr-xr-x 3 kinneko staff 96 2 12 14:20 .
drwxr-xr-x 18 kinneko staff 576 2 12 14:20 ..
-rw-r--r-- 1 kinneko staff 2459 2 12 14:20 secure_boot_signing_key.pem
% cat keys/secure_boot_signing_key.pem
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----
OpenSSLコマンドで作ることもできる。コマンド実行時の出力は特にない。
% openssl genrsa -out ./keys/secure_boot_signing_key_openssl.pem 3072
% ls -al ./keys/secure_boot_signing_key_openssl.pem
-rw------- 1 kinneko staff 2484 2 12 14:22 ./keys/secure_boot_signing_key_openssl.pem
% cat ./keys/secure_boot_signing_key_openssl.pem
-----BEGIN PRIVATE KEY-----
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
EC/CzNl4Z4y07btTEKzsTQ==
-----END PRIVATE KEY-----
eFuseに書き込むダイジェスト鍵を作成する。これは、idf.pyではラップされていないので、独自のコマンドはない。opensslコマンドで作成する。
% openssl rsa -in ./keys/secure_boot_signing_key.pem -pubout -out ./keys/secure_boot_signing_key_pub.pem
writing RSA key
% ls -al keys/secure_boot_signing_key_pub.pem
-rw-r--r-- 1 kinneko staff 625 2 12 14:27 keys/secure_boot_signing_key_pub.pem
% cat keys/secure_boot_signing_key_pub.pem
-----BEGIN PUBLIC KEY-----
MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAxB97Vkkg5lXq5zg+HBEU
uQ7J/otTAc0lb+HmmwGgNxG+XhlGYAyzSSQSHrtMomNkqGJRN3CTdAK3tMCbMMsq
Irl9ukHZgQSqItNPHTCTriBkuSoq73HVgfNLRRvy4gDu9w8kZsv1OMS70VwVQJl3
148e7mn29DQIIdXoD4n/yrQXOjX4ybg/M8FDb/I4ZtT4LaHih9w+LB5ZrzSpl9fO
4VhzEGOlsA05wvA1lDibQZfjrZ26NYWgN45Nhd4Y8u71VwEutSuDZUrdiSR9uFWQ
KOoq4M3txYq2E7D6GJ33g7YSIcWXxxN0ZjMKoH5GMgcGEBLZsbu5q9zUe5+P2YCL
XvTQKyqJ2HgBO+TONwdY0C9TiIEjd6ECzJqjI6SVvhnL39xc62QA+fdkakRFQdzA
r3xHbF+WH2eHvWBqcLfML0dS3mvWWfprPqyLjuajTPA9FlbOaVkX+w2kAgmyBes6
wiauWulh9CWgwibDqLpixAZAlUQhV1oowbBVTNdHX6avAgMBAAE=
-----END PUBLIC KEY-----
署名の実行-手動署名-
作成した鍵を使って実際に署名を行うには、ビルド時に自動適用する方法と、ビルドしたバイナリにコマンドで署名を追加する方法がある。手動署名と自動署名の順で試す。
署名する必要があるファイルは通常ビルドを行うと作成される以下の4つになる。
・アプリとOTA:build/ota_data_initial.bin, build/supermini_rgb48_test.bin
・ブートローダー(2nd):build/bootloader/bootloader.bin
・パーティションテーブル:build/partition_table/partition-table.bin
ただし、パーティションテーブルの署名は検証されないので、手動で行う場合はやる必要はない。
アプリ本体のsupermini_rgb48_test.binを署名してsupermini_rgb48_test_signed.binを作る。使用するコマンドはidf.py secure-sign-dataとespsecure.py sign_data --version 2があって、どちらかを実行する。
idf.py secure-sign-dataの実行時には、内部でbuildが作業ディレクトリになるので、イメージのbuildパスは指定する必要がない、また、keyfileはbuildからの相対パスで指定しておく。(そんなん知らんがなめんどくさ)
% idf.py secure-sign-data --keyfile ../keys/secure_boot_signing_key.pem --output supermini_rgb48_test_signed.bin supermini_rgb48_test.bin
Executing action: secure-sign-data
Running espsecure in directory /Users/kinneko/Downloads/esp/supermini/supermini_rgb48_test/build
Executing "/Users/kinneko/.espressif/python_env/idf5.5_py3.13_env/bin/python -m espsecure sign_data --version 2 --keyfile ../keys/secure_boot_signing_key.pem --output supermini_rgb48_test_signed.bin supermini_rgb48_test.bin"...
espsecure.py v4.11.dev1
Padding data contents by 3776 bytes so signature sector aligns at sector boundary
1 signing key(s) found.
Signed 225280 bytes of data from supermini_rgb48_test.bin. Signature sector now has 1 signature blocks.
% ls -al build/supermini_rgb48_test_signed.bin
-rw-r--r-- 1 kinneko staff 229376 2 12 16:06 build/supermini_rgb48_test_signed.bin
espsecure.py sign_dataのほうは、プロジェクトのルートからのパス指定でよい。
% espsecure.py sign_data --version 2 --keyfile ./keys/secure_boot_signing_key.pem --output ./build/supermini_rgb48_test_signed_espsecure.bin ./build/supermini_rgb48_test.bin
espsecure.py v4.11.dev1
Padding data contents by 3776 bytes so signature sector aligns at sector boundary
1 signing key(s) found.
Signed 225280 bytes of data from ./build/supermini_rgb48_test.bin. Signature sector now has 1 signature blocks.
% ls -al build/supermini_rgb48_test_signed_espsecure.bin
-rw-r--r-- 1 kinneko staff 229376 2 12 16:08 build/supermini_rgb48_test_signed_espsecure.bin
OTAイメージやブートローダーも同様に署名しておく。
つづく
オリジナル投稿:
ESP32-S3でSecure Boot V2 -1-|kinneko|pixivFANBOX
https://kinneko.fanbox.cc/posts/11394371



