PSA APIs 18 · 落とし穴とチェックリスト — 出荷前に確かめること

Chapter 18

落とし穴とチェックリスト — 出荷前に確かめること

この章のゴール.

PSA を使ったコードで実際に起きる失敗を、エラーコード別・設計別に整理し、 レビューで確認する項目を持つこと。 そして本シリーズで扱わなかった API を、名前と参照先だけ把握すること。

この章で使う既出の用語(定義は各リンク先). PSA(01 章 1 節)、認証制度(01 章 1 節)、サイズマクロ(02 章 4 節)、操作オブジェクト(02 章 5 節)、algorithm(03 章 11 節)、type(03 章 11 節)、usage(03 章 11 節)、場所(03 章 7 節)、DER(04 章 2 節)、generate(04 章 10 節)、import(04 章 10 節)、破棄(04 章 1 節)、error(05 章 4 節)、ハッシュ(05 章 1 節)、乱数(05 章 1 節)、HMAC-SHA256(06 章 1 節)、AES(07 章 1 節)、CTR(07 章 9 節)、対称暗号(07 章 1 節)、カウンタ(08 章 4 節)、ノンス(08 章 1 節)、平文(08 章 1 節)、チャレンジ(09 章 5 節)、HKDF(10 章)、info(10 章 3 節)、パスワード(10 章 2 節)、ECDH(11 章 1 節)、共有秘密(11 章 1 節)、ITS(13 章 1 節)、IAK(14 章 4 節)、Profile(14 章 3 節)、トークン(14 章)、ドライバ(15 章)、ベニア(16 章 1 節)

1. エラーコード別の原因表

デバッグ中に最初に見るのはエラーコードである。コード → 原因の逆引きを、遭遇頻度の順に並べる。

エラー原因(頻度順)
NOT_PERMITTED (−133)① 鍵の usage に必要なフラグがない(署名に SIGN_HASH、MAC に SIGN_MESSAGE、導出に DERIVE、export_key に EXPORT) ② 鍵の algorithm と操作のアルゴリズムが不一致(ECDH vs KEY_AGREEMENT(ECDH, HKDF)、GCM vs CTR、ECDSA(SHA_256) vs ECDSA(SHA_384)) ③ WRITE_ONCE のストレージに再書き込み ④ read-only 鍵の破棄 ⑤ TF-M で他クライアントの鍵
INVALID_ARGUMENT (−135)① import するバイト列の形式・長さが type と合わない(PEM を渡した、DER の包装を外していない、公開鍵の 0x04 がない) ② sign_hash のハッシュ長がアルゴリズムと不一致 ③ 鍵長が不正(Curve25519 に 256、P-521 に 512) ④ 揮発鍵に ID を設定、永続鍵に ID 未設定 ⑤ AEAD のノンス長が規定外 ⑥ psa_hash_compare に長さ違いの期待値 ⑦ CBC_NO_PADDING に 16 の倍数でない入力
NOT_SUPPORTED (−134)① PSA_WANT_* の宣言漏れ(特に KEY_PAIR_GENERATE / _EXPORT) ② 曲線の宣言漏れ(PSA_WANT_ECC_SECP_R1_256) ③ TF-M のプロファイルで非対称暗号が無効(Profile Small) ④ ドライバがそのアルゴリズムを持たず、ソフトウェア実装も無効
BAD_STATE (−137)① psa_crypto_init() 忘れ ② 分割操作の順序違反(set_iv の前に update、update_ad を update の後、sign_setup に verify_finish) ③ エラー後に abort せず再利用 ④ 未初期化の操作オブジェクト
BUFFER_TOO_SMALL (−138)① サイズマクロを使わず決め打ち ② cipher_encrypt の出力に IV 分(16)を足していない ③ aead_encrypt の出力にタグ分(16)を足していない ④ RSA 鍵のエクスポートで DER のサイズを見誤り
INVALID_HANDLE (−136)① 未初期化の psa_key_id_t(0) ② 破棄済みの鍵 ③ 永続鍵の ID を間違えた ④ TF-M で別クライアントの鍵 ⑤ 実装によっては存在しない永続鍵(DOES_NOT_EXIST の代わりに返る)
INVALID_SIGNATURE (−149)① 本当に改ざん・偽造 ② 鍵・アルゴリズム・データのどれかが送信側と違う ③ AEAD の AD やノンスが違う ④ ECDSA 署名の形式(DER を raw として渡した) ⑤ ハッシュを取った範囲が違う
ALREADY_EXISTS (−139)永続鍵の ID がすでに使われている(前回の実行の残り)。「あれば使う」に直す
INSUFFICIENT_MEMORY (−141)① 鍵スロット上限(MBEDTLS_PSA_KEY_SLOT_COUNT) ② TF-M の CRYPTO_ENGINE_BUF_SIZE ③ 揮発鍵の破棄漏れ(リーク——使い終わっても解放されず溜まっていくこと)
INSUFFICIENT_STORAGE (−142)ITS/PS の領域が満杯、または ITS_MAX_ASSET_SIZE 超え
INSUFFICIENT_ENTROPY (−148)エントロピー源が未接続(15 章 3 節)
PROGRAMMER_ERROR (−129)TF-M でセキュア側のメモリやフラッシュ定数を指すポインタを渡した
COMMUNICATION_FAILURE (−145)セキュアエレメントの I²C/SPI 応答なし。TF-M のベニア呼び出しが割り込み中に行われた
エラーコードから原因への最短経路NOT_PERMITTED→ 鍵の usage / algorithmINVALID_ARGUMENT→ バイト列の形式・長さNOT_SUPPORTED→ PSA_WANT_* の宣言BAD_STATE→ init 忘れ・順序BUFFER_TOO_SMALL→ サイズマクロ(IV・タグ分)INVALID_HANDLE→ ID 0・破棄済み・他クライアントINVALID_SIGNATURE→ 改ざん、または鍵・AD・形式の不一致PROGRAMMER_ERROR→ TF-M: ポインタの領域赤: コードを直す。緑: 設定・環境を直す。灰: データや設計で対処するpsa_constant_names(Mbed TLS の programs/psa)で数値を定数名に戻せる
最初の 1 つの当たりをつけるための表

