PSA APIs 12 · 永続鍵とライフタイム — 電源を切っても残る鍵の扱い

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)を伴い、そして何より消し忘れると残り続ける。

揮発鍵と永続鍵揮発(VOLATILE = 0、既定)RAM のみ。ID は実装が割り当てる。destroy・電源断・mbedtls_psa_crypto_free で消える。セッション鍵、一時 ECDH 鍵、毎回 import する公開鍵永続(PERSISTENT = 1)ITS に保存。ID は自分で決める(1〜0x3FFFFFFF)。destroy するまで残る。作るのは 1 回だけ。装置の署名鍵、長期の共有鍵、工場書き込みの秘密「次の起動でも同じ鍵が要る」ときだけ永続にする
既定は揮発。永続鍵はストレージを使い、消し忘れると残り続ける

2. 寿命の中身 — 持続性と場所

03 章で述べたとおり、psa_key_lifetime_t は 2 つの情報を持つ。

\[ \text{lifetime} = (\text{location} \ll 8) \mid \text{persistence} \]
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_VOLATILE0x00揮発
PSA_KEY_PERSISTENCE_DEFAULT0x01永続。通常の不揮発保存
PSA_KEY_PERSISTENCE_READ_ONLY0xff永続かつ破棄不能。工場で焼かれた鍵、ハードウェアの固有鍵。psa_destroy_key は NOT_PERMITTED
0x02〜0xfe—実装定義(例: 「ファームウェア更新まで有効」など)
場所(上位 24 ビット)値意味
PSA_KEY_LOCATION_LOCAL_STORAGE0x000000PSA 実装自身が管理する(Mbed TLS のメモリ、または ITS)
PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT0x000001主セキュアエレメント。鍵の値はそのチップの中から出ない
0x000002〜0x7fffff—追加のセキュアエレメント、暗号アクセラレータなど(実装定義)
0x800000〜—ベンダ定義

場所が 0 以外の鍵は、「ドライバ」が処理する(15 章)。 ST の STSAFE、NXP の SE05x、Infineon の OPTIGA といった外付けセキュアエレメントに鍵を置くとき、 アプリケーションのコードはこの lifetime を指定する以外、何も変わらない。 psa_sign_hash() を呼べば、実装が「この鍵はセキュアエレメントにある」と判断してそのチップに署名を依頼する。 これが PSA の「実装の差をアプリケーションから隠す」設計の、最も価値のある部分である。

lifetime = (location << 8) | persistencelocation 24 ビットpersistence 8PSA_KEY_LIFETIME_VOLATILE = 0x00000000PSA_KEY_LIFETIME_PERSISTENT = 0x00000001FROM_PERSISTENCE_AND_LOCATION(DEFAULT, PRIMARY_SECURE_ELEMENT) = 0x00000101FROM_PERSISTENCE_AND_LOCATION(READ_ONLY, LOCAL_STORAGE) = 0x000000ff場所が 0 以外の鍵は「ドライバ」が処理するpsa_sign_hash(key, …) を呼ぶと、実装が鍵の場所を見てセキュアエレメントに署名を依頼する。アプリのコードは変わらない
上位が「どこに置くか」、下位が「残るか」。場所を変えるだけでセキュアエレメントに移る

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 鍵 */
範囲誰が使うか
0PSA_KEY_ID_NULL(鍵なし)
0x00000001〜0x3FFFFFFFアプリケーション(永続鍵)
0x40000000〜0x7FFFFFFF実装(揮発鍵の自動 ID、組み込み鍵、ベンダ用)
0x80000000〜実装(さらに予約)
psa_key_id_t の範囲0NULL0x00000001 〜 0x3FFFFFFF: アプリケーション(永続鍵)PSA_KEY_ID_USER_MIN 〜 USER_MAX0x40000000 〜 0x7FFFFFFF: 実装揮発鍵の自動 ID、組み込み鍵0x80000000 〜予約#define KEY_ID_DEVICE_SIGN ((psa_key_id_t)0x00010001) /* 区分 0x0001: 装置固有 */#define KEY_ID_OTA_VERIFY_PUB ((psa_key_id_t)0x00020001) /* 区分 0x0002: 検証用公開鍵 */#define KEY_ID_CONFIG_AEAD ((psa_key_id_t)0x00030001) /* 区分 0x0003: データ保護 */上位 16 ビットを区分、下位を通し番号にして、プロジェクトの 1 つのヘッダで管理する
永続鍵の ID はアプリケーション範囲から選び、台帳で一元管理する

4. 永続鍵はどこにどう保存されているか

Mbed TLS の場合、MBEDTLS_PSA_CRYPTO_STORAGE_C を有効にすると、永続鍵は ITS(Internal Trusted Storage)の API(13 章)を通して保存される。

つまり、永続鍵の安全性は「ITS がどこにあるか」で決まる。 Mbed TLS 単体をマイコンに載せ、ITS をアプリケーションと同じフラッシュに置いた場合、鍵はフラッシュ読み出し保護がなければ丸見えである。 「PSA を使ったから安全」ではなく「PSA + TF-M + フラッシュ読み出し保護、またはセキュアエレメント」で初めて鍵が守られる。

永続鍵はどこにあるか — 環境で安全性が変わるMbed TLS(PC)MBEDTLS_PSA_ITS_FILE_C: カレントディレクトリのファイル。平文。保護は OS のファイル権限のみMbed TLS 単体(マイコン)自前の ITS で内蔵フラッシュに。平文。フラッシュ読み出し保護(RDP 等)がなければ丸見えTF-MITS パーティションのフラッシュ領域。非セキュア側から読めない。平文だが「内部にあるから信頼」セキュアエレメント(場所 ≠ 0)ITS にはスロット番号だけ。鍵の値はチップから出ない結論「PSA を使ったから安全」ではなく「PSA + TF-M + 読み出し保護、またはセキュアエレメント」で鍵が守られる永続鍵の安全性 = ITS がどこにあるか
同じ psa_generate_key でも、鍵の置かれる場所は環境で全く違う

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()セキュアエレメント内のスロット番号を得る(ドライバ開発向け)

この章のポイント