ESP32 の WireGuard 鍵:デバイスごとか、共通の鍵を焼き込むか
ESP32 のファームウェアに組み込まれた鍵はピアの識別情報であり、パスワードではない。所有、フラッシュ保護、群全体での再利用という三つの条件で決める。
スケッチは WireGuard の秘密鍵を文字配列に置き、トンネルは動く。だからこの質問は繰り返し出てくる。本当に決めるべきなのは「これは安全か」ではなく、「三つの条件のどれがこの配備に当てはまるか」だ。条件とは、誰が物理的にデバイスを保持できるか、あなたの部品でフラッシュを読むと何が出るか、群が一つの鍵を共有するのか各機が自分の鍵を持つのか、である。これに答えれば設計は決まる。どの条件も、鍵が漏れうるという事実ではなく、漏れたときのコストを変えるからだ。
鍵が何を許可するか
WireGuard は公開鍵でピアを認証する。サーバーは各ピアの公開鍵を一つのアドレスとAllowedIPsのリストに対応づける。だからこそ秘密鍵があれば、クライアントはそのアドレスから通信を送り出せる。
同じエントリが、デバイスが到達できる宛先を決める。したがって鍵が漏れると、トンネルのアドレスだけでなくトンネルの背後のネットワークも露出する。
条件一:誰がデバイスを保持できるか
筐体が施錠された棚にあり、チームの外の誰も触らないなら、露出は主にファームウェア配布の問題だ。顧客に出荷され、車両に載り、保証で戻ってくるなら、物理的な所有が資格情報であり、バイナリの秘匿は二次的である。デバイスを手にした人は鍵を読む必要がない。動いているファームウェアがその人にトンネルを開いてしまうからだ。だからサーバー側の答えには、保護されたイメージだけでなく、失効と有限の寿命を含めなければならない。
この条件を他の二つより先に決める。両方の予算を決めるのはこの条件だからだ。
条件二:フラッシュを読むと何が出るか
フラッシュイメージを読める者は、リテラルとして保存された鍵を取り戻す。デバッグ接続、更新ファイル、バックアップ、返却された個体のいずれでも同じだ。フラッシュ暗号化は直接ダンプのコストを上げる。ESP-IDF の文書は、特定の部品と構成でこの機能が何を覆うかを説明している。あらゆる攻撃モデルで鍵を抽出不能にするものではなく、手元にあるデバイスの場合には何の役にも立たない。コストを変える一つの層として扱い、答えとして扱わないこと。
設計レビューで性質を主張する前に、自分のチップと構成についてのプラットフォーム文書を読むこと。
条件三:群全体での再利用
量産ロットに一つの鍵ということは、すべての個体が一つの識別情報を共有するということだ。サーバーはログでそれらを見分けられず、一つだけを失効させることができず、クローンと正規品を区別することもできない。デバイスごとの鍵はこの三つをすべて解決する。代償は登録の手順と、シリアル番号から公開鍵への対応表だ。その対応表こそ、失効を群全体の再書き込みではなく一行の変更に変える資産である。
群が作業台の上の五台なら、鍵の共有は妥当な取引かもしれない。現場の五百台なら、取引にすらならない。
デバイスごとの鍵を実用的にする登録の型
初回起動時にデバイス上で鍵ペアを生成し、秘密の半分を保護された不揮発記憶に置き、公開鍵だけを登録サービスに送る。サービスはアドレスを割り当て、ピアのエントリを書き込む。登録の応答を認証すること。さもないとローカルネットワークの攻撃者が自分の鍵をあなたのアカウントに登録できてしまう。プロビジョニング中に秘密鍵をシリアルコンソールへ出力しないこと。デバイスのシリアル番号を公開鍵の隣に記録し、紛失した個体がちょうど一つのピアエントリに対応するようにする。
小さなサービスだが、監査できる群と、書き込み直すしかない群の違いはここにある。
時刻、エンドポイント、そして判断
例はトンネルを開始する前に時刻を同期する。これは TLS 以外でも効く。WireGuard のハンドシェイクは再生保護のためのタイムスタンプを運ぶので、時計が狂ったまま起動したデバイスはハンドシェイクを拒否されうる。エンドポイントはホスト名で、サーバーの公開鍵が依然としてピアを認証していても、DNS を信頼の経路に入れる。間違ったアドレスは試行を無駄にし、デバイスがいつオンラインかを明かす。鍵を論じる前に、この二つを片づけること。
そして決める。所有が管理され群が小さい間だけ共有鍵を、どちらかが成り立たなくなった時点でデバイスごとの鍵を。