top of page
Blog article

Blog article

いまさらながら FIDO U2F CTAP1 を実装してみた

はじめに

今日は、大変いまさらながら U2F の Hostライブラリを作る機会がありましたので、U2F のスペックを読んでわかりにくかったことなどをまとめていきたいと思います。

Host ライブラリと言っているのは、いわゆる FIDO Client(web ブラウザ) と Authenticator(YubiKeyなど) との通信をする部分で、通常 U2F 通信は Chrome や Firefox などのブラウザが担ってくれるため、我々がなにかプログラムを書く必要はありません。


ただし、Webブラウザが利用できないようなネイティブアプリで FIDO認証を利用したい場合、今回のように Hostライブラリを作成する必要があります。(Windows Hello など、プラットフォームAPIでサポートされれば必要なくなります)

正直、CTAP2 のスペックやサンプルが出てきている段階で、なぜ今更 U2F なんだと思われるかもしれませんが、デバイスと Authernticator の通信に関しては、CTAP2と似通った部分もあり、気になる方もいるのではないかと考えブログに纏めました。


目次

・シーケンス

・ホストライブラリがやっていること

・U2Fデバイスとの通信

 ・JavaScript API 

 ・Raw Message Format

 ・APDU Format

 ・HID Protocol

・FIDO2について


シーケンス

まずはU2Fのシーケンス全体を確認してみましょう。


登録時



認証時



よく見る U2F のチャレンジ&レスポンスの図ですね。この Client と YubiKey の通信部分が、 CTAP と呼ばれるところです。


FIDO2 での CTAP2 のスペックと比較して CTAP1 とも呼ばれますので、本記事では CTAP1と呼んでいきます。


Client は通常はブラウザだと思いますが、U2Fとして実装しているのは Chrome だけです。(WebAuthN としては Firefox60 以降も対応しています)



ホストライブラリのやるべきこと

ホストライブラリは、 U2F JavaScript API などの API の裏側で動作します。 たとえば登録時であれば、

・USBデバイスを列挙する

・U2Fデバイスを探す

・登録のリクエストをデバイスに書き込む

・デバイスからのレスポンスを読み取る


といった機能が必要になります。

今回は FIDO U2F の実装である 3. registration request 以降の動作について、解説していきます。


U2Fデバイスとの通信

U2Fのスペックには U2F JavascriptAPI U2FU2F Raw Message Formats , そして、U2F HID Protocol があり、 Javascript API から順番に Client 側からデバイスのローレベルなプロトコルになっています。


なにやら、スペックがいっぱいありどれがどう関係しているのかわからなくなりますが、ポイントは3つです。


Point 1.  U2Fデバイス は HID デバイスとして動作する


さて、スペックにあるように、U2Fデバイスと Client の通信は HID(Human Interface Device) プロトコルでお話します。 HIDとはキーボードやマウスといったデバイスなどで用いられる共通規格でドライバレスで利用することが可能です。


Point 2. データの送受信フォーマットは APDU Format


通信は HID プロトコルで行うのですが、実際のメッセージは APDU Format という、フォーマットで送ります。APDU Formatとはスマートカードの読み取りなどで利用されるデータのやり取りの方式で、コマンドとデータ長を表すヘッダーと、データをくっつけて送る形になっています。


Point 3. 実際のデータ形式は U2F Raw Message Formts


そして、APDUで送る肝心のデータは U2F Raw Message Formats という形式にして送ります。


Raw Message Format はバイト配列のデータなので、最終的に JavaScript などで扱えるようなデータ形式に変換してやれば、Chrome に搭載された API のように、JSONなどのデータ形式で扱えます。


まとめると、こんな感じです。

以上3つのポイントがわかれば、あとはスペックや yubico のリファレンスコードを読めば理解できるかと思います。


(私は普段デバイス周りの開発をしているわけではないので、このあたりを理解するのに時間がかかりました)



すべてを説明すると長くなってしまいますので、今回は登録フェーズをなぞりながら、実際のデータを確認してみましょう。


例えば、 JavaScript API で https://example.com から、以下のような Registration Request がきたとします。



このデータを Raw Message Formats に変換するには、まずは ClientData と呼ばれる JSON String を作成します。


ClientDataのメンバは “type”, “challenge”, “origin”, “cid” とありますが、U2Fデバイス登録の際は、

・type: “navigator.id.finishEnrollment” 固定

・challenge: サーバーからのチャレンジ string そのまま

・origin: HTTP 通信なら、認証するドメイン

・cid:  option。 channel ID という Token Binding を実現する署名に使われる JwkKey 形式の公開鍵です。、今回は割愛です。


Raw Message Formats 側では JSON の SHA256 のハッシュを取った値を使います。

これが Challenge Parameter になります。(16進数表記です)


また、JSONをを Web Safe Base64 Encode したものは、 ClientData としてサーバーに送信します。


Web Safe Base 64 とか URL Safe Base64  とか呼ばれている “/” を “_”, “+” を “-” に変える例のアレです。ただしパディングは削除します。(つまり末尾の === は削除します)

このパラメータはサーバーに送るためにBase64エンコードしただけで、このデータをAuthenticator との通信で使うわけではありません。私はエンコードしてからHashをとってしまい動かないということがありました。


もう一つのパラメータとして appId(“https://example.com”) の sha256 ハッシュを取ったものを Appication Parameter とします。

この二つを合体させたものが Registration Request Message です。

※FIDO U2F Raw Message 4.1 Fig. 2 Registration Request Message



APDU Format


次に、U2F Raw Message フォーマットは APDU Format で HID デバイスに送られます。


APDU Format はヘッダ部にデータ長やコマンドパラメータを指定する必要があり、Registration時のコマンドパラメータは以下のようになっています。


APDU のデータには Short Encoding と Extended Length Encoding の2種類があり、 U2F では Short Encoding を利用します。

※Le はレスポンスデータの最大サイズを規定するのですが、 最大長を 256 bytes に設定する場合は無視されます。



HID Protocol


あとは、HIDデバイスにデータを送るだけなのですが、 HIDデバイスへの書き込みは 64byte ずつしかできません。


また APDU format 同様ヘッダが以下のように付きますので、実際に送るデータはこんな感じです。

・※チャンネルIDはデバイスの初期化時に取得

・※コマンドの 7番目の bit は常に1 


DATAは先ほどの APDU データです。計 71 byte(0x47)ですが、 HIDのパケットは 64 byte であり、HID Transport 用のヘッダー 7 byte をのぞいた 57 byte しか送れません。残りのデータはシーケンスデータとして以下のような形で送ります。

あとはデバイスからのレスポンスを読みます。

つまり、今度は HID protocol → APDU format → U2F Raw Message Format と逆にたど

っていって、デバイスのレスポンスを取得します。



FIOD2について

いまさらながらの情報でしたが、いかがでしたでしょうか。


冒頭の話と重なりますが、なぜいまさら U2F のホスト側の通信の解説をしたかというと、 FIDO2 での CTAP2 でも同様のプロトコルが使われており、練習台にちょうどよかったからです(CTAP1のほうがずっと簡単)。


CTAP2では PIN関連のコマンドが増えていたり、送るデータも増えており、かつ標準化され CBOR と呼ばれるフォーマットになっていたりします。


今週末の #fidocon では CBOR についての解説が聞けるそうですので、勉強してきましたらブログをアップデートしたいと思います。


bottom of page