Matter 18 · OTA ソフトウェア更新 — Provider / Requestor と BDX

Chapter 18

OTA ソフトウェア更新 — Provider / Requestor と BDX

この章がなぜ必要なのか——出荷後に直せない製品は作ってはいけない.

セキュリティ脆弱性、相互運用性の不具合、仕様の更新—— 出荷後にファームウェアを更新できないことは、それ自体がリスクである。

Matter は OTA を標準の枠組みとして定義している。 エコシステム側が更新を配信してくれるので、 メーカーが独自のクラウドを持たなくてよい——これは大きな利点である。

この章で使う既出の用語(定義は各リンク先). Matter(01 章 3 節)、アプリケーション層(01 章 3 節)、コミッショニング(01 章 3 節)、セキュリティ(01 章 2 節)、ネットワーク(01 章 3 節)、相互運用性(01 章 2 節)、ACL(02 章 4 節)、Wi-Fi(04 章 9 節)、必要(05 章 5 節)、Exchange(06 章 5 節)、指数バックオフ(06 章 3 節)、ProductID(08 章 1 節)、VendorID(08 章 1 節)、ハッシュ(11 章 2 節)、改竄(11 章 1 節)、署名(11 章 2 節)、DCL(12 章 11 節)、メーカー(12 章 3 節)

1. 登場人物

ロールクラスタ役割
OTA Provider0x0029イメージを配布する側。ハブやクラウド連携ノード
OTA Requestor0x002A更新を受ける側。あなたの機器
[OTA Provider]                          [OTA Requestor(機器)]
(ハブ、または                              │
  エコシステムのクラウド                     │
  と連携したノード)                         │
      │<──── QueryImage ──────────────────│ 「更新ありますか?」
      │────> QueryImageResponse ─────────>│ 「あります。バージョン X」
      │<──── BDX でイメージを転送 ─────────>│
      │<──── ApplyUpdateRequest ──────────│ 「適用してよいですか?」
      │────> ApplyUpdateResponse ────────>│ 「どうぞ」
      │                                   │ ← 再起動して適用
      │<──── NotifyUpdateApplied ─────────│ 「適用しました」

2. Requestor 側の流れ

(a) Provider を知る

方法内容
DefaultOTAProviders 属性コミッショニング時などに設定される
AnnounceOTAProvider コマンドProvider が「私がいます」と通知

(b) QueryImage

QueryImage {
    VendorID, ProductID,
    SoftwareVersion,          ← 現在のバージョン
    ProtocolsSupported,       ← BDX Synchronous など
    HardwareVersion,          ← 任意
    Location, RequestorCanConsent, MetadataForProvider
}
    ↓
QueryImageResponse {
    Status,                   ← UpdateAvailable / Busy / NotAvailable / DownloadProtocolNotSupported
    DelayedActionTime,        ← Busy のとき、次に聞くまでの待ち時間
    ImageURI,                 ← bdx:// または https://
    SoftwareVersion,          ← 新しいバージョン
    SoftwareVersionString,
    UpdateToken,              ← このセッションの識別子
    UserConsentNeeded,
    MetadataForRequestor
}

Busy と DelayedActionTime が重要である. 家中の機器が一斉に更新を要求すると、Provider が過負荷になる。 Busy + 待ち時間で更新を分散させる。

Requestor 側は必ずこれを尊重すること。 無視して即座に再試行する実装は、 認証テストでも問題になるし、実運用でネットワークを詰まらせる。

(c) ダウンロード(BDX)

BDX(Bulk Data Exchange)は、Matter のセッション上で大きなデータを転送するプロトコル。

特徴内容
Matter のセッション上で動く暗号化・認証済み
ブロック単位の転送ブロックサイズを折衝
再開一部の実装では途中から再開可能
フロー制御受信側のペースに合わせる

https:// の URI が返される場合もある(大きなイメージや、Wi-Fi 機器向け)。 その場合は通常の HTTPS でダウンロードする。

Thread 機器での BDX は遅い. 250 kbps、実効はさらに低い。1 MB のイメージに数分〜数十分かかる。

対策:

「更新中は使えません」が 30 分続く製品は、ユーザーに嫌われる。

(d) 適用

ApplyUpdateRequest { UpdateToken, NewVersion }
    ↓
ApplyUpdateResponse {
    Action,        ← Proceed / AwaitNextAction / Discontinue
    DelayedActionTime
}
Action意味
Proceed適用してよい
AwaitNextAction待て(あとで再度聞け)
Discontinue中止せよ

AwaitNextAction の使いどころ. 「ドアロックが施錠中は更新しない」「照明が点いている間は更新しない」 といった制御を Provider 側から行える。

Requestor 側でも、危険な状態での再起動を避ける判断が必要である。 調理家電が加熱中に再起動してはいけない。

(e) 適用後

NotifyUpdateApplied { UpdateToken, SoftwareVersion }

これで Provider は更新の成功を知る。

3. UpdateState の遷移

OtaSoftwareUpdateRequestor クラスタの UpdateState 属性で外部から観測できる。

状態意味
Unknown不明
Idle何もしていない
Querying問い合わせ中
DelayedOnQueryBusy を受けて待機中
Downloadingダウンロード中
Applying適用中
DelayedOnApply適用待機中
RollingBackロールバック中
DelayedOnUserConsentユーザー同意待ち

