SWTPM と Docker ではじめる TPM アプリケーション開発

TPM を使ったアプリケーションを作ってみたい、でも、学習コスト...お高いんでしょう? 全宇宙で 3 名くらいの方が抱えていそうな気がするお悩みに応えるクリスマススペシャル小ネタレシピを公開します🍰

TPM ムズカシイ

TPM(Trusted Platform Module)の学習は沼です。 TPM なんぞや、どんな使い方デキル、どうやって使う、どうやって開発、どうやってデバッグ、テスト...。 浦島太郎が亀に乗って元の浜に帰ると、地上では 700 年もの年月が経過しておりましたとさ🐢。

・・・と、まではいかなくともムズカシイのは確かです。 本稿は『TPM 完全に理解した』と勘違い出来る程度の理解を促す手助けをします。 なお本稿の対象とする TPM は TPM 2.0 デバイスのみで、TPM 1.2 は一切触れません。

まず、TPM なんぞや 〜 どうやって使うまでをサクっと学習するには TPM-JS という学習コンテンツがおすすめです。

TPM-JS では TPM シミュレーターを JavaScript(WebAssembly)で動かしながら TPM の機能や使い方を学べます。 解説は英語ですし内容も簡単ではないやもですが、これ以上にわかりやすく書かれたドキュメントは存在しないと思われます。 用意されたコマンドを実行してフムフムするだけでなく、ブラウザの開発者ツールで任意のコマンドを実行してホッホーもできます。 この時点で『TPM 完全に理解した』と勘違いしてしまいそうになるほど TPM-JS は優良なコンテンツです。

が、次のステップに進もうとしたアナタは気づくでしょう。 1 ミリも手が動かない、ワタシは何も理解していなかった・・・、と。

TPM コワイ

実機 PC の TPM を触るにはちょっとした勇気が必要ですよね。 メーカーが PC 製造時に設定した情報を消してしまうんじゃないかとか、何もしてないのに壊れたとか心配が尽きません。 私はやっちゃいました。

TPM シミュレーターを使いたいところですが、自分が今アクセスしているのは実機 TPM なのかシミュレーターなのか、やや不安を覚えます。 最近は VirtualBox でも仮想 TPM がサポートされ、手軽に利用できるようになりました🙏。 しかし TPM とどのようなコマンドのやり取りをしているのか見えづらく、アプリケーション開発には今ひとつです。 TPM-JS が使用している ibmswtpm2 はもちろん素晴らしいソフトウェアですが、次の理由から私の中で選定から転げ落ちます。

  • 開発や解析に便利なオプションが無い
  • プロトコルが Microsoft TPM シミュレーターのもので、実際の TPM とわずかに異なる
    • 通信解析のノイズになってしまう
  • 動作が低速
    • 本物の TPM を模している? 個人的に開発時はサクサク動いて欲しい

SWTPM スゴイ

色々と解決してくれたのが SWTPM です。

  • 開発や解析に便利なオプションがそこそこある
  • プロトコルが実際の TPM と同じ
  • 動作が高速
  • QEMU の TPM デバイスとして使用可能
    • Windows の TPM アクセスもキャプチャ可能に(本稿では触れません、またいつか🙌)

みんな大好き Docker で環境を作っていきます。

swtpm_docker.zip をダウンロード、解凍してください。

docker buildx build -t swtpm docker または docker build -t swtpm docker コマンドで Docker イメージをビルドします。

諸々説明は省略しますが、次のようなイメージが出来上がります。

  • golang ベース
  • swtpm インストール済
  • tpm2-tools インストール済
  • tshark インストール済

次のコマンドでコンテナを起動します。

docker run --rm --name swtpm -p 127.0.0.1:2321:2321 -p 127.0.0.1:2322:2322 -v /tmp/swtpm:/swtpm -v "$PWD"/example:/src -it swtpm