2. 設計の落とし穴

エラーコードにならない——動くが安全でない——失敗のほうが危険である。

落とし穴なぜ危険か正しい形
rand() や時刻をノンス・鍵・チャレンジに使う予測できる。ECDSA なら秘密鍵が漏れるpsa_generate_random() / psa_generate_key()
AEAD のノンスがカウンタで、再起動で 0 に戻る同じ鍵・同じノンスで GCM の認証鍵が漏れる起動世代を含める、またはカウンタを ITS に周期保存
対称暗号(psa_cipher_*)だけで「暗号化」改ざん検出なし。復号は失敗しないAEAD
MAC の検証を psa_mac_compute + memcmp でタイミング攻撃psa_mac_verify
署名検証の公開鍵が書き換え可能な場所にある公開鍵を差し替えれば任意のイメージが通るWRITE_ONCE ITS、read-only 鍵、ブートローダ埋め込み
検証用公開鍵をサーバから受け取って使う信頼の起点が「そのサーバとの接続」に依存する工場で書き込む
1 つの鍵を複数用途で使う(署名と ECDH、暗号化と MAC)用途混同攻撃鍵ごとに用途 1 つ。KDF で分ける
ECDH の共有秘密をそのまま AES 鍵に偏りがある。毎回同じKDF を通す
KDF の info を省略送信鍵 = 受信鍵(反射攻撃)方向・用途を info に
EXPORT を「とりあえず」付ける乗っ取られたコードが鍵を読める理由を説明できる鍵だけに
戻り値を無視して次へ進む暗号化したつもりで平文送信、検証したつもりで未検証PSA_CHECK と goto cleanup
AEAD 分割復号で verify 前の出力を使う改ざんデータを処理するverify 成功まで保留、または失敗時に無効化
OTA でバージョン比較をしない署名の正しい古い脆弱イメージに戻せる単調増加のバージョンを ITS に
PC の Mbed TLS(ファイル ITS)の感覚でマイコンに載せる永続鍵が平文でフラッシュにあるTF-M、フラッシュ読み出し保護、セキュアエレメント
テスト用 IAK / MCUboot 鍵のまま出荷誰でも正当なトークン・イメージを作れるプロビジョニングで差し替え
割り込みハンドラから PSA を呼ぶミューテックス・フラッシュ書き込みで破綻タスクに委譲
操作オブジェクトを memcpyハードウェア状態が複製されないpsa_hash_clone のみ可

