Edited at

CTAP2 お勉強メモ#2 - 接続(GetInfo)


はじめに

前回「CTAP2 お勉強メモ#1」の続き。

これはCTAP仕様とサンプルプログラムでCTAPのお勉強をしたメモであります。


目次


  1. サンプルプログラム概要

  2. HIDをOpenしてYubikeyと接続

  3. CTAPHID_INITコマンド

  4. CTAPHID_CBORコマンド

  5. HIDをClose


1.サンプルプログラム概要(info.exe)


info.exeの実行結果


info.exeを実行

C:\project\libfido2\build\examples\Debug>info.exe "\\?\HID#VID_1050&PID_0120#6&1b5e4874&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"

proto: 0x02
major: 0x05
minor: 0x00
build: 0x02
caps: 0x05 (wink, cbor, msg)
version strings: U2F_V2, FIDO_2_0
extension strings: hmac-secret
aaguid: f8a011f38c0a4d15800617111f9edc7d
options: rk, up, noplat, noclientPin
maxmsgsiz: 1200
pin protocols: 1

どうやらYubikeyの情報を出すだけのようです。infoですので当然ですね。


処理はこんな感じ


  • HIDをOpenしてYubikeyと接続

  • CTAPHID_INITコマンドを送信して応答をGET

  • CTAPHID_CBORコマンドを送信して応答をGET

  • HIDをClose

次にこの処理の詳細を説明します。


2. HIDをOpenしてYubikeyと接続


  • 起動引数で指定したYubikeyのパスに接続します。

  • USBに接続されたYubikey(HIDデバイス)へのアクセスはOpen,Send,Receive,Closeといった低レベルAPIを使って行います。

  • これらのAPIは、hidapi.dllというライブラリを使っています。

  • この低レベル部分はCTAP仕様で定義されているものではないので詳細は割愛。


★CTAPHIDコマンドについて

~CTAP仕様書~

8.1. USB Human Interface Device (USB HID)

8.1.4. Message and packet structure

CTAP仕様で定義されているのは、HID通信で送受信するパケット仕様以降です。

CTAPHID_INITコマンドの説明の前に、CTAPHIDコマンドについて説明する必要があります。

CTAPでHID通信では以下の仕様が定められています。(細かく見るとかなりめんどくさいルールが色々あるようです。いろんなケースを想定しているのでしょう・・・)


  • HID通信用のパケット仕様がある。

  • パケットは初期パケット(initialization packets)と継続パケット(continuation packets)があり、フォーマットが少し違う。

  • 1パケットは64byte と決まっていて、送信データが1個のパケットに収まりきらない場合、初期パケット+継続パケットの複数パケットに分割して送信する。

  • 1パケットの送信データが64byteより少なくても後方にゼロを詰めて必ず64byteで送信する。


初期パケット(initialization packets)

項目
サイズ
説明1
説明2

CID
4
Channel identifier
チャネル識別子※

CMD
1
Command identifier (bit 7 always set)
コマンド(7bit目は1にしとけと書いてある)

BCNTH
1
High part of payload length
送信データのサイズ※

BCNTL
1
Low part of payload length
送信データのサイズ※

DATA
x
Payload data
送信データ


  • ※チャネル識別子(CID)について


    • CIDという識別子を指定する必要がある。

    • これはデバイス側で採番するものであり、クライアントは採番されたCIDを指定する必要がある。

    • では、どうやって採番するのか、ということですが、CIDに0xffffffffを指定してCTAPHID_INITを送信すると、Responseで採番されたCIDをGETすることができる。



  • ※送信データのサイズ


    • データサイズはBCNTHとBCNTLに分かれていて、要はushortの下位バイトと上位バイトって事かと思います。

    • このパケットのサイズではなく(パケットは64byteと決まっているので)送信データ全体のサイズをここにセットします。




継続パケット(continuation packets)

項目
サイズ
説明1
説明2

CID
4
Channel identifier
チャネル識別子

SEQ
1
Packet sequence 0x00..0x7f (bit 7 always cleared)
0~のパケット連番

DATA
x
Payload data
送信データ


3. CTAPHID_INITコマンドを送信して応答をGET

というわけで、CTAPHID_INITの説明

ここでの送受信データは以下の通り


CTAPHID_INIT_Packetログ

  // Platform → Authenticator 送信データ

// 1packet(64byte)
ff ff ff ff 86 00 08 fc 8c c9 91 14 b5 3b 12 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

