Chapter 12
永続鍵とライフタイム — 電源を切っても残る鍵の扱い
この章のゴール.
寿命(lifetime)の 32 ビットが持続性と場所に分かれていることを理解し、 永続鍵の ID を設計し、「揮発鍵と永続鍵のどちらにするか」を目的から決められるようになること。 永続鍵がどこに、どう保存されているかを知り、その安全性の限界を説明できること。
この章で使う既出の用語(定義は各リンク先). PSA(01 章 1 節)、ビット(02 章 4 節)、場所(03 章 7 節)、持続性(03 章 7 節)、import(04 章 10 節)、作成(04 章 1 節)、使用(04 章 1 節)、破棄(04 章 1 節)、MAC(06 章 1 節)、AES(07 章 1 節)、平文(08 章 1 節)、認証(09 章 1 節)、ECDH(11 章 1 節)、共有秘密(11 章 1 節)、鍵合意(11 章 1 節)
1. 揮発鍵と永続鍵
| 揮発鍵(volatile) | 永続鍵(persistent) | |
|---|---|---|
| 寿命定数 | PSA_KEY_LIFETIME_VOLATILE(0) | PSA_KEY_LIFETIME_PERSISTENT(1) |
| ID | 実装が割り当てる(psa_import_key の出力) | 自分で決めて psa_set_key_id() |
| 保存先 | RAM のみ | 不揮発ストレージ(ITS。13 章) |
| 消えるとき | psa_destroy_key()、mbedtls_psa_crypto_free()、電源断 | psa_destroy_key() のみ |
| 作る回数 | 起動ごと | 1 回だけ(2 回目は ALREADY_EXISTS) |
| 向く用途 | セッション鍵、一時 ECDH 鍵、毎回 import する公開鍵 | 装置の署名鍵、長期の共有鍵、工場書き込みの秘密 |
「揮発が既定」である。永続にするのは「次の起動でも同じ鍵が要る」ときだけにする。 永続鍵はストレージを消費し、作成にフラッシュ書き込み(数 ms)を伴い、そして何より消し忘れると残り続ける。
2. 寿命の中身 — 持続性と場所
03 章で述べたとおり、psa_key_lifetime_t は 2 つの情報を持つ。
psa_key_lifetime_t lt = PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
PSA_KEY_PERSISTENCE_DEFAULT, /* 永続 */
PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT); /* セキュアエレメントに置く */
psa_set_key_lifetime(&attr, lt);
/* 分解 */
PSA_KEY_LIFETIME_GET_PERSISTENCE(lt); /* 1 */
PSA_KEY_LIFETIME_GET_LOCATION(lt); /* 1 */
PSA_KEY_LIFETIME_IS_VOLATILE(lt); /* 0 */| 持続性(下位 8 ビット) | 値 | 意味 |
|---|---|---|
PSA_KEY_PERSISTENCE_VOLATILE | 0x00 | 揮発 |
PSA_KEY_PERSISTENCE_DEFAULT | 0x01 | 永続。通常の不揮発保存 |
PSA_KEY_PERSISTENCE_READ_ONLY | 0xff | 永続かつ破棄不能。工場で焼かれた鍵、ハードウェアの固有鍵。psa_destroy_key は NOT_PERMITTED |
| 0x02〜0xfe | — | 実装定義(例: 「ファームウェア更新まで有効」など) |
| 場所(上位 24 ビット) | 値 | 意味 |
|---|---|---|
PSA_KEY_LOCATION_LOCAL_STORAGE | 0x000000 | PSA 実装自身が管理する(Mbed TLS のメモリ、または ITS) |
PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT | 0x000001 | 主セキュアエレメント。鍵の値はそのチップの中から出ない |
| 0x000002〜0x7fffff | — | 追加のセキュアエレメント、暗号アクセラレータなど(実装定義) |
| 0x800000〜 | — | ベンダ定義 |
場所が 0 以外の鍵は、「ドライバ」が処理する(15 章)。 ST の STSAFE、NXP の SE05x、Infineon の OPTIGA といった外付けセキュアエレメントに鍵を置くとき、 アプリケーションのコードはこの lifetime を指定する以外、何も変わらない。 psa_sign_hash() を呼べば、実装が「この鍵はセキュアエレメントにある」と判断してそのチップに署名を依頼する。 これが PSA の「実装の差をアプリケーションから隠す」設計の、最も価値のある部分である。
3. 鍵 ID の設計
永続鍵の ID は PSA_KEY_ID_USER_MIN(1)〜 PSA_KEY_ID_USER_MAX(0x3FFFFFFF) の範囲で自分で決める。 プロジェクトの中で1 つのヘッダに集める。
/* keys.h — プロジェクト全体の鍵 ID 台帳 */
#define KEY_ID_DEVICE_SIGN ((psa_key_id_t)0x00010001) /* 装置認証用 ECDSA P-256 鍵ペア。工場で生成 */
#define KEY_ID_DEVICE_ECDH ((psa_key_id_t)0x00010002) /* 静的 ECDH 用(使うなら) */
#define KEY_ID_OTA_VERIFY_PUB ((psa_key_id_t)0x00020001) /* 更新イメージ検証用の公開鍵 */
#define KEY_ID_CONFIG_AEAD ((psa_key_id_t)0x00030001) /* 設定領域の AES-GCM 鍵 */
#define KEY_ID_LOG_MAC ((psa_key_id_t)0x00030002) /* ログの HMAC 鍵 */- 上位 16 ビットを「区分」(0x0001 = 装置固有、0x0002 = 検証用公開鍵、0x0003 = データ保護)、下位 16 ビットを通し番号にすると整理しやすい
- 0x40000000 以上は使わない。TF-M の組み込み鍵(ハードウェア固有鍵、アテステーション鍵)は 0x7FFF0000 前後に置かれることが多く、Mbed TLS は揮発鍵にこの範囲の ID を割り当てる
- 同じ ID を「別のプロジェクト、別のファームウェア」で違う意味に使わない。ストレージに残った古い鍵を新しいコードが「自分の鍵」だと思って使う事故が起きる
- 鍵 ID は秘密ではない。分かっても鍵は使えない(TF-M では、他のクライアントが作った鍵は ID を知っていても使えない。16 章)
| 範囲 | 誰が使うか |
|---|---|
| 0 | PSA_KEY_ID_NULL(鍵なし) |
| 0x00000001〜0x3FFFFFFF | アプリケーション(永続鍵) |
| 0x40000000〜0x7FFFFFFF | 実装(揮発鍵の自動 ID、組み込み鍵、ベンダ用) |
| 0x80000000〜 | 実装(さらに予約) |
4. 永続鍵はどこにどう保存されているか
Mbed TLS の場合、MBEDTLS_PSA_CRYPTO_STORAGE_C を有効にすると、永続鍵は ITS(Internal Trusted Storage)の API(13 章)を通して保存される。
- PC 上の Mbed TLS では、
MBEDTLS_PSA_ITS_FILE_Cによりカレントディレクトリに00000000<id>のようなファイルが作られる。平文である(保護は OS のファイル権限だけ) - マイコンで TF-M を使う場合、ITS はセキュア側のフラッシュ領域に置かれ、非セキュア側からは読めない。さらに TF-M の ITS は、書き込むデータを暗号化しない(「Internal Trusted」=内部にあるから信頼する)——チップ内部フラッシュの読み出し保護(RDP など)が安全性の根拠になる
- セキュアエレメントに置いた鍵(場所 ≠ 0)は、ストレージには鍵の値ではなく、セキュアエレメント内のスロット番号だけが保存される
つまり、永続鍵の安全性は「ITS がどこにあるか」で決まる。 Mbed TLS 単体をマイコンに載せ、ITS をアプリケーションと同じフラッシュに置いた場合、鍵はフラッシュ読み出し保護がなければ丸見えである。 「PSA を使ったから安全」ではなく「PSA + TF-M + フラッシュ読み出し保護、またはセキュアエレメント」で初めて鍵が守られる。
5. 永続鍵の運用パターン
5.1 初回起動で生成する
04 章の「あれば使う、なければ作る」である。工場で個別に鍵を書き込む必要がなく、鍵が装置の外に一度も出ない。 公開鍵はその後、装置が自分でサーバに登録する(または製造ラインで psa_export_public_key() して取り出す)。
5.2 製造時に注入する
共有秘密(マスター鍵から導出した装置鍵など)は、製造ラインで psa_import_key() により永続鍵として書き込む。 注入用のコードは製品ファームウェアから外し、ライフサイクル(iotsec 編 14 章)を「Secured」に進めてから出荷する。
5.3 更新する
「鍵を差し替える」には psa_destroy_key() してから同じ ID で作り直す。 その間に電源が切れると鍵がない状態になるので、新しい鍵を別 ID で作ってから、参照を切り替え、古い鍵を消す(2 段階)ほうが安全である。
5.4 揮発鍵を永続化する
導出や鍵合意で作った揮発鍵を保存したいなら、psa_copy_key()(04 章)で寿命だけ変えた複製を作る(元の鍵に PSA_KEY_USAGE_COPY が要る)。 または、導出時の output_key() の属性に最初から永続寿命と ID を指定する。
6. 起動シーケンスとの関係
永続鍵は psa_crypto_init() の時点では読み込まれない。 初めてその ID が使われたときにストレージから読まれ、以後メモリにキャッシュされる(psa_purge_key() で追い出せる)。 だから起動は速いが、最初の署名だけ数 ms 遅いことがある。 起動直後の応答時間が厳しいなら、初期化中に psa_get_key_attributes() を呼んで先に読み込ませる。
TF-M では、鍵スロット数(MBEDTLS_PSA_KEY_SLOT_COUNT、既定 32 程度)に上限がある。 永続鍵を数十個も同時に開くと PSA_ERROR_INSUFFICIENT_MEMORY になる。 使い終わった永続鍵は psa_purge_key() でスロットを空ける。
7. 手を動かす
ライフタイムと鍵 ID を組み立てる
8. 仕様書に逃がす
| 関数・定数 | 用途 |
|---|---|
PSA_KEY_LIFETIME_IS_READ_ONLY(lt) | 破棄不能かどうか |
PSA_KEY_ID_VENDOR_MIN / PSA_KEY_ID_VENDOR_MAX | 実装側の ID 範囲 |
mbedtls_svc_key_id_make(owner, id) / MBEDTLS_SVC_KEY_ID_GET_KEY_ID() | Mbed TLS の「所有者付き鍵 ID」(TF-M 環境で内部的に使う) |
psa_get_key_slot_number() | セキュアエレメント内のスロット番号を得る(ドライバ開発向け) |
この章のポイント
- 既定は揮発。次の起動でも要る鍵だけを永続にする
- 寿命 = 場所(上位 24 ビット)+ 持続性(下位 8 ビット)。場所を変えるだけで鍵がセキュアエレメントに移り、アプリケーションのコードは変わらない
- 永続鍵の ID は 1〜0x3FFFFFFF をプロジェクトの台帳で一元管理
- 永続鍵の安全性は ITS がどこにあるかで決まる。Mbed TLS 単体のファイル ITS は平文
- 永続鍵は初回使用時に読み込まれる。差し替えは 2 段階で