3. パフォーマンスの目安

「遅い」と感じたときの当たりをつける数字である(Cortex-M33 100 MHz、ソフトウェア実装、-Os。ハードウェアアクセラレータで AES/SHA は 10 倍以上速くなる)。

操作時間の目安
SHA-256(1 KB)0.1〜0.2 ms
AES-128-GCM(1 KB)0.3〜0.6 ms
HMAC-SHA256(64 B)20〜40 µs
ECDSA P-256 署名20〜60 ms
ECDSA P-256 検証40〜100 ms
ECDH P-25620〜60 ms
P-256 鍵生成20〜60 ms
RSA-2048 署名300〜1000 ms
RSA-2048 検証10〜30 ms
RSA-2048 鍵生成5〜60 秒(ばらつく)
TF-M 越しの呼び出し 1 回のオーバーヘッド5〜20 µs
ITS 書き込み(小)1〜10 ms(フラッシュ消去を伴うと数十 ms)

ECC の計算は MBEDTLS_ECP_WINDOW_SIZE / MBEDTLS_ECP_FIXED_POINT_OPTIM で 2 倍程度、ハードウェア ECC アクセラレータで 10 倍程度変わる。 割り込みを長時間止める処理の中で署名を呼ばない。中断可能な署名 API(09 章)はこのためにある。

4. 本シリーズで扱わなかった API

「そういうものがある」と知っておくだけで、必要になったときに仕様書を引ける。

API / 関数群何か参照先
PAKE(psa_pake_*)パスワード認証鍵交換。SPAKE2+(Matter)、EC-JPAKE(Thread)Crypto API 1.1 拡張 "PAKE"
中断可能な署名(psa_sign_hash_start/complete 等)長い署名を分割実行Crypto API 1.1 "Interruptible operations"
鍵の包み込み(psa_wrap_key / psa_unwrap_key)AES-KW で鍵を包むCrypto API 1.3
暗号化された鍵の import(psa_import_key の拡張、psa_generate_key_custom)生成パラメータCrypto API 1.2
SP 800-108 KDF、XChaCha20-Poly1305、SHAKE追加アルゴリズムCrypto API 1.2 / 1.3
Firmware Update API(psa_fwu_start / write / finish / install / accept / reject / query / clean)更新イメージの受け取りとスロット切替を標準化。TF-M の FWU パーティションが MCUboot と連携PSA Firmware Update API 1.0
Platform サービス(tfm_platform_system_reset、tfm_platform_ioctl、NV カウンタ)TF-M 固有。リセット、NV カウンタ(ロールバック番号)の読み書きTF-M docs "Platform Service"
FF-M クライアント API(psa_framework_version、psa_version、psa_connect、psa_call、psa_close)自作パーティションとの通信FF-M 1.1
PSA Certified Crypto API for ML / PQC 拡張ML-KEM / ML-DSA(ポスト量子暗号)を扱う PSA_ALG_ML_DSA / PSA_KEY_TYPE_ML_KEM などCrypto API 1.3 以降の拡張(2025 年時点で仕様策定中〜初期実装)
Secure Element ドライバの旧インタフェース(psa_drv_se_*)3.x の古い SE ドライバ API。非推奨Mbed TLS docs
本編で扱った範囲と、名前だけ知っておく範囲本編で扱った(日常の 9 割)鍵管理: import / generate / export_public_key / destroy / get_key_attributesハッシュ・MAC・cipher・AEAD の一発関数と分割関数署名: sign_hash / verify_hash / sign_message / verify_message鍵導出: HKDF / PBKDF2、鍵合意: ECDHストレージ: ITS / PS の 4 関数、アテステーション: get_tokenMbed TLS の設定・乱数源・ドライバ、TF-M の構造・ビルドpsa_generate_random、psa_status_t、サイズマクロ名前と参照先だけPAKE(SPAKE2+ / EC-JPAKE)中断可能な署名wrap_key / unwrap_keyFirmware Update APIFF-M クライアント APISP 800-108、XChaCha、SHAKEポスト量子(ML-KEM / ML-DSA)旧 SE ドライバ(psa_drv_se_*)
右側は必要になったときに仕様書を引く

5. 出荷前チェックリスト

レビュー用チェックリスト

6. 学び続けるために


この章のポイント

これで全 18 章は終わりである。シリーズの目次に戻る。