ラズパイでYubikeyを光らせてみる

#はじめに
ラズパイにFIDO2セキュリティキーを接続してCTAPコマンドでお話してみました。

- FIDOとかCTAPって何？
	- 参考:[FIDOとWebAuthnとCTAPのはなし](https://www.slideshare.net/SatoshiSuzuki23/fidowebauthnctap-149340423)
- CTAP
	- 参考:[CTAP2 お勉強メモ#1 - 環境構築(Build)](https://qiita.com/gebo/items/d2ffbd4fcf7d75e21b63)

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252291/919cc98e-33a3-b055-e214-0633b034f683.jpeg" width=70%>

#環境
- ラズパイ:[Raspberry Pi 3 Model b+](https://www.amazon.co.jp/RS%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88Raspberry-Pi-3-B-%E3%83%9E%E3%82%B6%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89/dp/B07BFH96M3)
- ラズパイのOS:[raspbian stretch (2019-04-08)](http://ftp.jaist.ac.jp/pub/raspberrypi/raspbian/images/raspbian-2019-04-09/)	
- 光らせるFIDO2セキュリティキー:[Security Key by Yubico](https://www.yubico.com/product/security-key-by-yubico)
- 言語:Python 3.5.3

####補足
#####ラズパイのバージョンについて
2019/7/30時点でRaspbinはBusterというバージョンなんですが、これ新しすぎてちょっとアレなんで一つ前のStrechというバージョンを使います。Strechをインストールする方法については以下を参考にしました。
→参考:[Raspbian Busterリリース！Stretchとの違いとStretchの入手方法](https://camp.isaax.io/ja/tips-ja/raspberry-pi/raspbian-buster-vs-stretch)

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252291/14f4f5ce-9b62-f48d-32f1-46ab3be56c63.png" width=50%>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252291/9b28c942-099b-5baa-be78-fe53cfdd3904.png" width=30%>

#####ここまでセットアップした状態から始めます

- ラズビアンstrechはセットアップ完了して、ラズパイ起動できる状態
- Wifi接続済み
- 日本語入力システムインストール済み
	- 参考:[Raspberry Pi3の日本語入力を有効にする](https://qiita.com/Higemal/items/6cde9d6b40cbe9f0e97f)
- VNC・SSH接続できる状態
	- 参考:[WindowsからRaspberry Pi 3 Model B+にリモート接続する](https://qiita.com/NagaokaKenichi/items/edab135b4118a47c821c)

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252291/4e7c64b4-14f4-c0dc-2d74-1beacdc2d98b.png" width=70%>


#サンプルプロラム実行までの手順

###pythonのバージョン確認
pythonの2と3が最初から入っています。今回はpython3でやります。

```bash:pythonのバージョン確認
pi@raspberrypi:~ $ python --version
Python 2.7.13
pi@raspberrypi:~ $ python3 --version
Python 3.5.3
```

###openssl 1.0.2のインストール
まず、OpenSSLをいれます。
pipでインストールできませんでした。どうやらラズパイ用のOpenSSLはないらしく、仕方がないので、ソースを落としてきてビルドします。

```console:openssl_1.0.2のインストール
wget https://www.openssl.org/source/openssl-1.0.2.tar.gz
tar xvf openssl-1.0.2.tar.gz
cd openssl-1.0.2
./config zlib shared no-ssl2
make && sudo make install

// makeには30分くらいかかります
```

参考:[Raspberry Piに最新版の各種ツール・言語・ライブラリをインストールする](https://qiita.com/kb10uy/items/976a52f687bcb7745fc7)


###サンプルソースのダウンロード
YubicoのサンプルをGitHubから落とします。
どこか作業のフォルダを作ってその中で実行しましょう。
**注意:Python3なのでpip3です**

```console:サンプルソースのダウンロード
// gitでソースを落とす
git clone https://github.com/Yubico/python-fido2.git

// fido2をインストールする
pip3 install fido2

// インストールに成功すると
// Successfully installed asn1crypto-0.24.0 cffi-1.12.3 cryptography-2.7 fido2-0.7.0 pycparser-2.19 six-1.12.0
// と出る

// ちゃんとfido2がインストールされたかどうか確認
pip3 list | grep fido2
// fido2 (0.7.0)とか出ればOK
```

###サンプルソースの実行
落としてきたサンプルソースのexamplesディレクトリにpyが今回実行するサンプルです。

####get_info.py
FIDO2キーの情報をGETして出力するサンプルです。

ラズパイのUSBにYubikeyを刺して、get_info.pyを実行します。
Yubikeyがビカビカ光って、結果が表示されたらOK。

キーに[GetInfoコマンド](https://qiita.com/gebo/items/e0bd197d607312dcf4fb)を送ってGETしたキーの情報を出力したあと、Winkコマンドを送ってキーを光らせているようです。

**注意:pyの実行はpython3**

```bash:get_info.py
pi@raspberrypi:~/work/python-fido2-master/examples $ python3 get_info.py

// ここからが実行結果（適当に改行いれてます）
CONNECT: CtapHidDevice(/dev/hidraw1)
CTAPHID protocol version: 2
DEVICE INFO: Info(
  versions: ['U2F_V2', 'FIDO_2_0'], 
  extensions: ['hmac-secret'], 
  aaguid: h'fa2b99dc9e3942578f924a30d23c4118', 
  options: {'clientPin': True, 'up': True, 'rk': True, 'plat': False},
  max_message_size: 1200, pin_protocols: [1]
)

WINK sent!
```

####credential.py
キーにクレデンシャルを登録して、認証を行うサンプルです。

CTAPの以下のコマンドが使われています。

- [authenticatorMakeCredential](https://qiita.com/gebo/items/2cfc3202cd88a59b24ba)
- [authenticatorGetAssertion](https://qiita.com/gebo/items/634aa39b0e08d8258682)
- [authenticatorGetNextAssertion](https://qiita.com/gebo/items/cfc6ceb1c7f9aa5fdad6#getassertion--rp%E3%81%AB%E5%AF%BE%E3%81%97%E3%81%A6%E8%A4%87%E6%95%B0%E3%81%AEuser%E3%81%8C%E7%99%BB%E9%8C%B2%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%A9%E3%81%AE%E3%82%88%E3%81%86%E3%81%AA%E6%8C%99%E5%8B%95%E3%81%AB%E3%81%AA%E3%82%8B%E3%81%AE%E3%81%8B)
- [authenticatorClientPIN](https://qiita.com/gebo/items/84454583daeaf6711fd0)

```bash:credential.py
pi@raspberrypi:~/work/python-fido2/examples $ python3 credential.py
Use USB HID channel.

Please enter PIN:
// ◆ここでPINを入力してENTERします

Touch your authenticator device now...
// ◆ここでキーをタッチします

// キーにクレデンシャルを登録して成功すると以下のログが出る
New credential created!
CLIENT DATA: {
  "origin": "https://example.com", 
  "clientExtensions": {}, 
  "challenge": "Y2hhbGxlbmdl", 
  "type": "webauthn.create"
}

ATTESTATION OBJECT: AttestationObject(
  fmt: 'packed', 
  auth_data: AuthenticatorData(
    rp_id_hash: h'a379a6f6...2fa13d2125586ce1947', 
    flags: 0x45, 
    counter: 66, 
    credential_data: AttestedCredentialData(
      aaguid: h'fa2b99dc9e3942578f924a30d23c4118', 
      credential_id: h'9b26...f262d2bfbb3525cf8b', 
      public_key: {
        1: 2,
        3: -7,
        -1: 1,
        -2: b'\x00\x...84\x99`\x9f/\xda', 
        -3: b'\x98\x...x9f\x90J\xe5\xda'
      }
    ), 
    att_statement: {
      'alg': -7, 
      'sig': b'0F\x02!\...xd3+\xaap\xa7|\x1bBKA\xd9X', 
      'x5c': [
        b'0\x82\x02\xbc9...9\xff\xbc\x93\x8c\xa0\xb47'
      ]
    }
  )

CREDENTIAL DATA: AttestedCredentialData(
  aaguid: h'fa2b99dc9e3942578f924a30d23c4118', 
  credential_id: h'9b262e9c0fe5fa34d7a687b5cc1b81abd9ecebee055de2f9c04985b0b691c41f059f4ab3e043bec57426863ba1f05288de1f27d36b8e935762d2bfbb3525cf8b', 
  public_key: {
    1: 2,
    3: -7,
    -1: 1,
    -2: b'\x00\xbdm\xce\xc2\xc2\xb0!#u\xc18\xb9Z\xd5R[A\x14\xea\xfe\xc6F\xe1T\xcc\x84\x99`\x9f/\xda',
    -3: b'\x98\x89,\xa9\xacv\x92\xa9q7\xee;\xa3\xf1\x7f\x1f-%\xb0[\x80\xeeR\xf0\xb8|\xee\x9f\x90J\xe5\xda'
  }

Attestation signature verified!
// 登録完了した、という意味。

// 認証のテスト
Touch your authenticator device now...
// ◆もう一度キーにタッチします。

Credential authenticated!
CLIENT DATA: {
  "origin": "https://example.com", 
  "clientExtensions": {},
  "challenge": "Q0hBTExFTkdF",
  "type": "webauthn.get"
}

ASSERTION DATA: AssertionResponse(
  credential: {
    'id': b"\x9b&.\x9c\xd2\xbf\xb\xcf\x8b...", 
    'type': 'public-key'
  }, 
  auth_data: AuthenticatorData(
    rp_id_hash: h'a379ad30ab13d21255ce1947...', 
    flags: 0x05, 
    counter: 67
  ), 
  signature: h'3044022016c0224af4814eaa6cb...'
)
Assertion signature verified!
// 認証も完了した、という意味
```

#ラズパイでVSCODEでpyをデバック実行してみる
さて、次はこのサンプルプログラムをデバック実行してみたくなります。
ラズパイに開発環境を導入します。
開発環境は今最もモダンなVSCODEにします。
（VSCODEはラズパイではcode-ossっていう名前です）

このcode-ossですが、セットアップにトラップが2つあります。（2019/7/30時点）

###トラップ1
あちこちのサイトで以下の2発のコマンドでインストールしていますが、私の環境ではエラーになりました。このやり方はNGです。

```bash:code-ossのインストール→失敗
sudo -s
. <( wget -O - https://code.headmelted.com/installers/apt.sh )

// 色々処理が走って、最後に以下のエラーメッセージが出てインストール失敗する
// E: 認証されていないパッケージがあり、-y オプションが --allow-unauthenticated な しで使用されました
// Visual Studio Code install failed.
```

###トラップ2
code-ossをインストールできても、起動したら真っ黒なウィンドウがでてくるだけでなんもできません。最新バージョンのモジュールはダメみたいです。

参考:[RaspberryPiにVSCodeをインストールして起動してもウィンドウに何も表示されない問題](https://qiita.com/sh00t/items/af46724fabadef4fcfd0)


###というわけで、上記トラップを回避してcode-ossをセットアップする手順は以下の通り

- guiを使うので、SSHではなくVNC接続するか、ラズパイにモニタキーボードつないで直でやりましょう。
- どっか作業ディレクトリを作成して、その中でやりましょう。

####1)apt.shを落としてくる

```bash:
wget  https://code.headmelted.com/installers/apt.sh
```

####2)テキストエディタでapt.shを開いて以下の行を変更する

```bash:変更前
apt-get install -t ${repo_name} -y ${code_executable_name};
#apt-get install -t ${repo_name} -y --allow-unauthenticated ${code_executable_name};
```

```bash:変更後
#apt-get install -t ${repo_name} -y ${code_executable_name};
apt-get install -t ${repo_name} -y --allow-unauthenticated ${code_executable_name};
```

####3)apt.shを実行して再起動する

```bash:apt.shを実行して再起動する
sudo -s
. apt.sh

// こんなコメントが出たらOK
Installation complete!
You can start code at any time by calling "code-oss" within a terminal.
A shortcut should also now be available in your desktop menus (depending on your distribution).

// rebootしましょう
reboot
```

####4)code-ossをダウングレードする

```bash:code-ossをダウングレードする
sudo apt-get install code-oss=1.29.0-1539702286

// コマンドが成功したら、更新しないマークを付けてreboot
sudo apt-mark hold code-oss
reboot
```

####5)code-oss起動！

```bash:code-oss起動！
code-oss
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252291/1fea69d5-b0ba-25af-25f8-07e8df59dda3.png)

あとは適当にoss-codeを操作していくと、勝手にインストールがリコメンドされるので入れていきます。

- japanese
- Python
- Linter Pylint

ラズパイなのでさくさくはいかないですが、デバック実行もOK。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252291/19b20d4f-dd00-3738-870e-837d8170efb3.png)


#おつかれさまでした
いがいと簡単！