WebAuthnぽいことができるWinデスクトップアプリ用ライブラリ WebAuthnModokiDesktopβ


はじめに

WindowsデスクトップアプリでもWebAuthnっぽいことができるライブラリを作成したので紹介します。

- 2018/12/18 FEITIAN BioPass FIDO2での動作確認をしました

- 2018/12/24 Verify機能を追加しました

- 2019/01/14 NFC(Yubikey5)に対応しました

- 2019/03/09 ver 2.0.0.0


注意事項


  • 本ライブラリ・デモプログラムはWebAuthn、CTAPを勉強しながら作成した検証プログラムです。

  • サンプルレベルの品質なので重要なクレデンシャル情報が入っている認証器は使わないことをお勧めします。

  • 本ライブラリ・デモプログラムを利用することによって生じるいかなる問題についても、その責任を負いません。


1.実行環境

※Webとか名前がついていますが、サーバーと通信するなど一切ありません。


2.とりあえず動かしてみる


  • お手元に『2』って書いてある青いYubikeyをご用意ください

  • あるいはFEITIAN BioPass FIDO2でもOK

  • あるいはYubikey5でもOK


  • ココからバイナリ一式をダウンロードします。


  • testUI02.exe を実行します。

  • YubikeyをUSBに刺して「get info」をクリックして「Success」って出たらOKです。

  • あるいは パソリにYubikey5を乗っけて「get info」をクリックして「Success」って出たらOKです。

image.png


get Info

Authenticatorの情報をGETします。GETして表示するだけです。


Register

登録。WebAuthnのcredentials.create()ぽいことをやります。

UserNameを入力してNextして登録します。

YubikeyにPINが設定してある場合は CTAP2_ERR_PIN_REQUIRED PIN とエラーになるので画面右上PIN欄にPINを入力してからNextボタンをクリックしてください。

Enable username-less loginにチェックをつけるとResident Keyします。

BioPassで指紋認証したい場合は、User VerificationにチェックONしてください。

Regident Keyは認証器にユーザー情報を保存する機能ですが、無限に保存できるわけではありません、認証器の保存領域MAXになった時の動作はYubikeyの場合、変なエラーが起きるようになるなど、あんまりうれしくない挙動になるようですのでご注意ください。

※2019/2/11追記 青いYubikeyでは26個目の登録(authenticatorMakeCredential)で 0x28:CTAP2_ERR_KEY_STORE_FULL のエラーになりました。


Login

認証。WebAuthnのcredentials.get()ぽいことをやります。

Credential Idを指定してget()します。

このサンプルは直前にRegisterしたCredential Idをメモリに保持して再利用するだけです。

なので、Registerの後にやってください。

※BioPassで指紋認証したい場合は、User VerificationにチェックONしてください。


Login without username

こちらも認証ですが、Credential Idを指定しない方法です。

なのでRegisterしないでも実行可能です。


3.ライブラリ解説

ソースは以下の場所です。

https://github.com/gebogebogebo/WebAuthnModokiDesktop


ライブラリ構成

ライブラリは64bit専用です。

- WebAuthnModokiDesktop.dll(本体)

- BouncyCastle.dll(Bouncy Castle)

- Newtonsoft.Json.dll(Newtonsoft.Json)

- CBOR(PeterO.Cbor)

- Numbers(PeterO.Numbers)

- HidLibrary(hidlibrary)

Module.png


プロジェクトへの組み込み


  • Visual Studioでプロジェクトを作成します。


  • ここからとってきたバイナリ一式(binフォルダの中身)をexeと同じフォルダに置いてください。

  • Visual Studioの参照から WebAuthnModokiDesktop.dll を参照に追加してください。


メソッド

using gebo.CTAP2.WebAuthnModokiDesktop;

using gebo.CTAP2;


  • Credentials.Create()

  • Credentials.Get()

  • Credentials.Info()

  • Credentials.SetPin()

  • Credentials.ChangePin()

  • Credentials.HidCheck()

  • Credentials.NfcCheck()

  • Credentials.SerializeAttestationToFile()

  • Credentials.DeSerializeAttestationFromFile()


Credentials.Create()


引数


  • DevParam devParam : デバイスの検索パラメータ※

  • string publickeyJson : WebAuthnで指定するOptionをJSON文字列形式で指定します。

  • string pin="" : PIN

