Raspberry Pi 4にはHTTP経由でFAT32のブートイメージを取得して起動する機能が追加されましたが、 HTTPなのでそのままでは改ざんされる可能性があります。これに対してSecure Boot機能なるものが追加されたようですので試してみます。 (この機能では改ざんは防げますが、盗聴は防げません。また、ブートイメージのサイズが大きすぎると失敗します。ご注意ください。)
手順としては次のようになります。
- FAT32のブートイメージ(
boot.img
)を作成 - 検証用のRSA鍵ペアを生成
- eepromに仕込む公開鍵:
public.pem
- イメージファイルに署名する秘密鍵:
private.pem
- eepromに仕込む公開鍵:
- eepromイメージをHTTP Secure Boot用にカスタマイズし、Raspberry Pi 4に書き込む
boot.img
に署名したboot.sigを生成し、eepromの設定に仕込んだWebサーバのパスに設置
必要なもの
- Raspberry Pi 4本体(2台あると楽)
- DHCPが利用できる有線ネットワーク
- 到達可能なWebサーバ
boot.imgの作成
boot.img
は適当に作成しておいてください。
(今回はRaspberry Pi Imagerのboot.imgをそのまま用いました。)
とりあえずhttps://github.com/raspberrypi/firmware/tree/master/bootのファイルを全部持ってきて、 FAT32でフォーマットしたファイルイメージに全部コピーしておけば、kernelが起動するところまでは試せます。後はinitramfsにbusyboxを仕込むなどすればなんとでもなります。
検証用のRSA鍵ペアを生成
署名用の秘密鍵private.pem
とeepromに仕込む公開鍵public.pem
を生成します。
鍵フォーマットはごくふつうのRSA 2048bit鍵でよいようです。 (今のところこれ以外だと動作しないらしい)
1
2
% openssl genrsa 2048 > private.pem
% openssl rsa -in private.pem -pubout -out public.pem
eeprom-http-boot.conf
eepromの設定ファイルの例です。
主に編集が必要なのはBOOT_ORDER
とNET_INSTALL_ENABLED
、NET_INSTALL_KEYBOARD_WAIT
、
HTTP_HOST
、HTTP_PORT
、HTTP_PATH
の部分です。
NET_INSTALL_ENABLED
を1
にすると、起動時にネットインストール(HTTP Boot)の指示待ち
(キーボードによるShiftキーの入力待ち)が行われるようになります。
この指示待ちはNET_INSTALL_KEYBOARD_WAIT
で指定された時間(今回は10000
なので10000ms)行われ、
Shiftキーの入力があった場合にHTTP Bootが試行されます。
もし入力がなければ、BOOT_ORDER
の順にブートが試行されます。
BOOT_ORDER
では、SDカード(BOOT_ORDER
の0x1
)、
USBストレージ(BOOT_ORDER
の0x4
)の順で参照、
いずれも失敗したらリセット(BOOT_ORDERの0xf
)するようにしています。
もしHTTP Bootを強制的に実行したいのであれば、BOOT_ORDER
の任意の場所に0x7
を加えます。
BOOT_ORDER
は下位桁から順に参照される点に注意してください。
HTTP_HOST
、HTTP_PORT
、HTTP_PATH
は、その名の通りホスト名とポート番号、サーバ上でのパスです。
この例では、http://rpi-image.hachune.net/net_install/boot.img
からダウンロードされるようになります。
ブートイメージファイルの名前(boot.img
)は変更できないようです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[all]
BOOT_UART=1
WAKE_ON_GPIO=1
POWER_OFF_ON_HALT=0
BOOT_ORDER=0xf41
SD_BOOT_MAX_RETRIES=1
HTTP_HOST=rpi-image.hachune.net
HTTP_PORT=80
HTTP_PATH=net_install
NET_INSTALL_ENABLED=1
NET_INSTALL_KEYBOARD_WAIT=10000
USB_MSD_DISCOVER_TIMEOUT=10000
FREEZE_VERSION=1
[none]
eepromイメージのカスタマイズ
rpi-eeprom-config
コマンドと先ほど作成した設定ファイルeeprom-http-boot.conf
でeepromイメージをカスタマイズします。
ついでにSecure Boot用公開鍵も追加します。
1
2
3
4
5
6
# eepromイメージへの公開鍵の追加と設定の更新
% rpi-eeprom-config -c eeprom-http-boot.conf -p public.pem -o pieeprom.bin /usr/lib/firmware/raspberrypi/bootloader/stable/pieeprom-2022-03-10.bin
# eepromイメージの検証用ハッシュを生成
% rpi-eeprom-digest -i pieeprom.bin -o pieeprom.sig
# アップデート用ファイル名に変更
% ln -f pieeprom.bin pieeprom.upd
pieeprom.upd
とpieeprom.sig
をHTTP bootしたいRaspberry Pi 4のboot用ファイルシステム内にコピーしておけば、次回起動時に自動的にeepromが更新されます。
更新後はカラフルでいかにもHTTP bootしそうな画面が出てくるようになります。
boot.imgの署名ファイル生成
Raspberry Pi 4の起動に必要なファームウェアやカーネル等が詰まったboot.img
に対し、先ほど作成した秘密鍵private.pem
で署名を行い、boot.sig
を生成します。
1
2
# private.pemを用いてboot.imgの署名ファイルboot.sigを生成
% rpi-eeprom-digest -i boot.img -o boot.sig -k private.pem
boot.imgとboot.sigの設置
設定ファイルeeprom-http-boot.conf
のHTTP_HOSTとHTTP_PORT
、
HTTP_PATH
で設定したWebサーバにboot.img
とboot.sig
を設置します。
Webサーバはなんでも大丈夫ですが、必ずRaspberry Pi 4が利用するネットワークのDHCPサーバから得られるDNSサーバが、
Webサーバのアドレスを引けるようにしておく必要があります。
今回の場合は、http://rpi-image.hachune.net/net_install/boot.img
とhttp://rpi-image.hachune.net/net_install/boot.sig
がダウンロードできるようにします。
HTTP bootする
すべての条件が整ったら、Raspberry Pi 4を起動します。 (テストしやすいようにストレージ類は全部抜いておきましょう) 起動したらすかさずShiftキーを押し続けます。
うまくダウンロードが始まると、こんな感じになります。
後はいつも通りカーネルとユーザランドのアプリが起動してきます。
起動時のログ
eeprom設定ファイル作成時にBOOT_UART=1
としておくと、こんな感じのログが得られます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
RPi: BOOTLOADER release VERSION:778c182c DATE: 2022/03/10 TIME: 11:57:12 BOOTMODE: 0x00000006 part: 0 BUILD_TIMESTAMP=1646913432 0x519624e9 0x00d03114 0x0005795f
PM_RSTS: 0x00001000
part 00000000 reset_info 00000000
uSD voltage 3.3V
Initialising SDRAM 'Micron' 32Gb x2 total-size: 64 Gbit 3200
XHCI-STOP
xHC ver: 256 HCS: 05000420 fc000031 00e70004 HCC: 002841eb
USBSTS 11
xHC ver: 256 HCS: 05000420 fc000031 00e70004 HCC: 002841eb
xHC ports 5 slots 32 intrs 4
Boot mode: SD (01) order f4
USB2[1] 400202e1 connected
USB2 root HUB port 1 init
DEV [01:00] 2.16 000000:01 class 9 VID 2109 PID 3431
HUB init [01:00] 2.16 000000:01
HUB [01:00] 2.16 000000:01 init port 3 speed 1
DEV [02:01] 2.00 000003:01 class 0 VID 17ef PID 6047
HID [02:01] 2.00 000003:01 register HID
HDMI0 edid block 0 offset 0
00ffffffffffff002157010001000000
011d0104824627782ad9b0a357499c25
11494b210800714081c0810081408180
9500a9c0b300023a801871382d40582c
4500c48e2100001e000000fd0017551e
641e0410000000000001000000f7000a
0040c6440000000000000000000000fc
0048444d4920544f205553420a2001d4
HDMI0 edid block 1 offset 128
02032cf151010203041112131f202122
3c3d3e905f6423090707830100006703
0c001000b83ce50e61606665011d0072
51d01e206e285500c48e2100001e8c0a
d08a20e02d10103e9600c48e21000018
8c0ad090204031200c405500c48e2100
00184e1f008051001e3040803700c48e
21000018000000000000000000000022
HDMI0: best-mode 1 (limit 1) CEA 1e000f80070000700000008010000000
GENET: RESET_PHY
PHY ID 600d 84a2
NET_BOOT: dc:a6:32:xx:xx:xx wait for link TFTP: 0.0.0.0
LINK STATUS: speed: 1000 full duplex
Link ready
GENET START: 64 16 32
GENET: UMAC_START 0xdca632b2 0x4bcf0000
RX: 0 IP: 0 IPV4: 0 MAC: 0 UDP: 0 UDP RECV: 0 IP_CSUM_ERR: 0 UDP_CSUM_ERR: 0
DHCP src: 62:bd:62:xx:xx:xx 192.168.254.254
YI_ADDR 192.168.254.105
SI_ADDR 192.168.254.254
OPTIONS:-
op: 53 len: 1 DHCP recv OFFER (2) expect OFFER
op: 54 len: 4 192.168.254.254
op: 51 len: 4
op: 1 len: 4 255.255.255.0
op: 3 len: 4 192.168.254.254
op: 6 len: 4 192.168.254.254
NET 192.168.254.105 255.255.255.0 gw 192.168.254.254 tftp 0.0.0.0
DHCP src: 62:bd:62:d6:de:5a 192.168.254.254
YI_ADDR 192.168.254.105
SI_ADDR 192.168.254.254
OPTIONS:-
op: 53 len: 1 DHCP recv ACK (5) expect ACK
op: 54 len: 4 192.168.254.254
op: 51 len: 4
op: 1 len: 4 255.255.255.0
op: 3 len: 4 192.168.254.254
op: 6 len: 4 192.168.254.254
op: 66 len: 13 192.168.254.101[66]: 192.168.254.101
op: 15 len: 16
NET 192.168.254.105 255.255.255.0 gw 192.168.254.254 tftp 0.0.0.0
RX: 2 IP: 0 IPV4: 2 MAC: 2 UDP: 2 UDP RECV: 2 IP_CSUM_ERR: 0 UDP_CSUM_ERR: 0
Loading boot.img ...
HTTP: GET request for http://rpi-image.hachune.net:80/net_install/boot.sig
SIG boot.sig b9fb1f930760ca62c981adab010eb20aeaff86079e62e147598f229d8813b54c 1649341567
HTTP: GET request for http://rpi-image.hachune.net:80/net_install/boot.img
HTTP: got 0% at 1 kB/s
HTTP: got 10% at 1285 kB/s
HTTP: got 28% at 2255 kB/s
HTTP: got 46% at 2747 kB/s
HTTP: got 64% at 3038 kB/s
HTTP: got 82% at 3234 kB/s
HTTP: got 100% at 3925 kB/s
Verifying
RSA verify
rsa-verify pass (0x0)
MBR: 0x00000000, 0 type: 0x00
MBR: 0x00000000, 0 type: 0x00
MBR: 0x00000000, 0 type: 0x00
MBR: 0x00000000, 0 type: 0x00
Trying partition: 0
type: 16 lba: 0 oem: 'mkfs.fat' volume: ' V ^ '
rsc 4 fat-sectors 48 c-count 11759 c-size 4
root dir cluster 1 sectors 16 entries 256
FAT16 clusters 11759
Read config.txt bytes 280 hnd 0x52
Read start4.elf bytes 2240608 hnd 0x2151
Read fixup4.dat bytes 5354 hnd 0x53
Firmware: bd88f66f8952d34e4e0613a85c7a6d3da49e13e2 Jan 20 2022 13:56:48
0x00d03114 0x00000000 0x00000fff
MEM GPU: 76 ARM: 948 TOTAL: 1024
Starting start4.elf @ 0xfec00200 partition 0
Stopping network
RX: 15 IP: 0 IPV4: 6 MAC: 2 UDP: 2 UDP RECV: 2 IP_CSUM_ERR: 0 UDP_CSUM_ERR: 0
RX: 15 IP: 0 IPV4: 6 MAC: 2 UDP: 2 UDP RECV: 2 IP_CSUM_ERR: 0 UDP_CSUM_ERR: 0
GENET STOP: 0
GENET: RESET_PHY
PHY ID 600d 84a2
XHCI-STOP
xHC ver: 256 HCS: 05000420 fc000031 00e70004 HCC: 002841eb
USBSTS 18
+
Welcome to Buildroot
buildroot login:
rsa-verify pass (0x0)
となっており、boot.img
の検証が成功していることが分かります。
eeprom更新における公開鍵の取り扱いについて
Raspberry Pi Documentationに
At the moment, if you then apply a public eeprom update, your key will be lost and will need to be re-added.
とある通り、現時点ではeepromの更新を行うと公開鍵が失われるようです。
このため、eepromの更新を停止するといった処置(eepromの設定ファイルにFREEZE_VERSION=1
を追記)が必要となります。
FREEZE_VERSION=1
を解除する際は、microSDカードとrecovery.binを用いた復旧作業が必要となる点に注意してください。
参考
- Raspberry Pi Documentation - HTTP Boot
- Raspberry Pi Documentation - Raspberry Pi 4 Bootloader Configuration Properties
編集履歴
- eeprom-http-boot.confのブート順に関する記述を追記。