MAC で動かすことは想定していなかったのですが、--privileged オプションがあれば M1 MAC でも動く..😅そうです。 うまくいけば次の状態になります。

  • SWTPM 初期セットアップ
    • EK CA(PKI)構築および SWTPM へ EK 証明書を封入
    • 大抵の実機 TPM には入っている、非常に重要な証明書
  • SWTPM を起動し、2321/tcp でアクセス待受(2322/tcp は制御用)
  • TPM アクセスブローカー 起動
    • 無くてもいい
    • クライアント --(dbus)--> TPM アクセスブローカー --(tcp)--> SWTPM で通信させる
  • TPM 通信のパケットキャプチャ開始

docker exec -it swtpm bash でコンテナに入り、tpm2-tools でアクセスしてみます。

$ tpm2_getcap -l
$ tpm2_getcap handles-nv-index
$ tpm2_nvread 0x1C00002 | openssl x509 -text -noout

次のようなキャプチャも表示されたのではないでしょうか。

    4 0.000091459    127.0.0.1 ? 127.0.0.1    TPM 90 56954 ? 2321,  [TPM Request], Command TPM2_CC_GetCapability, len(22)
    6 0.000153464    127.0.0.1 ? 127.0.0.1    TPM 95 2321 ? 56954,  [TPM Response], Response Code TPM2 Success, len(27)
   14 2.809799869    127.0.0.1 ? 127.0.0.1    TPM 90 56964 ? 2321,  [TPM Request], Command TPM2_CC_GetCapability, len(22)
   16 2.810052087    127.0.0.1 ? 127.0.0.1    TPM 285 2321 ? 56964,  [TPM Response], Response Code TPM2 Success, len(217)
   24 2.815326273    127.0.0.1 ? 127.0.0.1    TPM 127 56980 ? 2321,  [TPM Request], Command TPM2_CC_StartAuthSession, len(59)
   26 2.815440186    127.0.0.1 ? 127.0.0.1    TPM 116 2321 ? 56980,  [TPM Response], Response Code TPM2 Success, len(48)
   34 2.815725397    127.0.0.1 ? 127.0.0.1    TPM 82 56990 ? 2321,  [TPM Request], Command TPM2_CC_ContextSave, len(14)
   36 2.816002920    127.0.0.1 ? 127.0.0.1    TPM 482 2321 ? 56990,  [TPM Response], Response Code TPM2 Success, len(414)
   44 2.816224526    127.0.0.1 ? 127.0.0.1    TPM 82 56992 ? 2321,  [TPM Request], Command TPM2_CC_NV_ReadPublic, len(14)
   46 2.816315814    127.0.0.1 ? 127.0.0.1    TPM 130 2321 ? 56992,  [TPM Response], Response Code TPM2 Success, len(62)
   54 2.816787355    127.0.0.1 ? 127.0.0.1    TPM 90 57008 ? 2321,  [TPM Request], Command TPM2_CC_GetCapability, len(22)
   56 2.816867838    127.0.0.1 ? 127.0.0.1    TPM 95 2321 ? 57008,  [TPM Response], Response Code TPM2 Success, len(27)
   64 2.817222671    127.0.0.1 ? 127.0.0.1    TPM 82 57022 ? 2321,  [TPM Request], Command TPM2_CC_NV_ReadPublic, len(14)
   66 2.817270778    127.0.0.1 ? 127.0.0.1    TPM 130 2321 ? 57022,  [TPM Response], Response Code TPM2 Success, len(62)
   74 2.817688609    127.0.0.1 ? 127.0.0.1    TPM 82 57038 ? 2321,  [TPM Request], Command TPM2_CC_NV_ReadPublic, len(14)
   76 2.817767972    127.0.0.1 ? 127.0.0.1    TPM 130 2321 ? 57038,  [TPM Response], Response Code TPM2 Success, len(62)
   84 2.818151319    127.0.0.1 ? 127.0.0.1    TPM 82 57048 ? 2321,  [TPM Request], Command TPM2_CC_NV_ReadPublic, len(14)
   86 2.818228862    127.0.0.1 ? 127.0.0.1    TPM 130 2321 ? 57048,  [TPM Response], Response Code TPM2 Success, len(62)
   94 2.822557343    127.0.0.1 ? 127.0.0.1    TPM 482 57056 ? 2321,  [TPM Request], Command TPM2_CC_ContextLoad, len(414)
   96 2.822759508    127.0.0.1 ? 127.0.0.1    TPM 82 2321 ? 57056,  [TPM Response], Response Code TPM2 Success, len(14)
  104 2.823039363    127.0.0.1 ? 127.0.0.1    TPM 167 57066 ? 2321,  [TPM Request], Command TPM2_CC_NV_Read[Malformed Packet]
  106 2.823490764    127.0.0.1 ? 127.0.0.1    TPM 1169 2321 ? 57066,  [TPM Response], Response Code TPM2 Success[Malformed Packet]
  114 2.824105010    127.0.0.1 ? 127.0.0.1    TPM 82 57072 ? 2321,  [TPM Request], Command TPM2_CC_ContextSave, len(14)
  116 2.824300867    127.0.0.1 ? 127.0.0.1    TPM 482 2321 ? 57072,  [TPM Response], Response Code TPM2 Success, len(414)
  124 2.826306139    127.0.0.1 ? 127.0.0.1    TPM 82 57088 ? 2321,  [TPM Request], Command TPM2_CC_FlushContext, len(14)
  126 2.826364381    127.0.0.1 ? 127.0.0.1    TPM 78 2321 ? 57088,  [TPM Response], Response Code TPM2 Success, len(10)

