以前の投稿 「FIDOデバイスエミュレータを作成してみた(これが最後)」 で、FIDO2のデバイスエミュレータの作成を試みて、断念していたのですが、久しぶりに挑戦して、原因がわかり、完成できました。
ソースコードもろもろを以下のGitHubに上げてあります。
poruruba/fido2_server
ただ、いくつかのサイトで動かしていますが、動かないサイトがあります。おそらく、FIDOアライアンスのCertifiedデバイスではないからかと思います。たとえば、AWSのWebコンソールへのログインのためのFIDOデバイスとして登録できますが、認証時に失敗しています。。。
(20210626 訂正)
X509v3証明書に足りない情報があっただけで、普通にAWSのログインに使えました。最後にAWSコンソールでの例を示しておきました。
(2021/6/27 修正) npmモジュール ecdsa-secp256r1 を不要にしました。
(2022/1/4 追記)
M5Stack用暗号認証ユニットでFIDO2デバイスを実装しました。
https://qiita.com/poruruba/items/7e74ff3cdf27d4937f2d
#目指す構成
本来、FIDO2デバイスは以下の構成で使います。ブラウザとFIDO2デバイスの間は、BLEかNFCかHIDで通信します(ブラウザの実装状況にも寄りますが)。
FIDO2対応サーバ
⇔(HTTPS)
ブラウザ
⇔(BLE、NFC、HID)
FIDO2デバイス
目指す構成は以下の構成です。
FIDO2対応サーバ
⇔(HTTPS)
ブラウザ
⇔(BLE)
M5StickC
⇔(HTTP)
FIDOデバイスエミュレータ
FIDO2デバイスの代わりにM5StickCを使い、BLEでブラウザと通信します。
ちなみに、M5StickCは単に背後にあるWebサーバ(FIDOデバイスエミュレータ)に転送しているだけです。
今回、紆余曲折しましたが、FIDOデバイスエミュレータをNode.jsで作成することができました。
#今回直したところ
以下に仕様定義されていたのですが、実装が漏れておりました。というか気づきませんでした。
・0x07 ("check-only"): if the control byte is set to 0x07 by the FIDO Client, the U2F token is supposed to simply check whether the provided key handle was originally created by this token, and whether it was created for the provided application parameter. If so, the U2F token must respond with an authentication response
message:error:test-of-user-presence-required (note that despite the name this signals a success condition).
やられた。。。。
0x07のときには、「message:error:test-of-user-presence-required」を返すべきとのこと。
そして、それがこれのこと。
SW_CONDITIONS_NOT_SATISFIED (0x6985): The request was rejected due to test-of-user-presence being required.
これを直したらあっさり動きました。。。
#追加で直したところ
x509v3証明書を作成するために、npmモジュールであるjsrsasignを使っていたのですが、脆弱性があったらしく、最新にアップデートすると、インタフェースが変わっているため、変更が必要でした。
新しい書き方
var cert = new rs.KJUR.asn1.x509.Certificate({
version: 3,
serial: { int: serial_no++ },
issuer: { str: "/CN=" + FIDO_ISSUER},
notbefore: FIDO_EXPIRE_START,
notafter: toUTCString(new Date(Date.now() + FIDO_EXPIRE * 24 * 60 * 60 * 1000)),
subject: { str: "/CN=" + FIDO_SUBJECT },
sbjpubkey: kp.pubKeyObj, // can specify public key object or PEM string
sigalg: "SHA256withECDSA",
ext: [
{
//サブジェクトキー識別子
extname: "subjectKeyIdentifier",
kid: {
hex: derSKI.getEncodedHex()
}
},
{
// FIDO U2F certificate transports extension
extname: "1.3.6.1.4.1.45724.2.1.1",
extn: "03020640"
}
],
cakey: kp_cert
});
#その他直したところ
M5StickC
・LCDに通信状態を表示するようにしました。
・M5StickCにおいて、BLEコネクション切断されたときには、3秒ほど、BLEアドバタイズを停止させ再度起動するようにしました。(そうしないと、ブラウザが見つけてくれなかった)
FIDO2エミュレータ
・生成した認証情報をファイルに保存するようにしました。
・x509v3証明書の署名鍵を共通にして、ファイルに保存しておくようにしました。
FIDO対応サーバ
・ユーザ情報をファイルに保存するようにしました。
認証や登録を繰り返していると、 data/fido2_device/
や、data/fido2_server/
にたくさんファイルができてくるので、不要なファイルは削除してあげてください。
#立ち上げ方法
以下から、まるごとZIPダウンロードします。
https://github.com/poruruba/fido2_server
■FIDO2エミュレータ兼FIDO対応サーバ
フォルダfido2_serverにあります。
> unzip fido2_server-master.zip
> cd fido2_server-master
> cd fido2_server
> mkdir data
> mkdir data/fido2_device
> midir data/fido2_server
> mkdir cert
> touch .env
> node app.js
HTTPSが必要であるため、SSL証明書が必要です。certフォルダに置きます。
.envには以下を記載します。ポート番号です。
SPORT=443
PORT=10080
いくつか環境に合わせて書き換えるところがあります。その他、以前の投稿を参考にしてください。
WebAuthnを使ったFIDOサーバを立ててみた
ちなみに、当時はfido2-libの修正が必要な個所が何件かありましたが、そのうちの1件は最新では修正されているようでした。
■M5StickC
フォルダFido2Gatewayにあります。
いくつか環境に合わせて書き換えるところがあります。その他、以前の投稿を参考にしてください。
FIDOデバイスエミュレータを作成してみた(だけどもうちょっと。)
#使ってみる
まずは、今回同時に立ち上げた、FIDO対応サーバで動作確認。
https://【立ち上げたサーバのホスト名】/fido2/index.html
詳細は以下をご確認ください。
ちなみに、今回の画面キャプチャでは、Windows PCでの画面ですが、Androidでも同様に動作を確認できます。(以前投稿したときと表示が変わっているようで、以前のほうがかっこよかったです。。。)
それから、BLEで通信するには、最初に、WindowsのBLE設定で、M5StickCとペアリング設定しておく必要があるようです。
登録開始ボタンを押下。
登録実行ボタンを押下。
これで、FIDO2デバイスの登録が完了しました。
続けて、認証してみましょう。ログイン開始ボタンを押下。
ログイン実行ボタンを押下。
認証成功です。
試しに、他のサイトでも確認してみます。
Registerボタンを押下
今度は、Authenticateボタンを押下
以下のサイトも。
登録ボタンを押下
次は認証。ログインボタンを押下。
以下でもできました。
#AWSコンソールのログインに使ってみる
AWSのWebコンソールのログインに使ってみます。
AWSのIAMからとりあえずユーザアカウントを作ります。以下の例では、「fido2」という名前のユーザを作りました。そして、認証情報のタブを選択します。
次に、MFA デバイスの割り当て のところの管理をクリックします。
そうすると、以下のようなダイアログが表示されるので、U2Fセキュリティキーを選択して、「続行」ボタンを押下します。
以下が表示されます。
登録が完了すると以下が表示されます。
ログインしてみましょう。まずは普通にユーザ名とパスワードを入力してログインします。
そうすると、以下のようにFIDO2デバイスを要求されるので、M5StickCが電源Onでアドバタイジング状態であれば、そのままログイン処理が進むはずです。
無事にログインが完了します。
以上