// Platform ← Authenticator Response
// 1packet(64byte)
ff ff ff ff 86 00 11 fc 8c c9 91 14 b5 3b 12 00
1d 00 08 02 05 00 02 05 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00



CTAPHID_INITコマンド(0x06)


  • CIDの割り当て要求コマンド。

  • 最初にこのコマンドCIDをGETし、以降のメッセージのCIDに指定します。

項目
サイズ

説明

CID
4
0xffffffff
CIDの割り当て要求という意味

CMD
1
0x86
CTAP_INITという意味※

BCNTH
1
0
データが8byteなのでここは0でよい

BCNTL
1
8
データ長

DATA
8
8-byte nonce
8バイトのnonce※


  • ※CMDについて


    • CTAPHID_INITは0x06なんですが、CMDフィールドは 7ビット目を1たてるという謎のルールがある ので 0x80|0x06(CTAPHID_INIT)⇒0x86 を設定します



  • ※nonceについて


    • 送信側が決めた8byteの値。応答にも含まれるので送信に対する応答かどうかチェックに使いましょう(ということらしい)。




応答パケット

CTAPHID_INIT (0x06)コマンドに対してこんな応答が返ってきます。

項目
サイズ

説明

CID
4
0xffffffff
送信データと同じ

CMD
1
0x86
送信データと同じ

BCNTH
1
0

BCNTL
1
17
データサイズ

DATA
8
送信で指定したnonce

DATA
4
割り当てられたCID

DATA
1
CTAPHID protocol version identifier

DATA
1
Major device version number

DATA
1
Minor device version number

DATA
1
Build device version number

DATA
1
Capabilities flags


先ほどのCTAPHID_INIT Packetログ をパースすると

Platform → Authenticator 送信データ=CTAPHID_INIT(0x06)コマンド


  • CID=0xff ff ff ff (CID要求)

  • CMD=0x86 (CTAPHID_INIT(0x06)コマンド)

  • BCNTH=0

  • BCNTL=8

  • DATA=0xfc 8c c9 91 14 b5 3b 12 (nonce)

Response


  • CID=0xff ff ff ff

  • CMD=0x86

  • BCNTH=0

  • BCNTL=11

  • DATA=0xfc 8c c9 91 14 b5 3b 12 (nonce)

  • DATA=00 1d 00 08 (CID)

  • DATA=02 (proto)

  • DATA=05 (major)

  • DATA=00 (minor)

  • DATA=02 (build)

  • DATA=05 (caps=wink, cbor, msg)

CTAP仕様書 = 8.1.9.1.3. CTAPHID_INIT (0x06)


4. CTAPHID_CBORコマンドを送信して応答をGET

CTAP仕様書 = 8.1.9.1.2. CTAPHID_CBOR (0x10)

ここでの送受信データは以下の通り


CTAPHID_CBOR_Packetログ

  // Platform → Authenticator 送信データ

// 1packet(64byte)
00 1d 00 08 90 00 01 04 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

// Platform ← Authenticator Response
// 2 packet(64byte×2)
// initialization packet
00 1d 00 08 90 00 56 00 a6 01 82 66 55 32 46 5f
56 32 68 46 49 44 4f 5f 32 5f 30 02 81 6b 68 6d
61 63 2d 73 65 63 72 65 74 03 50 f8 a0 11 f3 8c
0a 4d 15 80 06 17 11 1f 9e dc 7d 04 a4 62 72 6b

// continuation packet
00 1d 00 08 00 f5 62 75 70 f5 64 70 6c 61 74 f4
69 63 6c 69 65 6e 74 50 69 6e f4 05 19 04 b0 06
81 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00


これがまた、めんどくさいコトになっています。


  • CTAPHID_CBORコマンドとはデバイス(Yubikey)にCBORエンコードしたメッセージを送信するコマンドです。

  • CBORとはJSONを短くすることに特化したエンコード方式のようで、なかなか独特なルールになっています。

  • このCBORエンコードされたメッセージはなにかというと、これまたフォーマットが決まっていて、今回はauthenticatorGetInfoメッセージというものです。

  • 以降でCTAPHID_CBORコマンドとauthenticatorGetInfoメッセージのフォーマットを説明します。


    • ここではCBORの詳細説明はしません。あまりWebには情報がなく、日本語サイトではココしか見つかりませんでした。

    • CBORのエンコードはココでできるので、それで確認しておしまいにします。




CTAPHID_CBORコマンド(0x10)

項目
サイズ
説明1
説明2

