🖐

Yubikey Bio の生体認証をCTAPで見てみる

2021/10/23に公開

はじめに

生体認証に対応した Yubikey Bio の生体情報の管理や認証機能の検証を行いました。

https://www.yubico.com/products/yubikey-bio-series/

FIDO2 - CTAP 2.1

Yubikey Bio は FIDO2という国際標準のプロトコルで実装されています。
FIDO2の仕様は公開されており、Yubikey Bio は FIDO2 の中の CTAP という仕様に基づいて動作します。
CTAP 2.1バージョンで生体認証が追加されており、その仕様を実装した製品が Yubikey Bio です。

具体的には以下の仕様になります。

Client to Authenticator Protocol (CTAP)
Proposed Standard, June 15, 2021

特に生体情報の管理に関わるコマンドは以下の部分です。

検証方法

Yubikey Bioの生体認証はどんなもんなんでしょうか。
FIDO2デモサイトとか、Chromeのセキュリティキーの管理機能でも検証できるのですが、ここではCTAPレベルで検証します。

macOS でCTAP2.1に対応したツール・ライブラリを使って検証を行いました。

ctapcli(コマンドラインツール)

ctap2.1を実装したコマンドラインツールです。mac専用です。

以下の2発のbrewコマンドでインストールできます。

brew tap gebogebogebo/tap
brew install ctapcli

バージョン 0.0.8 以降で Yubikey Bio 対応です。
% ctapcli -V
ctapcli 0.0.8

ctapcliの詳細は以下を参照ください。

https://github.com/gebogebogebo/homebrew-tap

FIDOキーのPINを設定したりスペックを表示したりするツールを作った

ctap_hid_fido2(Rustクレート)

ctapのRustクレートです。

以下の場所で公開しています。

crates.io

Yubikey Bioの生体データ管理機能

セキュリティキーが生体認証に対応してるか確認する

ctapcli

ctapcliではinfoサブコマンドの --get bio オプションで生体認証に対応したキーかどうか確認することができます。

% ctapcli info --get bio
Get the Authenticator infomation.

option bio = true

bioEnroll
This authenticator supports the authenticatorBioEnrollment commands, and has at least one bio enrollment presently provisioned.

ctap_hid_fido2

ctap_hid_fido2ライブラリでは、enable_info_option()InfoOption::BioEnroll を指定することで生体認証に対応しているかどうか確認することができます。

if ctap_hid_fido2::enable_info_option(&Cfg::init(), &InfoOption::BioEnroll)?.is_some(){
    Ok(true)
} else {
    Ok(false)
}

指紋センサー情報を取得する

ctapcli

bioサブコマンドに --info オプションをつけることで指紋センサ情報を表示します。

% ctapcli bio --info
Bio Management.

Display sensor info.
- Modality
  - Fingerprint
- Fingerprint kind
  - touch type fingerprints
- Maximum good samples required for enrollment
  - 16
- Maximum number of bytes the authenticator will accept as a templateFriendlyName
  - 15

ctap_hid_fido2

bio_enrollment_get_fingerprint_sensor_info() で指紋センサー情報を取得することができます。

let sensor_info = ctap_hid_fido2::bio_enrollment_get_fingerprint_sensor_info(
    &Cfg::init(),
)?;

センサー情報は BioSensorInfo 型の struct です。

  • Modality は Fingerprint のみの定義です。
  • FingerprintKind は TouchType または SwipeType です。Yubikey Bio の場合 TouchType です。
  • maxCaptureSamplesRequiredForEnroll は指紋登録時に必要なサンプル数です。Yubikey Bio の場合 4 でした。
  • maxTemplateFriendlyName は 登録するときに設定可能な名称の最大バイト数です。Yubikey Bio の場合 ? でした。

指紋を登録する

ctapcli

bioサブコマンド --enroll で対話モードで指紋を登録することができます。
登録にはPINの入力が必要になります。

% ctapcli bio --enroll
Bio Management.

Enrolling fingerprint.
PIN: [PINを入力してENTER]

bio enrollment
Please follow the instructions to touch the sensor on the authenticator.

Press any key to start the registration.

[ENTERを入力すると登録開始]

- Touch the sensor on the authenticator
[キーのセンサをタッチする]

Good fingerprint capture. 0x00: CTAP2_ENROLL_FEEDBACK_FP_GOOD
- Number of samples required = 4

- Touch the sensor on the authenticator
[キーのセンサをタッチする]

Good fingerprint capture. 0x00: CTAP2_ENROLL_FEEDBACK_FP_GOOD
- Number of samples required = 3

- Touch the sensor on the authenticator
[キーのセンサをタッチする]

Good fingerprint capture. 0x00: CTAP2_ENROLL_FEEDBACK_FP_GOOD
- Number of samples required = 2

- Touch the sensor on the authenticator
[キーのセンサをタッチする]

Good fingerprint capture. 0x00: CTAP2_ENROLL_FEEDBACK_FP_GOOD
- Number of samples required = 1

- Touch the sensor on the authenticator
[キーのセンサをタッチする]

Good fingerprint capture. 0x00: CTAP2_ENROLL_FEEDBACK_FP_GOOD
- Number of samples required = 0

- bio enrollment Success

templateId: "0B27"

input name:
[右手親指などの登録名を入力してENTER]

- Success

ctap_hid_fido2

上記 ctapcli bio --enroll は ctap_hid_fido2 の以下の3つのコマンドで実現しています。

  • bio_enrollment_begin()
  • bio_enrollment_next()
  • bio_enrollment_set_friendly_name()

bio_enrollment_begin()

