# FIDO2認証の調査 FIDO2は公開鍵暗号を利用して従来のパスワード認証より強力な認証を行うための規格である。 ## FIDO規格の歴史 FIDO AllianceはU2FとUAFを規格化した。 U2Fは二段階認証手段で、UAFはパスワードレス認証を行う規格である。 これらを統合した結果、FIDO2規格が生まれた。 ## 特徴 - 非常に安全 - パスワード不要 - 外部認証器またはTPMを使うので安全 - 外部認証器またはTPMがなければ使えない - 鍵がウェブサイトごとに異なるものを使う - 主要ブラウザ最新版はすべて対応している ## 対応認証器 - Windows Hello - Apple Touch ID/Face ID - Android画面ロック - YubiKey - Trezor - Ledger - Google Titan ## API 公開鍵ベースの認証、パスワード認証が利用できる。前者はデバイスのTPMやYubikey, Trezorなどの外部認証器が使える。後者はWIP? 外部の認証器との通信はBluetooth, ISO7816.ISO14443, USB HIDの通信方式における送信方法がCTAPによって定義される ### 新規登録フロー `navigator.credentials.create(options?: PublicKeyCredentialCreationOptions)` - 認証先のウェブサイト - 認証に使うユーザー情報 - 公開鍵暗号方式 - COSEのアルゴつかえる - RSAまたはECDSAが既定 - チャレンジ などを送ると、鍵を生成・記憶して、 - rawId - clientDataJSON - クライアントデータ - このJSONが署名文? - attestationObject - 電子署名が含まれたCBOR ### 利用フロー `navigator.credentials.get(options?: PublicKeyCredentialRequestOptions)` createのときと同様の形式で、createの時と同じ鍵でチャレンジを署名して返す。 ### 検証 #### 環境 - Windows 11 - Firefox 97 - AMD Ryzen 9 3950X (AMD PSP TEE内臓) - 外部TPM非接続 Windows Helloによる認証を行った。認証に使った方法はTPM(Windowsにログインするときに使うPIN)である。 ### 結果 https://codesandbox.io/s/cocky-lumiere-gyhrky ``` PublicKeyCredential {getClientExtensionResults: ƒ getClientExtensionResults(), rawId: ArrayBuffer, response: AuthenticatorAttestationResponse, id: "zYnIjuB0EIXW-G1XOo4ZMxho6XDXOxv8D4_zm_98ZwY", type: "public-key"…} {} {"challenge":"jAom_w","clientExtensions":{},"hashAlgorithm":"SHA-256","origin":"https://gyhrky.csb.app","type":"webauthn.create"} Uint8Array {0: 163, 1: 99, 2: 102, 3: 109, 4: 116…} a363666d74646e6f6e656761747453746d74a0686175746844617461590167eb94a11634db6334bf23ec0d3a8d9858509c5fe6ec6832b71314a3818f677c864500000000000000000000000000000000000000000020cd89c88ee0741085d6f86d573a8e19331868e970d73b1bfc0f8ff39bff7c6706a401030339010020590100dc7b6fb382e1df4918822c0fc1c2241b34a7fa1d15f8cc4087202ba5bdcf55667ac94434a08c1eae945beb050ac9e8cc1777890819fe77031e6be67439b5d3ba8969560f6e40fe96a740f370d8c0565fc3eb594b2a56a4cf68494c448c5a34c40c3d7be46ecacf6eb0193e3cf7c89e3fcf3da3f62748dbb0ddf7989d62ba0cf7d1dd4c54406b8c5a7766b4e5b9b7d2c2a59c6b050dd7b79c80f0b43052005530b11c613c24d066dc621d8611f1e9d163da10c94300abec70867492d081a10811ecb4c0fb8c68fa3a425493c9153ce5d6615e869b18a79c5fb8d9b2e3fde43c465e1eff82adf1107a90b0db66929e72bbb50cc3547ddc1efb593691c2afaa26172143010001 PublicKeyCredential {getClientExtensionResults: ƒ getClientExtensionResults(), rawId: ArrayBuffer, response: AuthenticatorAssertionResponse, id: "zYnIjuB0EIXW-G1XOo4ZMxho6XDXOxv8D4_zm_98ZwY", type: "public-key"…} {} {"challenge":"jAom_w","clientExtensions":{},"hashAlgorithm":"SHA-256","origin":"https://gyhrky.csb.app","type":"webauthn.get"} Uint8Array {0: 235, 1: 148, 2: 161, 3: 22, 4: 52…} eb94a11634db6334bf23ec0d3a8d9858509c5fe6ec6832b71314a3818f677c860500000001 ``` 実行を繰り返しても、同じ署名文が返ってきた。 RS256を使っている。pubKeyCredParamsからRS256を除いたら、PIN入力画面が表示されず、セキュリティキーの入力を求められた。 ## これを使えるか? これに使う電子署名アルゴリズム・暗号文フォーマットを受容するスマートコントラクト等があれば不可能ではなさそうである。 しかし、任意の暗号文を設定してSecp256k1署名をできないので、既存のブロックチェーンの電子署名には使えなさそうである。 また、対応する署名アルゴが複数あり、認証器によって対応するものが異なるため(TrezorはES256のみ, Windows HelloはRS256のみ)、アルゴ対応数増やすと大変である。 また、出力された電子署名を秘密鍵として扱いECDSA鍵ペアを導出するのもやめたほうがよい。 Windows 11環境では決定論的署名であるようだが、そのほかの認証器がそうであるという保証はない(もしかしたらCTAPに定義してあるかも)ので、同じ鍵ペアを導出できるかどうかわからないからである。 ## 参考文献 https://github.com/trezor/trezor-firmware/blob/319d0f16e33892d0f9c5fc4fd22186bf5e75acb8/core/src/apps/webauthn/fido2.py#L1783 https://www.w3.org/TR/webauthn https://www.iana.org/assignments/cose/cose.xhtml#algorithms