LoginSignup
4
3

More than 3 years have passed since last update.

OpenSKで認証時にボタンが反応しない件を調べてみた

Last updated at Posted at 2020-08-16

nRF52840-DKにOpenSKを入れてUSB FIDOキーにしてみたの続きです。


2020/08/20 追記
本投稿8/16で同日に修正をOpenSKにプルリクエストしたところ即座にマージされたのでこの現象は発生しなくなりました。めっちゃ早い対応!


OpenSKを使って認証するときにセキュリティキーのボタンを押しても反応しない以下の謎がありました。

「セキュリティキーにタッチしてください」のポップアップ画面でキー(nRF52840-DK)のボタンを押しても反応せずキャンセルするしかない

auth.PNG

調査してみると以下のような状況です。

バグならば仕方ない、そのうち修正されるだろうと思っていたのですが、夏休み暇なので自分で調べてみたという話です。

環境

  • ビルド環境
    • Mac OS X Catalina 10.15.5
    • vscode 1.48.0
  • 実行環境
    • Windows 10 Pro 64bit 1909
  • セキュリティキー

どこが怪しいのか

Macだと正常に動作して、Winだとおかしい、ということはOpenSKの問題ではないようにも思います。Webサーバ(RP)かブラウザ(Platform)の問題?。「セキュリティキーにタッチしてください」のポップアップはWebAuthnを実装したブラウザの機能で表示しているのでブラウザが怪しい。OpenSKから受け取ったの認証結果(Assertion)の検証でブラウザが内部的にコケてしまっているのかも知れません。

OpenSKとブラウザでどんなやりとりがされているのか調べてみます。

どこが怪しいのか2

ユーザープログラムがコールするJavaScriptのWebAuthnの認証APIはnavigator.credentials.get()です。ブラウザはこのAPIを受けて内部でCTAPコマンドをセキュリティキー(OpenSK)に放り投げます。認証で使うCTAPコマンドはauthenticatorClientPIN,authenticatorGetAssertion,authenticatorGetNextAssertionです。今回の問題はPINを検証した後のUserPresenceフェーズで発生しているのでauthenticatorGetAssertionで何か起こっているようです。

CTAPコマンドの通信内容をトレースする

authenticatorGetAssertionを見てみましょう。以下のツールを使って通信内容を見ることができます。

CTAPcs - HIDTest01.exe

  • HIDTest01.exeを立ち上げる
  • 接続確認
    • セキュリティキーをUSBに挿して GetInfoボタン をクリック→ログにそれっぽいのが出たら接続OK
  • 登録
    • RPIDは test.com のまま、PINを入力、ResidentKeyは チェックOFF で MakeCredentialボタン をクリック→セキュリティキーが光ったらボタンを押す→成功すると CredentialID が取れる
  • 認証
    • そのまま GetAssertionボタン をクリック→セキュリティキーが光ったらボタンを押す
    • ここでログにでてくる CTAP ResponseDataJson が authenticatorGetAssertion の応答なので、これを調査します。
    • OpenSK、Yubikey、BioPassのログを比べてみます。
OpenSK
- CTAP ResponseDataJson = 
{
"1":
    {   "id":"LiSHLJSRyKpyEUlCqCwmo99VZCoYjfGnsWNn2RPitrcYP80L_HFb1_DY4doGnAfkp738pWbX_yCPXnGZ6r0Vt6b0MAmVy6vV-RUtMWAEQZkpsBHRpEWmX4kIgJZi3LT02CacCHktzRcLuxvU_P8tuA",
        "type":"public-key"
    },
"2":
    "matxXYSjvF4OkqpQ5npYE2N_0XRL0wGrCPhxkd24FuAFAAAAGQ",
"3":
    "MEUCIQCD0jAejoDvRtKIZ7ZRBikQ6Yma51Ib7KK5Mt-SctHrKgIgS5ujml4W28-66Xq50UVsZl97rKhTz5jgAfViJqs8Bqc",
"4":
    {
        "id":""
    }
}
Yubikey
- CTAP ResponseDataJson = 
{
"1":
    {
        "id":"KL-rWIRGn26kZxtQXasrN4TI7vsnkvb3xAu_3huZ-nxF-wk-aOWtsXeP2f3rZiU-EBYjHcPJoQDE0KyOFLc9BA",
        "type":"public-key"
    },
"2":
    "matxXYSjvF4OkqpQ5npYE2N_0XRL0wGrCPhxkd24FuAFAAAA3w",
"3":
    "MEUCIQDsA3Fr3LPapPUWBn4m56QTfvNvIxMmLKqKsjBe4YRDWAIgPUdmgwcn0P7h-PxR2fPDYXcBsLYFRvQdxzpIrYllkoc"
}
BioPass
- CTAP ResponseDataJson = 
{
"1":
    {
        "id":"HpVOwMsjnnLFXVPNTszaMxzbO16pm7FQn8E3Gk4bnI-NoNrwp5-UVvq4dcp1AYdPCwh_Al3YkBAqZvDF8zV81rnvIuROH9b_pkUL1K6epYdINUwfIiCOJcZwYcqyoE9S",
        "type":"public-key"
    },
"2":
    "matxXYSjvF4OkqpQ5npYE2N_0XRL0wGrCPhxkd24FuAFAAAAHQ",
"3":
    "MEUCIBY7hxOq8lc-RoUUKL5MuKf7QyhHyCL7DXhU78QawymzAiEA-FbLH9iBW12WaocTr3NxXJMMxbCnmW2LgJLWFoZQzWA"
}