指紋登録を開始します。引数にPINとスキャンタイムアウト(ミリ秒)を指定します。
コールすると指紋のスキャンを開始し、スキャンが完了すると戻ってきます。
戻り値は EnrollStatus1EnrollStatus2 のタプルの Result です。

let (enroll_status1,enroll_status2) = ctap_hid_fido2::bio_enrollment_begin(&Cfg::init(), Some(pin), Some(10000))?;
  • EnrollStatus1: bio_enrollment_next() に引き渡すデータです。
    • devide : 内部データ
    • cid : 内部データ
    • pin_token : 内部データ
    • template_id : テンプレートID
  • EnrollStatus2 : 指紋のスキャンをした結果です。
    • status = lastEnrollSampleStatus Value
    • message = 上記 status に対応するメッセージ
    • remaining_samples = remainingSamples (登録完了までに必要なスキャン回数)
    • is_finish = 登録完了したかどうかを示します

bio_enrollment_next()

指紋登録を完了するためには何度かスキャンする必要があります。最初に bio_enrollment_begin() し、次からは bio_enrollment_next() でスキャンします。
bio_enrollment_next()の引数には( bio_enrollment_begin() で取得した) EnrollStatus1 を指定します。

let enroll_status2 = ctap_hid_fido2::bio_enrollment_next(&Cfg::init(), enroll_status1, Some(10000))?;

enroll_status2.is_finishtrue となると 指紋登録完了となります。

bio_enrollment_set_friendly_name()

登録された指紋の表示名称を設定します。引数にPIN、テンプレートID、表示名称を指定します。
テンプレートIDは bio_enrollment_begin() で取得したものを指定します。

ctap_hid_fido2::bio_enrollment_set_friendly_name(
    &Cfg::init(),
    pin,
    template_id,
    "display-name",
)?;

登録されている指紋を取得する

ctapcli

単に ctapcli bio とすると、登録されている指紋を表示します。
以下例の場合 0000 がテンプレートID、testが表示名称です。

% ctapcli bio    
Bio Management.

List registered biometric authenticate data.
PIN: [PINを入力してENTER]

Number of registrations = 2
0000 : test
0001 : 右手親指

ctap_hid_fido2

ctap_hid_fido2では bio_enrollment_enumerate_enrollments() で登録情報をリストで取得することができます。

let template_infos = ctap_hid_fido2::bio_enrollment_enumerate_enrollments(&Cfg::init(), pin)?;

上記 template_infos は Vec<TemplateInfo> 型です。

指紋を削除する

ctapcli

ctapcli bio -d テンプレートID で1件削除します。
以下はテンプレートID 0001 を削除する例です。

% ctapcli bio -d 0001
Bio Management.

Delete a fingerprint.
PIN: [PINを入力してENTER]

Delete enrollment
value for templateId: "0001"

- Success

ctap_hid_fido2

bio_enrollment_remove() で削除します。引数にテンプレートIDを指定します。

ctap_hid_fido2::bio_enrollment_remove(&Cfg::init(), pin, &template_id)?;

Yubikey Bioで指紋によるクレデンシャル登録と認証

ctapcli

ctapcliでは ctapcli bio --test で指紋での登録と認証をテストすることができます。

% ctapcli bio -t
Bio Management.

Test register and authenticate.

Register
- Touch the sensor on the authenticator
[ここでキーをタッチして指紋認証]

Verify
Register Success !!

Authenticate
- Touch the sensor on the authenticator
[ここでキーをタッチして指紋認証]

Verify
Authenticate Success !!

Register and Authenticate Success

ctap_hid_fido2

登録と認証を指紋認証で行う方法です。

make_credential() がクレデンシャルを登録するAPIですが、pin引数にNoneを指定 すると指紋認証で登録します。

let rpid = "ctapcli.test";
let challenge = verifier::create_challenge();
let pin = None;

let att = ctap_hid_fido2::make_credential(
        &Cfg::init(),
        rpid,
        &challenge,
        pin
)?;

認証を行う get_assertion() を同様に、pin引数にNoneを指定 すると指紋認証となります。

let pin = None;

let ass = ctap_hid_fido2::get_assertion(
        &Cfg::init(),
        rpid,
        &challenge,
        &verify_result.credential_id,
        pin,
)?;

指紋認証のロックカウンタを調べる

PINと同じく指紋認証もカウンタを持っていて連続して間違えるとロックがかかります。
生体認証にロックがかかった場合、PINで認証をパスすることで自動的に解除されます。

ctapcli

ctapcli pinコマンドを実行すると通常のPINリトライカウンタと指紋認証のリトライカウンタを得ることができます。

% ctapcli pin
PIN Management.

Get PIN retry counter.

PIN retry counter = 8

:) :) :) :) :) :) :) :) 

PIN retry counter represents the number of attempts left before PIN is disabled.
Each correct PIN entry resets the PIN retry counters back to their maximum values.
Each incorrect PIN entry decrements the counter by 1.
Once the PIN retry counter reaches 0, built-in user verification are disabled and can only be enabled if authenticator is reset.


Get UV retry counter.

UV retry counter = 3

UV retries count is the number of built-in UV attempts remaining before built-in UV is disabled on the device.

ctap_hid_fido2

get_uv_retries() で指紋認証のリトライ回数を取得することができます。

match ctap_hid_fido2::get_uv_retries(&Cfg::init()) {
	Ok(v) => println!("UV retry counter = {}", v),
	Err(err) => return Err(err),
};

おつかれさまでした

とりあえずという感じの検証でした。

CTAPのコマンド詳細についてはソースを見ていたただければと思います。

https://github.com/gebogebogebo/ctap-hid-fido2

Discussion