課題
SSHクライアントがサーバーに接続するとき、中間者攻撃者ではなく本物のサーバーと通信していることを確認する必要があります。従来のSSHでは、クライアントが初回接続時に生のホスト鍵を記憶することでこれに対処してきました。単一のマシンであればこれで機能しますが、多数のデバイスを扱う環境ではスケールせず、事前に信頼関係を確立する手段もありません。さらにサーバーの秘密鍵の問題もあります。秘密鍵がディスク上のファイルとして存在する場合、サーバーを侵害した攻撃者はその鍵をコピーし、別の場所でそのデバイスになりすますことができてしまいます。
追加した機能
wolfSSHに、ホスト鍵としてX.509証明書を使い、対応する秘密鍵をTPM内部に封印したままサーバーを動作させる機能を追加しました。これにより上記の2つの課題を同時に解決できます。証明書はクライアントがあらかじめ信頼しているCAによって署名されているため、クライアントは初回接続時に推測するのではなく、事前にサーバーの身元を検証します。秘密鍵はTPM内部で生成され、TPMの外に出ることは決してありません。そのため、サーバーが完全に侵害された場合であっても、攻撃者に鍵を渡すことはできません。SSHの鍵交換ではTPMが交換ハッシュに署名し、鍵のソフトウェア上のコピーは一切存在しません。ECDSAとRSAの両方に対応しています。
サーバー側の実装は2回の関数呼び出しだけです。証明書が鍵に紐づくよう、まずTPM鍵をバインドし、次に証明書をロードします。
wolfSSH_CTX_UseTpmHostKey(ctx, &tpmDev, &tpmKey);
wolfSSH_CTX_UseCert_buffer(ctx, certDer, certDerSz, WOLFSSH_FORMAT_ASN1);
クライアント側では、信頼するCAをロードし、証明書ホスト鍵アルゴリズムを必須に設定します。これにより、接続が気付かないうちに通常の鍵にフォールバックし、CAの検証を省略してしまうことを防ぎます。
wolfSSH_CTX_SetAlgoListKey(ctx, "x509v3-ecdsa-sha2-nistp256,x509v3-ssh-rsa");
wolfSSH_CTX_AddRootCert_buffer(ctx, caDer, caDerSz, WOLFSSH_FORMAT_ASN1);
実際のTPMを使い、エンドツーエンドで動作を検証しました。正しいCAを設定した場合、クライアントは接続してデータを送受信します。無関係なCAを設定した場合、クライアントは接続を拒否します。これが中間者攻撃を実際に阻止する動作です。上記の2つのケースは、ECDSAとRSAのどちらでも期待どおりに動作することを確認しました。
試してみる
証明書とTPMのサポートを有効にして、wolfSSL、wolfTPM、wolfSSHをビルドします。
wolfSSL: ./configure --enable-wolfssh --enable-wolftpm --enable-keygen \
--enable-certgen --enable-certreq --enable-certext \
--enable-cryptocb \
CFLAGS="-DWC_RSA_NO_PADDING"
wolfTPM: ./configure --enable-fwtpm --enable-swtpm
wolfSSH: ./configure --enable-tpm --enable-certs
TPMシミュレータ(wolfTPMのfwtpmサーバーまたはibmswtpm2)を起動し、新しいサンプルを実行します。
$ ./examples/tpmcertserver/tpmcertserver -k ecc
$ ./examples/tpmcertserver/tpmcertclient -A tpm-server-cert.der
サーバーはTPM内に署名鍵を作成し、そこから証明書を生成して接続を待ち受けます。クライアントは1バイトのデータもやり取りする前に、その証明書をCAで検証します。examples/tpmcertserver 以下のサンプルが、動作する完全なリファレンスです。
この機能とサンプルは、wolfSSHのプルリクエスト wolfSSL/wolfssh#1081 で追加しました。
もし弊社製品についてご質問があれば、お問い合わせ窓口info@wolfssl.jpまでご連絡をお願い致します。