わかりにくいようでわかりやすいのですが、OpenSKだけ"4"があります。

OpenSK
"4":
    {
        "id":""
    }

これは何なんでしょうか?

"4"って何?

CTAPの仕様書によると、user (0x04) - PublicKeyCredentialUserEntity というものです。

PublicKeyCredentialUserEntity
PublicKeyCredentialUserEntity structure containing the user account information. User identifiable information (name, DisplayName, icon) MUST not be returned if user verification is not done by the authenticator.
ユーザーアカウント情報を含むPublicKeyCredentialUserEntity構造体。ユーザ認証が認証者によって行われていない場合、ユーザを特定できる情報 (name, DisplayName, icon) は返されてはなりません[MUST]。

6.1. Commands

EXAMPLE2
var user = {
      id: Uint8Array.from(window.atob("MIIBkzCCATigAwIBAjCCAZMwggE4oAMCAQIwggGTMII="), c=>c.charCodeAt(0)),
      icon: "https://pics.example.com/00/p/aBjjjpqPb.png",
      name: "johnpsmith@example.com",
      displayName: "John P. Smith"
    };

id , icon ,name ,displayNameのメンバを持つ構造体で、要するにユーザー情報ですね(雰囲気理解)。確かに登録時にユーザー名は入力してますが、ログを見る限り空っぽです。YubikeyやBioPassでは存在すらしていない。何でなんでしょうか?

PublicKeyCredentialUserEntityとは

FIDO2にはResidentKeyという機能がありまして、セキュリティキーの中にユーザー情報を格納することができます。登録時にユーザー情報をキーの中に保管しておいて、認証時にキーの中にあるユーザー情報を取り出しそのユーザーでログインするなんてことを想定した機能です。ResidentKey機能によってユーザーは自分自身が誰かをわざわざ入力しなくてもキー(所持)とPIN(記憶)または指紋(生体)による2要素認証を実現できます。このキーの中に格納されるユーザー情報が PublicKeyCredentialUserEntity構造体 です。便利なんですけどキーのメモリを使うので格納できる量には限界があるという問題もあります。ResidentKeyを使っているRPはあんまりいないんじゃないかと思います。

さて、今の使い方ではResidentKey機能は使っておりません。なので、PublicKeyCredentialUserEntityは無い、あるいはPublicKeyCredentialUserEntityの中身が空、というセキュリティキー側の動きは仕様的には問題なさそうです。しかしブラウザは空のPublicKeyCredentialUserEntityを受け付けないようで、エラーにするわけでもなくシカト(無視)するようです。つまり、OpenSKはちゃんとボタンプッシュを検知して応答しているんだけども、ブラウザにシカトされている状況、というわけです。YubikeyもBioPassもPublicKeyCredentialUserEntityが無い応答をしているのでブラウザ側はOpenSKのような応答に対応していないのか、CTAP仕様がそうなのかもしれません。

とりあえず、OpenSKもPublicKeyCredentialUserEntityを無しにするようにすればブラウザは反応してくれるかもしれませんのでやってみます。

OepnSKを修正する

ソースをみてみます。Rustはよくわからないしデバック実行もできないのでとにかくコードを舐めるようにみます...

半日ほどかかってようやく該当の場所を見つけました。

mod.rs
    let user = if flags & UV_FLAG != 0 {
        Some(PublicKeyCredentialUserEntity {
            user_id: credential.user_handle.clone(),
            user_name: None,
            user_display_name: credential.other_ui.clone(),
            user_icon: None,
        })
    } else {
        Non
    };

このifの中に入っているのにもかかわらず、credential.user_handleが空なので空のPublicKeyCredentialUserEntityが生成されてしまうんでしょう。登録時にResidentKeyをfalseにしているのでcredential.user_handleが空なのは正常だと思います。つまり、この判定を修正する必要があるのかもしれません。

修正しました(1行!)。
これで空のPublicKeyCredentialUserEntityを生成することはなくなるはずです。

mod.rs
        let user = if (flags & UV_FLAG != 0) && (credential.user_handle.len() > 0) {
            Some(PublicKeyCredentialUserEntity {
                user_id: credential.user_handle.clone(),
                user_name: None,
                user_display_name: credential.other_ui.clone(),
                user_icon: None,
            })
        } else {
            None
        };

テスト

認証するときにボタンを押したらちゃんと認証できるようになりました。
しかし修正方法がこれでいいのか、OpenSKはあえて対応していないのかもしれません...

環境 YubiOn fido.identityserver.com webauthn.io
Windows 10 Pro 1909
Chrome 84.0.4147.125
OK OK OK
Windows 10 Pro 1909
Edge 84.0.522.59
OK OK OK
Mac OS X Catalina 10.15.5
Chrome 84.0.4147.125
OK OK OK

おつかれさまでした

Rustの言語仕様は非常に興味深く面白い!

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3