※devParamについて

Authenticatorデバイスを検索するパラメータです。

とりあえず、gebo.CTAP2.DevParam.getDefaultParams()をしておけばYubikeyとFEITIANのパラメータ設定されます。それ以外の製品は手動で追加してください。


戻り値


  • CreateCommandStatusクラス : 中にAttestationが入っています。

var devParam = DevParam.GetDefaultParams();

byte[] challenge = System.Text.Encoding.ASCII.GetBytes("this is challenge");
string pin = "xxxx";
string json =
"{" +
"rp : {" +
"id : 'demo.WebauthnMODOKI.gebogebo.com'," +
"}," +
"user : {" +
"id : 'userid'," +
"name :'name_name'," +
"displayName :'my name is gebogebo'," +
"}," +
"pubKeyCredParams: [{type: 'public-key',alg: -7}]," +
"timeout: 60000," +
"authenticatorSelection : {" +
"requireResidentKey : false," +
"}," +
string.Format($"challenge:[{string.Join(",", challenge)}],") +
"}";
var response = await Credentials.Create(devParam,json, pin);
if (response.isSuccess == true) {
// 成功
// response.attestation ...
}


Credentials.Get()


引数


  • DevParam devParam : デバイスの検索パラメータ

  • string publickeyJson : WebAuthnで指定するOptionをJSON文字列形式で指定します。

  • string pin="" : PIN


戻り値


  • getcommandstatusクラス : 中にAssertionが入っています。


    • Assertionは複数取れる場合があるのでリストです。



var devParam = DevParam.GetDefaultParams();

byte[] challenge = System.Text.Encoding.ASCII.GetBytes("this is challenge");
string pin = "xxxx";
byte[] CredentialId= // createでGETしたCredentialIdを指定してください(response.attestation.CredentialId);

string json =
"{" +
"timeout : 60000," +
string.Format($"challenge:[{string.Join(",", challenge)}],") +
"rpId : 'demo.WebauthnMODOKI.gebogebo.com'," +
"allowCredentials : [{" +
string.Format($"id : [{string.Join(",", CredentialId)}],") +
"type : 'public-key'," +
"}]," +
"requireUserPresence : 'true'," +
"userVerification : 'discouraged'," +
"}";

var response = await Credentials.Get(devParam ,json, pin);
if (response.isSuccess == true) {
// 成功
// response.assertions[0] ...
}


Credentials.SetPin()


引数


  • DevParam devParam : デバイスの検索パラメータ

  • string newpin : 設定するPIN


戻り値


  • commandstatusクラス : 処理結果です

PINを初めてセットするときに使うコマンドです。

PIN変更ではありません。


Credentials.ChangePin()


引数


  • DevParam devParam : デバイスの検索パラメータ

  • string newpin : 設定するPIN

  • string currentpin : 現在のPIN


戻り値


  • commandstatusクラス : 処理結果です


Credentials.Info()


引数


  • List hidParams : HIDデバイスの検索パラメータ


戻り値


  • infocommandstatusクラス : Authenticatorの情報


Credentials.HidCheck()


引数


  • List hidParams

USBにささっているAuthenticatorの情報を取ってきます。


Credentials.NfcCheck()


引数


  • List nfcParams

NFCリーダーにのっかっているAuthenticatorの情報を取ってきます。


Credentials.SerializeAttestationToFile()


引数


  • CTAPResponseAttestation att : attestationクラス

  • string pathname: シリアライズするファイルのパスとファイル名


戻り値


  • bool : true(成功)/false(失敗)

attestationをファイルに保存します。


Credentials.DeSerializeAttestationFromFile()


引数


  • string pathname: デシリアライズするファイルのパスとファイル名


戻り値


  • CTAPResponseAttestation : Attestationクラス

attestationをファイルからクラスにデシリアライズします。


おつかれさまでした


  • 対応していない・未検証の部分


    • 応答値を検証する機能はありません。

    • PINを変更する機能はありません。

    • timeoutパラメータには対応していません。

    • 32bit環境では動作確認していません、多分動かないと思います。


    • 2って書いてある青いYubikey以外では動作確認していません。



  • 夜 酒飲みながら書いているコードなので、怪しいところが多々あり。

  • 参考にさせていただきました。