BitVisor の ID管理(idman)をつかう #1

BitVisor のID管理（以下、idman）はもともと国家公務員身分証ICカードに BitVisor専用アプリ（以下、BitVisorAP）を入れて使うためのライブラリとして開発されました。しかし現在 BitVisorAP を搭載したICカードは入手できないため、せっかくの idman ライブラリが活用されていません。そこでこの記事では BitVisor の idman ライブラリをマイナンバーカードの 公的個人認証AP（JPKI－AP） で使えるか検証します。

マイナンバーカードの公式情報は[こちら](https://www.soumu.go.jp/kojinbango_card/)

# 免責事項

この記事に書かれている情報の利用または行為によって発生したいかなるトラブル・損失・損害に対して、著者は一切の責任を負いません。またこの記事はICカードリーダのためのオープンな標準規格に基づいており、リバースエンジニアリングなどとは一切関係ないことをお断りしておきます。本記事はオープンソースの観点からマイナンバーカードを用いた公開鍵基盤（PKI）サービスの活用を促進し、それをもってサイバーセキュリティの高度化を進めることを目的としています。

# 公開鍵基盤（Public Key Infrastructure）の基礎

公開鍵基盤（Public Key Infrastructure、略して PKI）は公開鍵証明書を使った認証基盤のことです。電子証明書（X.509）は ITU-T で標準化されています。PKI対応ICカードには、利用者の電子証明書（Public Key Certificate, 公開鍵証明書とも呼ぶ）、それに対応する秘密鍵、CA（Certification Authority、認証局）の電子証明書、が入っています。秘密鍵はICカード内部で生成され、原則としてICカードの外に出さないように設計されています。ssh-keygenをICカード内部で実行すると言ったらわかりやすいかもしれません。

PKI対応カードの一種であるマイナンバーカードの 公的個人認証AP には２種類の鍵ペア（と電子証明書）が入っていて、それぞれ「署名用」と「利用者認証用」に用途が分かれています。前者は電子署名（否認防止）用途で e-Tax とかで使われるもの、後者が認証用途でHTTPSのクライアント認証などで使われることを想定したものです。

ICカードになんらかのデータ（大抵はハッシュ値のようなダイジェスト）を送ると、ICカードのプロセッサがそのデータを内部の秘密鍵で暗号化して結果だけを返します。上記の２つの機能はどちらもこの機能を使います。利用者の電子証明書は、発行元の CA（政府CA）の電子証明書で検証でき、なおかつ失効していなければ(厳密にはOCSPとかCRLで確認）、その秘密鍵は今も有効と考えます。秘密鍵が耐タンパ性をもつICカードにはいっていて、ICカードは利用者が所持しており、かつICカードを使うには利用者PINが必要であることで安全性を担保しています。

公開鍵基盤（PKI）は信頼チェーンを作るのに適していますが、実際は証明書の失効検証や再発行などの運用が大変です。そんなこともあって個人利用では公開鍵だけを使うことが多いです。たとえば id_rsa.pub を cat して github.com に登録したり、ssh 接続先の authorized_keys に登録するといった使い方です。hamanoさんが [マイナンバーカードで ssh する方法](https://www.osstech.co.jp/~hamano/posts/jpki-ssh/) を紹介していて参考になります。証明書から公開鍵だけを取り出して使っています。

# BitVisor のID管理（idman）ライブラリ

前置きが長くなりましたが本題に入ります。ICカード関連は idman ディレクトリにあります。せっかく多くの人たちが開発に携わったオープンソースのライブラリですから有効活用してもらいたいと思って記事を書いています。

ICカードといっても 実は AP （ICカードに入っているアプリ）の仕様以外はオープン規格で作られています。このため BitVisor がサポートしている PC/SC 標準ライブラリでそのままマイナンバーカードにアクセスできます（あとの実験で示します）。

idman のディレクトリ構成は以下のとおりです。実際のところ BitVisor のICカード関連ライブラリは Linux のオープンソースソフトウェア pcsc-lite、ccid、libusb を素直に移植した形になっています。ハイパーバイザである BitVisor は OS なしで動きますから（それ自体がOSのようなものですから）、上記のライブラリが必要とする glibc なども直接実装されています。厳密には USB 関連はID管理ライブラリとしてではなく drivers/usb 以下に実装されています（あとで実際に使っていきます）。

| ディレクトリ名 | 目的 | 関数の例 |
|--------------|------|--------|
|pcsc/ | PC/SC対応カードリーダの接続 | SCardEstablishContext |
|pkcs11/ | PKCS#11 暗号トークンAPI | C_GetFunctionList |
|ccid/ | CCID対応カードリーダの接続 | GetCardStatus | 
|standardio/ | 上記ライブラリが使う glibc や libusb | IDMan_StMemcpy |
| iccard/ | BitVisor独自のICカード管理層（フックポイント） | IDMan_SCardEstablishContext |
| idman_pkcs11/ | BitVisorAP専用 API | IDman_IPInitializeReader |

とくに上の３つのディレクトリは汎用性が高く利用価値の高いライブラリです。

上記の idman ライブラリを利用するコードはいろいろあります。例えば、BitVisor の起動時にユーザ認証するコードが bitvisor/boot/login/minios_init/minios_init.c にあります。ICカードの BitVisorAP に保管してあるプレーンパスワードを使って認証する方式（弱い）、BitVisorAP内部の秘密鍵で認証する方式（強い）の２種類があります。マイナンバーカードの公的個人認証AP は後者に近いものです。

minios_init.c の最後には BitVisor 組み込み IPsec VPN モジュールのリモートアクセスVPN で使われる電子証明書をICカードから取り出す処理が入っています。IPsec VPN モジュールでは IKE (Internet Key Exchange) プロトコルの認証にもICカードを利用していたはずです（コードは vpn/kernel.c あたりかと）。BitVisor がハイパーバイザ層でストレージを暗号化する機能もあり、ICカードからAES鍵を取り出すのに使っていたコードが core/io_iohook.c にあります。これを後々テストに使います。

# まずは Linux で事前検証
BitVisor でマイナンバーカードを使う前に、いちど Linux で ICカードリーダとの通信を確認しておきます。いきなり BitVisor でICカードのデバッグをするのは大変ですし、ICカードリーダとマイナンバーカードの動作確認もできます。PC/SC 接続や APDU (Application Protocol Data Unit) コマンドの基本的な仕組みを理解するのにも役立ちます。

# テスト環境： VMware Fusion 11.5 + BitVisor + CentOS7

いまお読みになっているこの記事は VMware Fusion 11.5 + BitVisor + ゲスト CentOS 7 の上で動作を確認しています。今回は特別に作業を効率化するために VMware Fusion を使っていますが、本来は 実マシン + BitVisor + ゲストOS で動くシステムです（本来は VMware Fusion は不要です）。

VMware Fusion で Nested VM と IOMMU オプションを有効にして CentOS7をインストールし、その上で BitVisor を make して grub に設定しました。再起動すると、VMware Fusion のうえで BitVisor が起動し、その上で CentOS が動きます。このとき、BitVisor の準パススルードライバ（Intel Pro1000, ahci, xhci, uhci）もちゃんと動くことを確認しました。なお、ICカードリーダに関しては VMware の設定ファイル（.vmx）に以下の２行を追加してあります。

```
usb.generic.allowCCID = "TRUE"
usb.ccid.disable = "TRUE"
```

ICカードリーダは接触型の SCM SCR 3310 を使います。Amazon で1500円くらいで購入できます。e-Tax している方はおそらくご自分のICカードリーダを使えるはずです。ただソニーのパソリも試しましたが Linux ではそのままで認識してくれませんでした。安いもののほうが汎用部品を使っているので認識しやすいのかもしれません。今回のICカードには自分のマイナンバーカードを使います。

これ以降は、この記事の最初の免責事項をもう一度確認してください。

# Linux に OpenSC をインストール

OpenSC はスマートカードのためのオープンソースライブラリです。ヨーロッパでは OpenSC のようなオープンソースライブラリを使って National ID card を使ったプログラミングができる国があるようです。日本人の [hamano さん](https://www.jnsa.org/seminar/pki-day/2017/data/170419_hamano.pdf) がマイナンバーカードを OpenSC で使えるようにしてくださっていますので有り難く使わせていただきましょう。

```
$ sudo yum install opensc
```

OpenSC をインストールすると、依存ライブラリとして pcsc-lite と pcsc-lite-ccid が一緒にインストールされます。BitVisor に実装されているのはこの pcsc-lite と pcsc-lite-ccid の部分になります。ほかに libusb を使っていますがこちらも BitVisor に実装されています。

# ICカードリーダの認識

まずはICカードリーダが認識されているか試してみましょう。

```
$ opensc-tool -a
Card Not Present ... この時点ではカードをさしていないのでこれでOK
```

"No smart card readers found." と表示されるときは、lsusb を実行してスマートカードリーダが usb で認識されているか確認します。

```
$ lsusb
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 004: ID 0e0f:0002 VMware, Inc. Virtual USB Hub
Bus 003 Device 003: ID 0e0f:0002 VMware, Inc. Virtual USB Hub
Bus 003 Device 007: ID 04e6:511c SCM Microsystems, Inc.     ... こんな感じで出る
Bus 003 Device 002: ID 0e0f:0003 VMware, Inc. Virtual Mouse
```

なお、これ以降は、マイナンバーカードにカードリーダ経由でアクセスします。たとえば PIN を３回連続して間違えるとICカードがロックされてしまい市役所で解除してもらわないといけなくなります（この記事では PIN入力しなくてよいコマンドだけ扱ってます）。ICカードリーダが認識されたので、自分のマイナンバーカードを挿入して、以下のコマンドを実行してみました。

```
$ opensc-tool -a
Using reader with a card: SCM Microsystems Inc. SCR 3310 [CCID Interface] (21121152201400) 00 00
3b:da:13:ff:81:31:fb:46:80:12:39:2f:31:c1:73:c6:01:c0:3b
```

このコマンドからわかるのは ATR (Answer To Reset) と呼ばれるICカードが返す初期応答の値です。[こちら](http://ludovic.rousseau.free.fr/softwares/pcsc-tools/smartcard_list.txt) に ATR のリストがあり 3b:da...:c0:3b の19バイトの値は "My Number Card (The Social Security and Tax Number System in JAPAN) (eID)" つまり日本のマイナンバーカードへの割り当てであることがわかります。

自分が持っていた ETCカードでも試したところリストの "Japanese ETC (Electronic Toll Collection System) card" の欄の16進数が返ってきました。ATR の値は公開されていて、この ATR によってカード種別を識別します。

# マイナンバーカードの中身

[techmedia-think さん](https://techmedia-think.hatenablog.com/entry/2017/10/21/150246) の記事を参考にしてマイナンバーカードの内容を確認してみましょう。以下は PIN なしで見れるカード内容の概要になります。

```
$ pkcs15-tool --dump
Using reader with a card: SCM Microsystems Inc. SCR 3310 [CCID Interface] (21121152201400) 00 00
PKCS#15 Card [JPKI]:
    Version        : 0
    Serial number  : 00000000
    Manufacturer ID: JPKI
    Flags          : 

PIN [User Authentication PIN]    ... ユーザ認証用のPIN
 ...
PIN [Digital Signature PIN]　　　 ... 電子署名用のPIN
 ...
Private RSA Key [User Authentication Key]  ... 認証用の 2048 bit RSA 秘密鍵 (a)
    Object Flags   : [0x1], private
    Usage          : [0x4], sign
    Access Flags   : [0x1D], sensitive, alwaysSensitive, neverExtract, local
    ModLength      : 2048
 ...
Private RSA Key [Digital Signature Key] ... 電子署名用（否認防止用）の 2048 bit RSA 秘密鍵 (b)
    Object Flags   : [0x1], private
    Usage          : [0x204], sign, nonRepudiation
    Access Flags   : [0x1D], sensitive, alwaysSensitive, neverExtract, local
    ModLength      : 2048
 ...
Public RSA Key [User Authentication Public Key] ... 認証で使われる公開鍵 (a)
 ...
Public RSA Key [Digital Signature Public Key] ... 電子署名で使われる公開鍵 (b)
 ...
X.509 Certificate [User Authentication Certificate] ... CAが発行した(a)の電子証明書
 ...
X.509 Certificate [Digital Signature Certificate] ... CAが発行した(b)の電子証明書
 ...
X.509 Certificate [User Authentication Certificate CA] 認証で使われるCAの電子証明書
 ...
X.509 Certificate [Digital Signature Certificate CA] 電子署名で使われるCAの電子証明書
 ...
```

実際に電子証明書を取り出して openssl で証明書を text 形式で表示してみます。BitVisor に openssl が移植されている理由のひとつはこのように ASN.1 形式の電子証明書バイナリを処理するのに必要だからだと思います。

```
$ pkcs15-tool --read-certificate 1 > hoge.pem
$ openssl x509 -text -noout -in hoge.pem | less
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: XXXXXXX (0xXXXXXX) .. シリアル番号は消してあります
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=JP, O=JPKI, OU=JPKI for user authentication, OU=Japan Agency for Local Authority Information Systems
        Validity
            Not Before: Mar  1 16:37:54 20XX GMT
            Not After : Sep 21 14:59:59 20XX GMT
   ... この後、CN などの個人情報が続くので省略
```

マイナンバーカードの認証用証明書の後ろには失効状態をチェックする OCSP (Online Certificate Status Protocol) の URI や CRL (Certificate Revocation List) の配布ポイントが記載されていて面白いんですが BitVisor と関係ないので先に進みます。

# マイナンバーカードとおしゃべりする（１）

以下はマイナンバーカードの公的個人認証APに SELECT FILE コマンドを発行した例です。

```
$ opensc-tool -s 00:A4:04:0C:0A:D3:92:F0:00:26:01:00:00:00:01
Using reader with a card: SCM Microsystems Inc. SCR 3310 [CCID Interface] (21121152201400) 00 00
Sending: 00 A4 04 0C 0A D3 92 F0 00 26 01 00 00 00 01 
Received (SW1=0x90, SW2=0x00) ... 0x90 0x00 は 成功コード (HTTP 200 みたいなもの） 
```

マイナンバーカードの APDU 仕様については、[geboさんら](https://qiita.com/gebo/items/6a334b5453817a587683) が公開しています。スマートカードではカードとカードリーダの間の PC/SC通信（APDUのやりとり）は暗号化されず平文でやりとりされています。ですから、AP の仕様は事実上ほぼオープン仕様といっていいと思います。マイナンバーカードの安全性はICカード自体の対タンパ性やサイドチャネル攻撃への耐性に基づいており、APDU プロトコルの仕組みを秘密にしても安全性は高まりません（というか前述の仕様のため秘密にはできません）。たとえばヨーロッパの国であるエストニア（フィンランドのおむかい）では National ID card の仕様が公開されています。

さて、opensc-tool をつかうと APDU コマンドをカードに送れますが、毎回カード状態がリセットされるので、SELECT FILE したあとで、READ BINARY するような連続的な処理をする場合には、この次に説明するようにプログラムを書く必要があります。

# マイナンバーカードとおしゃべりする（２）

さきほどは一言しかおしゃべりできませんでしたから、今度はちゃんと会話をしたいですね。以下のように pcsc-lite の Python ラッパーをインストールして python プログラムを書きます。

```
$ sudo yum install python-pyscard
```

pcsclite などの作者として有名な [Rousseau さんのブログ] (https://ludovicrousseau.blogspot.com/2010/04/pcsc-sample-in-python.html) を参考にしてマイナンバーカードから証明書を取り出すプログラムをつくります。マイナンバーカードの APDU はさきほどの [geboさんの記事](https://qiita.com/gebo/items/6a334b5453817a587683) を参考にしました。

```
#! /usr/bin/env python

from smartcard.System import readers

SELECT_AP = [0x00, 0xA4, 0x04, 0x0C, 0x0A, 0xD3, 0x92, 0xF0, 0x00, 0x26, 0x01, 0x00, 0x00, 0x00, 0x01]
SELECT_AUTH_CERT = [0x00, 0xA4, 0x02, 0x0C, 0x02, 0x00, 0x0A]
READ_BINARY_HEAD = [0x00, 0xB0, 0x00, 0x00, 0x04]

r = readers()
print "Available readers:", r

reader = r[0]
print "Using:", reader

connection = reader.createConnection()
connection.connect()

data, sw1, sw2 = connection.transmit(SELECT_AP)
print "Response to SELECT APP: %02X %02X" % (sw1, sw2)
print data

data, sw1, sw2 = connection.transmit(SELECT_AUTH_CERT)
print "Response to SELECT FILE: %02X %02X" % (sw1, sw2)
print data

data, sw1, sw2 = connection.transmit(READ_BINARY_HEAD)
print "Response to READ BINARY: %02X %02X" % (sw1, sw2)
tmp = ""
for x in data: tmp += "%02X " % x
print tmp

# このあとで READ BINARY を 256 byte 単位で発行して証明書全体を読み込む（今回は PoC なのでここまで）
```

以下がマイナンバーカードで実行した結果です。なお、このように PIN 不要で取得できるのは認証用の公開鍵証明書のみで、電子署名用の証明書にアクセスするには PIN入力が必要です。（e-Tax では後者が使われているから PIN 入力が必要なんですね）

```
$ python test.py 
Available readers: ['SCM Microsystems Inc. SCR 3310 [CCID Interface] (21121152201400) 00 00']
Using: SCM Microsystems Inc. SCR 3310 [CCID Interface] (21121152201400) 00 00
Response to SELECT APP: 90 00   ... 0x90 0x00 は正常終了の応答
[]
Response to SELECT FILE: 90 00  ... 0x90 0x00 は正常終了の応答
[]
Response to READ BINARY: 90 00  ... 0x90 0x00 は正常終了の応答
30 82 06 1E  ... 最初の４バイトを受信
```

最後に証明書バイナリの最初の４バイトを読んでいます。電子証明書は ASN.1 形式バイナリで取り出せるので、最初に [TLV](http://directory.apache.org/api/internal-design-guide/4.1-asn1-tlv.html) を解析します。結果の 0x30 0x82 0x06 0x1E のうち、最初の 0x30 が Tag, 0x82 からは続く２バイトにバイナリの長さがあることがわかり、最後の 0x06 0x1E によって 1566バイトのバイナリがあることがわかりました。１回の READ BINARY では 256バイトまでしか取得できないため、このあと READ BINARY を [0x00, 0xB0, 0x00, 0x00, 0x00], [0x00, 0xB0, 0x01, 0x00, 0x00]... と続けて実行していって 1566バイトの証明書バイナリ全体を取得することになります。

今回は pcsc-lite を使ってマイナンバーカードに APDU を送れる事を確認したかっただけなのでここで終わりにします。

# デバッグ

Linux では pcscd デーモン（pcsc-liteに含まれる）が APDU のやりとりを行なっています。このデーモンを以下のようにデバッグオプション付きで実行すると、ICカードの状態遷移や交換された APDU を記録してデバッグできます。

```
$ sudo LIBCCID_ifdLogLevel=0x000F pcscd --foreground --debug --apdu --color | tee /tmp/log.txt
```

# BitVisor での検証
前述のとおり、BitVisor の ID管理(idman)ライブラリには ICカードへ接続する仕組み（PC/SC, CCID, libusb）が実装されています。これから BitVisor のID管理(idman)ライブラリでマイナンバーカードを利用する方法を説明していきますが、長くなりすぎたので続きは [#2](https://qiita.com/hrn/items/798abdde4c2843ee7a26) に書きます。ここまで読んでくださった方、どうも有り難う御座いました（続く）。 ## 実はこの記事をウェブで編集していたときにキーを押し間違えて一回全部消えてしまって大変でした...

# #1 のまとめ
この記事では BitVisor のID管理（idman）の目的とディレクトリ構成を紹介しました。そして Linux の pcsc-lite ライブラリを使ってマイナンバーカードにアクセスする方法を確認しました。