CID
4
INITで取得したCIDを指定する

CMD
1
0x90
0x80|0x10⇒0x90

BCNTH
1
High part of payload length
送信データのサイズ

BCNTL
1
Low part of payload length
送信データのサイズ

DATA
x
Payload data
CBORエンコードされたauthenticatorGetInfoメッセージ


authenticatorGetInfoメッセージ(0x04)

Yubikeyのデバイス情報を取得するコマンド。

パラメータなし、単に 0x04 と1byteデータを送ればよい。


応答パケット

CTAPHID_CBOR (0x10)コマンドに対してこんな応答が返ってきます。

initialization packet

項目
サイズ

説明

CID
4
0x00 1d 00 08
送信データと同じ

CMD
1
0x90
送信データと同じ

BCNTH
1
0

BCNTL
1
86
データサイズ

DATA
57

CBORエンコードされたauthenticatorGetInfo Response

continuation packet

項目
サイズ

説明

CID
4
0x00 1d 00 08
送信データと同じ

SEQ
1
0x00
継続パケットNo

DATA
29

CBORエンコードされたauthenticatorGetInfo Response

で、CBORエンコードされたauthenticatorGetInfo Responseだけをまとめるとこうなります。


CBORエンコードされたauthenticatorGetInfo_Response

  // payload len 86

00 a6 01 82 66 55 32 46 5f 56 32 68 46 49 44 4f
5f 32 5f 30 02 81 6b 68 6d 61 63 2d 73 65 63 72
65 74 03 50 f8 a0 11 f3 8c 0a 4d 15 80 06 17 11
1f 9e dc 7d 04 a4 62 72 6b f5 62 75 70 f5 64 70
6c 61 74 f4 69 63 6c 69 65 6e 74 50 69 6e f4 05
19 04 b0 06 81 01

で、これがすべてCBORエンコードというのは正しくなくて最初の1Byteだけ応答ステータスであり、2byteからCBORです。

CTAP仕様書6.2. Responses

キャプチャ7.PNG

さて、このCBORデータですが、CBOR Playgroundというサイトで一発でデコードできます。


CBORデコードログ

A6                                     # map(6)

01 # unsigned(1)
82 # array(2)
66 # text(6)
5532465F5632 # "U2F_V2"
68 # text(8)
4649444F5F325F30 # "FIDO_2_0"
02 # unsigned(2)
81 # array(1)
6B # text(11)
686D61632D736563726574 # "hmac-secret"
03 # unsigned(3)
50 # bytes(16)
F8A011F38C0A4D15800617111F9EDC7D # "\xF8\xA0\x11\xF3\x8C\nM\x15\x80\x06\x17\x11\x1F\x9E\xDC}"
04 # unsigned(4)
A4 # map(4)
62 # text(2)
726B # "rk"
F5 # primitive(21)
62 # text(2)
7570 # "up"
F5 # primitive(21)
64 # text(4)
706C6174 # "plat"
F4 # primitive(20)
69 # text(9)
636C69656E7450696E # "clientPin"
F4 # primitive(20)
05 # unsigned(5)
19 04B0 # unsigned(1200)
06 # unsigned(6)
81 # array(1)
01 # unsigned(1)

↑・・・なんだかよくわかりませんね。いや、よく見ればわかるのですがわかりずらいですね。

これはデコード結果ではなく、CBORパース最中のログです。



CBORデコード結果

{

1: ["U2F_V2", "FIDO_2_0"],
2: ["hmac-secret"],
3: h'F8A011F38C0A4D15800617111F9EDC7D',
4: {"rk": true, "up": true, "plat": false, "clientPin": false},
5: 1200,
6: [1]
}

↑やっと人間にもわかるようになりました。

ただ、これではまだ完全ではありません。

CTAP仕様書 6.2. Responses にこの意味が書いてあります。

image.png

まとめるとこうなるかと

項目
key

versions
1
U2F_V2,FIDO_2_0

extensions
2
hmac-secret

aaguid
3
F8A011F38C0A4D15800617111F9EDC7D

options※
4
rk, up, noplat, noclientPin

maxMsgSize
5
1200

pinProtocols
6
1

~ ※optionsの詳細 ⇒ CTAP仕様書 5.4. authenticatorGetInfo (0x04) ~


4. HIDをClose

省略!


おつかれさまでした

なんとなくわかったきがする・・・

すぐわすれるきがする・・・

CTAP2 お勉強メモ#3


参考