Chapter 14
アテステーション — 「このデバイスは何者か」を署名付きで証明する
この章のゴール.
psa_initial_attest_get_token()を呼んでトークンを取得し、 その中身(CBOR の主張の列と COSE 署名)を読めるようになり、 サーバ側で何を検証すべきか、そして「なぜチャレンジ応答より優れているか」を説明できるようになること。この章で使う既出の用語(定義は各リンク先). PSA(01 章 1 節)、参照実装(01 章 1 節)、type(03 章 11 節)、ハッシュ(05 章 1 節)、乱数(05 章 1 節)、MAC(06 章 1 節)、チャレンジ(09 章 5 節)、認証(09 章 1 節)
1. アテステーションとは何か
アテステーション(attestation、証明)は、 装置が「私はこのハードウェアで、このファームウェアを、この状態で動かしている」と、 改ざんできない形でサーバに申告する仕組みである。
09 章のチャレンジ応答は「秘密鍵を持っている」ことしか証明しない。 乗っ取られた装置も、正規のファームウェアが消されて別のコードが動いている装置も、秘密鍵さえ残っていれば認証を通ってしまう。 アテステーションは、署名の対象に「ブート時に測定したファームウェアのハッシュ」や「ライフサイクル状態」を含めることでこれを防ぐ。
PSA Initial Attestation API は、この申告書(トークン)を作る 2 つの関数だけからなる。
psa_status_t psa_initial_attest_get_token(const uint8_t *auth_challenge, size_t challenge_size,
uint8_t *token_buf, size_t token_buf_size,
size_t *token_size);
psa_status_t psa_initial_attest_get_token_size(size_t challenge_size, size_t *token_size);2. 呼び方
uint8_t challenge[32]; /* サーバから受け取った乱数(32 / 48 / 64 バイトのいずれか) */
uint8_t token[1024];
size_t token_len;
/* 必要なサイズを先に聞くこともできる */
PSA_CHECK(psa_initial_attest_get_token_size(sizeof challenge, &token_len));
/* token_len ≤ sizeof token を確認 */
PSA_CHECK(psa_initial_attest_get_token(challenge, sizeof challenge,
token, sizeof token, &token_len));
send_to_server(token, token_len);auth_challenge(チャレンジ)はサーバが作った乱数。長さは 32・48・64 バイトのどれか(他の長さはINVALID_ARGUMENT)。トークンの中にそのまま入る。再送攻撃を防ぐ- トークンの大きさは、ファームウェアの構成要素の数によるが、通常 300〜700 バイト。1 KB のバッファで足りる
- 呼ぶだけで、アプリケーションは署名鍵にも測定値にも触れない。すべてセキュア側(TF-M のアテステーションパーティション)が持っている
このため、アテステーションはTF-M(または同等のセキュア側実装)がある環境でしか意味を持たない。 Mbed TLS 単体にはこの API はない。 セキュア側が「非セキュア側が何を動かしているか」を独立に測定しているからこそ、申告に価値がある。
3. トークンの中身
トークンは COSE_Sign1(CBOR Object Signing and Encryption の署名 1 つ版、RFC 9052)で包まれた CBOR(Concise Binary Object Representation、JSON をバイナリにしたような形式、RFC 8949)のマップである。 中身の主張(claim、クレーム)は EAT(Entity Attestation Token、RFC 9711)の PSA プロファイルに従う。
| 主張(claim) | CBOR のキー | 型 | 意味 |
|---|---|---|---|
| Nonce | 10 | bstr | サーバが送ったチャレンジそのもの |
| UEID(Universal Entity ID) | 256 | bstr | 装置の一意 ID(型バイト + 32 バイト程度)。通常、アテステーション公開鍵のハッシュから作る |
| Profile | 265 | tstr | "http://arm.com/psa/2.0.0" など。トークンの形式のバージョン |
| Client ID | 2394 | int | トークンを要求した呼び出し元の ID(非セキュア側なら負の値) |
| Security lifecycle | 2395 | uint | 装置のライフサイクル状態。0x1000 = ASSEMBLY_AND_TEST、0x2000 = PSA_ROT_PROVISIONING、0x3000 = SECURED、0x4000 = NON_PSA_ROT_DEBUG、0x6000 = DECOMMISSIONED など |
| Implementation ID | 2396 | bstr | チップ・PSA 実装の識別子(32 バイト)。「どのベンダのどのチップか」 |
| Boot seed | 2397 | bstr | 起動ごとに変わる乱数(32 バイト)。同一起動内のトークンを結びつける |
| Certification reference | 2398 | tstr | PSA Certified の認証番号(任意) |
| Software components | 2399 | array | ブート時に測定したソフトウェアの一覧(次節) |
| Verification service | 2400 | tstr | 検証サービスの URL(任意) |
| Instance ID / Hardware version | 256 系 / 2402 | — | 旧プロファイルとの互換や追加情報 |
旧プロファイル(PSA_IOT_PROFILE_1)では、キーが −75000〜−75010 の負の整数だった(arm_psa_nonce = −75008 など)。 古い TF-M や検証ツールのログに負のキーが出たら、こちらである。
3.1 ソフトウェア構成要素
トークンの核心は Software components(キー 2399)である。 ブートローダ(MCUboot——Arm 系マイコンで広く使われるオープンソースのブートローダ)が起動時に各イメージのハッシュを測り、セキュア側に渡した値がここに入る。
| 項目 | キー | 内容 |
|---|---|---|
| Measurement type | 1 | "BL2", "SPE", "NSPE" など、何を測ったか |
| Measurement value | 2 | イメージのハッシュ(SHA-256、32 バイト) |
| Version | 4 | "1.2.0" などのバージョン文字列 |
| Signer ID | 5 | そのイメージに署名した鍵のハッシュ |
| Measurement description | 6 | "SHA256" など、ハッシュのアルゴリズム |
サーバはこの配列を見て、「この装置は既知の正しいファームウェア(ハッシュが一致)を動かしているか」を判断できる。 脆弱性のある古いバージョンを動かしている装置には、更新を強制したりアクセスを拒否したりできる。
4. 署名鍵 — IAK
トークンの署名には、IAK(Initial Attestation Key、初期アテステーション鍵)という装置固有の ECDSA P-256 鍵を使う。
- 工場で装置内に生成またはプロビジョニングされ、決して外に出ない(TF-M では組み込み鍵 ID
TFM_BUILTIN_KEY_ID_IAKとして、read-only の永続鍵として扱われる) - 公開鍵は製造時にサーバ(検証サービス)に登録される。UEID は公開鍵から計算されるので、サーバは UEID から公開鍵を引ける
- 対称鍵版(HMAC で COSE_Mac0 を作る)もあるが、検証側が同じ鍵を持つことになるので通常は非対称版を使う
TF-M の開発用ビルドには公開されたテスト用 IAKが入っている。 製品では必ず差し替える(attest_key.c またはプロビジョニングバンドル)。 差し替え忘れは「誰でも正当なトークンを作れる装置」を出荷することを意味する。
5. サーバ側の検証
検証サービスが行うことを列挙する。装置側は 1 関数だが、価値は検証側で生まれる。
- COSE_Sign1 の構造を解析し、CBOR の主張を取り出す
- UEID から登録済みの IAK 公開鍵を引く
- 署名を検証する(ECDSA P-256 + SHA-256。署名対象は COSE の
Sig_structure) - Nonce が自分の送ったチャレンジと一致することを確認する(再送防止)
- Security lifecycle が
SECUREDであることを確認する(デバッグ状態の装置を拒否) - Software components の各ハッシュが許可リストにあることを確認する
- 結果(合格/不合格、その理由)をアプリケーションサーバに返す
Arm は参照実装として Veraison プロジェクト(オープンソースの検証サービス)を提供している。 開発中は、TF-M の iat-verifier(Python ツール)でトークンをデコードして中身を眺めるのが手軽である。
pip install iat-verifier # TF-M の tools/iat-verifier
check_iat -k iak_pub.pem -t PSA-2.0.0-token token.cbor -p # デコードして表示・検証6. 使いどころ
| 場面 | アテステーションの使い方 |
|---|---|
| クラウドへの初回登録(オンボーディング) | トークンを提示し、正規のハードウェア・ファームウェアであることを確認してから証明書を発行する(iotsec 編 12 章のプロビジョニング) |
| 定期的な健全性確認 | 接続のたびに、または日次でトークンを取り、ファームウェアが改変されていないか確認する |
| OTA 後の確認 | 更新後のトークンで、新しいイメージのハッシュが報告されることを確認する |
| 機密データの配布条件 | 「SECURED 状態で、バージョン X 以上のとき」だけ鍵を配る |
トークンに秘密は入っていない。装置 ID とハッシュと署名だけである。 だから TLS で暗号化していない経路で送っても、内容が漏れて困ることはない(誰が何を動かしているかは分かる)。
7. 手を動かす
トークンの構造を見る
8. 仕様書に逃がす
| 項目 | 参照先 |
|---|---|
| トークンの完全な定義 | PSA Certified Attestation API 1.0 仕様書、および IETF(インターネット標準化団体)RFC 9711(EAT)と draft-tschofenig-rats-psa-token(PSA プロファイル) |
| CBOR / COSE の詳細 | RFC 8949 / RFC 9052 |
| 対称鍵版(COSE_Mac0) | Attestation API 仕様書の "Symmetric key" 節。SYMMETRIC_INITIAL_ATTESTATION ビルドオプション |
| Measured boot の仕組み | TF-M の tfm_boot_data / MCUboot の shared data。iotsec 編 05 章 |
この章のポイント
- アテステーション = 「何のハードウェアで、何のファームウェアが、どの状態で動いているか」の署名付き申告
- 装置側は
psa_initial_attest_get_token(チャレンジ, トークン)の 1 関数。鍵も測定値も触らない - トークンは COSE_Sign1 で包んだ CBOR。中身は Nonce、UEID、ライフサイクル、ソフトウェア構成要素のハッシュ
- 署名鍵は IAK。テスト用 IAK は必ず差し替える
- 価値は検証側で生まれる: 署名、Nonce、ライフサイクル、ハッシュの許可リストを確認する