UpdateStateProgress 属性でダウンロードの進捗(0〜100)も公開される。

これらを正しく更新すること. アプリが「更新中 45%」と表示できるかどうかは、この属性次第である。 ユーザー体験に直結する。

4. イメージのフォーマット

Matter の OTA イメージには標準ヘッダが定義されている。

フィールド内容
File Identifier0x1BEEF11E
Total Sizeヘッダ + ペイロードの全長
Header Sizeヘッダ長
Vendor ID / Product ID対象製品
Software Version新しいバージョン(数値)
Software Version String表示用
Payload Size本体のサイズ
Min/Max Applicable Version適用可能な現行バージョンの範囲
Release Notes URL任意
Image Digest / Digest Typeハッシュ
# SDK のツールでイメージを作る
./src/app/ota_image_tool.py create \
    -v 0xFFF1 -p 0x8000 -vn 2 -vs "2.0" -da sha256 \
    firmware.bin firmware-ota.bin

# 中身を確認
./src/app/ota_image_tool.py show firmware-ota.bin

Min/Max Applicable Version が段階的更新を可能にする. 「v1 → v3 に直接は上げられない。まず v2 を経由せよ」という制約を表現できる。 データ形式の移行が必要な更新で使う。

5. セキュリティ

OTA は最も危険な攻撃経路である. 任意のファームウェアを流し込めれば、機器を完全に乗っ取れる。

対策内容
転送路の保護BDX は Matter セッション上なので暗号化・認証済み
イメージの署名検証機器側で必ず検証する。最重要
セキュアブート署名されていないイメージは起動しない
バージョンのダウングレード防止古い(脆弱な)版に戻せないようにする
ロールバック起動に失敗したら旧イメージに戻る

署名検証を SoC のセキュアブートに任せるのが定石である. アプリケーション層で検証してから書き込むより、 ブートローダが起動前に検証する方が強い(書き込み後に改竄されても防げる)。

Matter の仕様は「転送の保護」までしか規定していない。 イメージ自体の署名と検証はメーカーの責任である。 ここを実装しないと、Provider を偽装できれば任意コード実行になる。

A/B 更新とロールバック

[領域 A: 現在動作中]   [領域 B: 空き]
        ↓ ダウンロード
[領域 A: 現在動作中]   [領域 B: 新イメージ]
        ↓ 再起動、B から起動
[領域 A: 旧イメージ]   [領域 B: 動作中(試用期間)]
        ↓ 正常に動作すれば確定
        ↓ 起動に失敗すれば A に戻る

「試用期間」の判定基準を決める必要がある.

緩すぎると、起動はするが通信できないファームで文鎮化する。 「Matter のセッションが 1 回確立できたら確定」あたりが実用的な基準である。

6. Provider 側の実装

自社でハブを作る、または開発時に検証する場合。

# SDK のサンプル Provider
./out/ota-provider-app/chip-ota-provider-app --filepath firmware-ota.bin

# コミッショニングして ACL を設定
chip-tool pairing onnetwork 2 20202021
chip-tool accesscontrol write acl '[{"privilege":5,"authMode":2,"subjects":[112233],"targets":null},{"privilege":3,"authMode":2,"subjects":null,"targets":null}]' 2 0

# Requestor に Provider を教える
chip-tool otasoftwareupdaterequestor announce-otaprovider 2 0 0 0 1 0

# 状態を見る
chip-tool otasoftwareupdaterequestor read update-state 1 0
chip-tool otasoftwareupdaterequestor read update-state-progress 1 0

Provider の ACL 設定が必要である. Requestor が Provider の QueryImage を呼べるように、 Provider 側の ACL に「誰でも Operate 可」のエントリが要る (上の例の 2 番目のエントリ)。 ここを忘れると UNSUPPORTED_ACCESS で止まる(14 章)。

7. 運用上の考慮

項目内容
配信の分散全機器が同時に更新すると帯域を食い潰す
バージョン管理SoftwareVersion は単調増加の整数(08 章)
DCL への登録OTA 情報を DCL に載せる方式もある(12 章)
エコシステム経由各社が独自に配信する場合、それぞれに提出が必要
失敗時の再試行指数バックオフ
電源断への耐性更新中に電源が切れても壊れない設計
ユーザー通知更新の有無・進捗・完了

エコシステムごとに配信の仕組みが違う点に注意. Apple / Google / Amazon がそれぞれ独自のパイプラインを持つ。 どこにイメージを提出し、どう承認されるかは各社のプログラムに従う。 認証取得(22 章)とセットで確認すべき事項である。

8. 落とし穴

落とし穴対処
Flash 容量が足りない設計時に 2 面分を確保(17 章)
イメージの署名検証を実装しない重大な脆弱性。セキュアブートを使う
ロールバックがない更新失敗で文鎮化
SoftwareVersion が非単調更新判定が壊れる
Provider の ACL 未設定UNSUPPORTED_ACCESS
Busy / DelayedActionTime を無視Provider を圧迫、テストで問題になる
Thread での転送時間を見積もらない数十分かかる
更新中に機器が使えないUX の悪化。A/B 面で回避
電源断への耐性がないブリックする
進捗属性を更新しないアプリで進捗が見えない
危険な状態での再起動加熱中・施錠動作中などは避ける

9. まとめ