ホスト側で次のようなコマンドを実行すると wireshark でもリアルタイムに表示できます。

tail -n +0 -f /tmp/swtpm/pcap/default.pcap | wireshark -ki -

wireshark(tshark)には TPM 2.0 の dissector が実装されており、ある程度の解析が可能です。

tpm2-tools のコマンドを組み合わせることで、TPM に関してやりたいことがほぼ確認できるかと思います。 仕上げにクロスプラットフォームな TPM アプリケーション開発ぽいことをやっていきます。

https://github.com/google/go-tpm を使ったサンプルを zip ファイルに同梱しましたので、それを使います。 先程の Docker 内で次のコマンドを実行してください。

$ cd /src
$ go mod tidy
$ go run .

次のような結果が表示され、キャプチャもできたのではないでしょうか。

root@fdc9f5f8cefb:/src# go run .
2023/12/19 03:29:09 *** [0] 1c00002 ***
2023/12/19 03:29:09 NV Pub: {NVIndex:29360130 NameAlg:SHA256 Attributes:PPRead + PlatformCreate + PPWrite + AuthRead + No Do + Writte + WriteDefine + OwnerRead AuthPolicy:[] DataSize:1016}
2023/12/19 03:29:09 Cert: issuer=CN=swtpm-localca subject=CN=unknown
2023/12/19 03:29:09 *** [1] 1c00016 ***
2023/12/19 03:29:09 NV Pub: {NVIndex:29360150 NameAlg:SHA256 Attributes:PlatformCreate + PPRead + AuthRead + PPWrite + No Do + Writte + OwnerRead + WriteDefine AuthPolicy:[] DataSize:842}
2023/12/19 03:29:09 Cert: issuer=CN=swtpm-localca subject=CN=unknown

TPM 完全に理解した

ここまで無事実行でき、"完全に理解した" と勘違いできた方が 3 名ほどいらっしゃれば幸いです。

サイバーディフェンス研究所では TPM リモートアテステーション技術を信頼の起点としたゼロトラストシステム PIV Gateway™ の研究開発を行っています。 今後も認証認可に関わる技術情報や製品情報をお届けしていきたいと思います。 製品に関する情報などは当社ホームページお問合せフォームからお気軽にお声がけ頂ければ幸いです。 PIV Gateway™CA および TPM の販売を開始しております。

それでは、よい TPM ライフを👋

© 2016 - 2024 DARK MATTER / Built with Hugo / Theme Stack designed by Jimmy