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

#はじめに
前回「[CTAP2 お勉強メモ#1](https://qiita.com/gebo/items/d2ffbd4fcf7d75e21b63)」の続き。

これはCTAPのお勉強をしたメモです。
**WebAuthn(ウェブオースン)ではなく、CTAP(シータップ)であります。**

- [CTAP仕様](https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html)
- [サンプルプログラム](https://github.com/Yubico/libfido2)
- [CTAP2 お勉強メモ#1](https://qiita.com/gebo/items/d2ffbd4fcf7d75e21b63)

# 目次
1. [サンプルプログラム概要](https://qiita.com/gebo/items/e0bd197d607312dcf4fb#1%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E6%A6%82%E8%A6%81infoexe)
2. [HIDをOpenしてYubikeyと接続](https://qiita.com/gebo/items/e0bd197d607312dcf4fb#2-hid%E3%82%92open%E3%81%97%E3%81%A6yubikey%E3%81%A8%E6%8E%A5%E7%B6%9A)
3. [CTAPHID_INITコマンド](https://qiita.com/gebo/items/e0bd197d607312dcf4fb#3-ctaphid_init%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%82%92%E9%80%81%E4%BF%A1%E3%81%97%E3%81%A6%E5%BF%9C%E7%AD%94%E3%82%92get)
4. [CTAPHID_CBORコマンド](https://qiita.com/gebo/items/e0bd197d607312dcf4fb#4-ctaphid_cbor%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%82%92%E9%80%81%E4%BF%A1%E3%81%97%E3%81%A6%E5%BF%9C%E7%AD%94%E3%82%92get)
5. [HIDをClose](https://qiita.com/gebo/items/e0bd197d607312dcf4fb#4-hid%E3%82%92close)

- [参考](https://qiita.com/gebo/items/e0bd197d607312dcf4fb#%E5%8F%82%E8%80%83)

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

####info.exeの実行結果

```bat: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

<img src="https://qiita-image-store.s3.amazonaws.com/0/252291/d0ce4ae7-aa06-ffaa-982a-3fe4c0eb35d0.png" width=60%>

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

#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)](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#usb)
[8.1.4. Message and packet structure](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#usb-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の説明

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

```bat: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)](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#usb-hid-init)

#4. CTAPHID_CBORコマンドを送信して応答をGET
[CTAP仕様書 = 8.1.9.1.2. CTAPHID_CBOR (0x10)](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#usb-hid-cbor)

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

```bat: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には情報がなく、日本語サイトでは[ココ](https://qiita.com/ritou/items/f3eafedab038d17e3066)しか見つかりませんでした。
	- CBORのエンコードは[ココ](http://cbor.me/)でできるので、それで確認しておしまいにします。

###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だけをまとめるとこうなります。

```bat: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だけ応答ステータスであり、2ｂyteからCBORです。

**～[CTAP仕様書6.2. Responses](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#responses)～**
<img width="779" alt="キャプチャ7.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/252291/66e8bc48-eb02-6eb8-321e-d8a6b12f8f11.png">

さて、このCBORデータですが、[CBOR Playgroundというサイト](http://cbor.me/)で一発でデコードできます。

```bat: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パース最中のログです。

---

```bat: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](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#responses)** にこの意味が書いてあります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/252291/4820f67e-9a41-3e0f-51e9-2b8f71d4a7e5.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)](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#authenticatorGetInfo)　～**

#4. HIDをClose
省略！

#おつかれさまでした
なんとなくわかったきがする・・・
すぐわすれるきがする・・・

[CTAP2 お勉強メモ#3](https://qiita.com/gebo/items/2cfc3202cd88a59b24ba)

#参考
- [Client to Authenticator Protocol (CTAP) Implementation Draft, February 27, 2018](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#usb-hid-implementation)
- [Yubico/libfido2](https://github.com/Yubico/libfido2)
- [CBOR playground](http://cbor.me/)