HPKIカードで署名してみる

#はじめに
HPKIカードというカードがありまして、マイナンバーカードと似たようなものですが、それのお医者さん向けのものです。
手元にこのカードのサンプルがあったので中身を見てみたいと思います。
以前投稿した「マイナンバーカード検証」の続きみたいなものです。
- [マイナンバーカード検証#1](https://qiita.com/gebo/items/6a334b5453817a587683)
- [マイナンバーカード検証#2](https://qiita.com/gebo/items/fa35c1f725f4c443f3f3)
- [マイナンバーカード検証#3](https://qiita.com/gebo/items/37fcb50565c5ebeacb7b)

####注意事項
- 日本医師会のサンプルカードを使いますが、[専用のHPKIカードドライバ](https://www.jmaca.med.or.jp/service/index.html#01)を使うものではありません。
- HPKIカードのPINを何度か間違えると**ロックがかかって使えなくなる**（はず）です。
- ロックを解除する方法はここでは記載していないのでご注意ください。
- HPKIカードはいろんな種類があるみたいです。ここで書いてあることが全ての種類のHPKIカードで使えるかどうかはわかりません。

####参考資料
- [JAHIS HPKI対応ICカードガイドラインVer.3.0](https://www.jahis.jp/standard/detail/id=609)
- [IC・ID カードの相互運用可能性の向上に係る基礎調査 報告書](https://www.ipa.go.jp/security/fy18/reports/ICID/index.html) ※古い資料なので注意
 
#目次
[１．環境](#%EF%BC%91%E7%92%B0%E5%A2%83)
[２．ファイル構造](#%EF%BC%92%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E6%A7%8B%E9%80%A0)
[３．おやくそく](#%EF%BC%93%E3%81%8A%E3%82%84%E3%81%8F%E3%81%9D%E3%81%8F)
[４．いろいろやってみる](#%EF%BC%94%E3%81%84%E3%82%8D%E3%81%84%E3%82%8D%E3%82%84%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B)
[４－１．証明書を取り出して公開鍵を取得](#%EF%BC%94%EF%BC%91%E8%A8%BC%E6%98%8E%E6%9B%B8%E3%82%92%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%97%E3%81%A6%E5%85%AC%E9%96%8B%E9%8D%B5%E3%82%92%E5%8F%96%E5%BE%97)
[４－２．PINのリトライ回数を調べる](#%EF%BC%94%EF%BC%92pin%E3%81%AE%E3%83%AA%E3%83%88%E3%83%A9%E3%82%A4%E5%9B%9E%E6%95%B0%E3%82%92%E8%AA%BF%E3%81%B9%E3%82%8B)
[４－３．署名](#%EF%BC%94%EF%BC%93%E7%BD%B2%E5%90%8D)
[４－４．Verify](#%EF%BC%94%EF%BC%94verify)
[５．ファイル構造を知る方法](#%EF%BC%95%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E6%A7%8B%E9%80%A0%E3%82%92%E7%9F%A5%E3%82%8B%E6%96%B9%E6%B3%95)


#１．環境
- Windows10 1803
- .Net Framework 4.6.1
- Visual Studio 2017 C#
- [パソリ-PaSoRi RC-S380](https://www.sony.co.jp/Products/felica/consumer/products/RC-S380.html)
- HPKIカード

検証ツール
- [OpenSSL](https://www.openssl.org/)
- [Git Hub - Lib/DemoApp](https://github.com/gebogebogebo/HPKIReader)

#２．ファイル構造
HPKIカードのファイル構造はこの図のようになっており、認証用と署名用がある、という点ではJPKIと同じですが、APが二つに分かれている、という点で異なっています。
- 電子認証用AP
- 電子署名用AP
名前の通り解釈して、自分自身の認証に使うのが認証用AP、電子署名するときに使うのが署名用APということだと思います。
それで、両方にPrivate Keyがあるんで、どっちでも署名できる、PINはそれぞれ別に持っている、ということになります。

![HPKCardDataModel.png](https://qiita-image-store.s3.amazonaws.com/0/252291/4b440912-5ee3-eb82-56db-050c03d6ecfa.png)

#３．おやくそく
基本的なことはJPKIカードと同じです。
- 証明書を取り出すためにPINは不要。
- Private KeyアクセスにはPINによるアンロックが必要。
- Private Keyにデータを投げつけて署名をGETすることができる。
- PINのリトライ回数は15回、PIN認証を間違えると減っていき、0になると・・・やってないのでどうなるかわかりません。 
- PINのアンロックに成功するとリトライ回数は15に戻る。

#４．いろいろやってみる
認証用APでいろいろやってみます。
（署名用APもAPの識別子が違うだけで同じです）

C#でICカードにアクセスする方法とか、APDUとは何ぞやという場合はこちらを参照⇒[マイナンバーカード検証#1](https://qiita.com/gebo/items/6a334b5453817a587683)

##４－１．証明書を取り出して公開鍵を取得
####(1)APをSELECT
APDU = `0x00 A4 04 00 [10] [E8 28 BD 08 0F A0 00 00 03 91 00 00 00 00 00 02] 00`
※[10]がデータサイズ(0x10⇒16byte)、[E8 28～]がAPの識別子。

####(2)認証用証明書をSELECT
APDU = `00 A4 02 0C [02] [00 16]`
※[02]がデータサイズ(0x02⇒2byte)、[00 16]がFILEの識別子。

####(3)証明書をReadする
(2)でSELECTしたFILEのブロックから証明書をREADします。
証明書データはDER形式で格納されています。
バイナリデータの読み出し方法はこちらを参照⇒[（３）READ BINARY](https://qiita.com/gebo/items/fa35c1f725f4c443f3f3#%EF%BC%93read-binary)

####証明書から公開鍵を取り出す
ここもJPKIと同じです。
⇒[２．認証用証明書から公開鍵を取り出す](https://qiita.com/gebo/items/fa35c1f725f4c443f3f3#%EF%BC%92%E8%AA%8D%E8%A8%BC%E7%94%A8%E8%A8%BC%E6%98%8E%E6%9B%B8%E3%81%8B%E3%82%89%E5%85%AC%E9%96%8B%E9%8D%B5%E3%82%92%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%99)

取り出した公開鍵（バイナリデータ）はVerifyに使うので、ファイルにでも保存しておきます。

※DER形式の証明書を拡張子DERでファイル保存するとWindowsではダブルクリックで中身を見ることができます。見てみると「サブジェクトディレクトリ属性」に**Medical Doctor**と表示されます。
これで、ドクターです、と判断するのかもしれません。

<img src="https://qiita-image-store.s3.amazonaws.com/0/252291/1b34852c-888b-bcd4-4a67-d872e510fc86.png" width=50%>


##４－２．PINのリトライ回数を調べる
これから署名をやっていきますが、PINをつかうので、まずはPINのリトライ回数をチェックできるようにしておきます。PINを間違えすぎると大変なことになります。

####(1)APをSELECT
さっきと一緒

####(2)PINをSELECT
APDU = `00 A4 02 0C [02] [00 02]`

####(3)VERIFY PINコマンド
- APDU = `0x00, 0x20, 0x00, 0x88`
- Response = `0x63, 0xCE`

Responseで`0x63, 0xC?`といった値が返ってきます。このとき`?`にロックまでのリトライ回数が返ってきます。このコマンドでリトライ回数が減ることはありませんので安心してください。

##４－３．署名
やっと署名をするところにきましたが、まず、HPKIカードで『署名』する機能とは一体何なのか、を説明したいと思います。

---
電子署名（でんししょめい）とは、電磁的記録（電子文書）に付与する、電子的な徴証であり、紙文書における印章やサイン（署名）に相当する役割をはたすものである
[wikipediaより](https://ja.wikipedia.org/wiki/%E9%9B%BB%E5%AD%90%E7%BD%B2%E5%90%8D)

---

例えば とあるPDFファイルの署名を得るには、**PDFファイルをバイナリでReadしてHPKIカードに丸ごと送り付けるのか、というと、そうではありません。**

HPKIカードで署名をするには`認証用鍵`FILEにSELECTして、APDUコマンドで**ある形式のデータ**を送信します。そうすると、バイナリデータが返ってきます。それが署名です。
APDUで送信する**ある形式のデータ**は署名対象のファイルのことではなく署名対象のファイルの`Digest Info`です。`Digest Info`とは`PKCS #1 (RFC 3447)` で決められている電子署名の形式です。

つまり、送信側が署名対象のファイルから `Digest Info` 形式のデータを作成して、そのデータをHPKIカードに送信するということです。

具体的な方法はこちらを参照してください　⇒　[電子署名について](https://qiita.com/gebo/items/fa35c1f725f4c443f3f3#%E9%9B%BB%E5%AD%90%E7%BD%B2%E5%90%8D%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)

**OpenSSLのコマンドでいうと（メモ）**
openssl rsautl -sign -inkey hpkiprivatekey.pem -in digest_info_of_targetfile.dat
↑HPKIカードでやっていること

openssl dgst -sha1 -sign hpkiprivatekey.pem targetfile.dat
↑PKCS #1 (RFC 3447)の電子署名をOpenSSLで作成するコマンド

##４－４．Verify
署名検証方法はJPKIと同じです。
⇒[４．検証](https://qiita.com/gebo/items/fa35c1f725f4c443f3f3#%EF%BC%94%E6%A4%9C%E8%A8%BC)

#５．ファイル構造を知る方法
HPKIカードは[このようなファイル構造](#%EF%BC%92%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E6%A7%8B%E9%80%A0)をしていますが、マルチベンダーを想定していて、ある程度自由にファイル構造を定義できるような仕様となっています。ベンダー毎に構造が違っていては実装する側は大変ですので、ファイル構造の定義そのものをカードに格納する仕様になっています。
その仕様が`JIS X 6320-15 (ISO/IEC 7816-15)`で、HPKIカードはこの仕様に基づいてファイル構造を`EF.OD`というファイルに持っています。
`EF.OD`を読み出してカード内のファイル構造を知ることができます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/252291/c6378a91-aa7f-942e-b485-c02bb1e5301a.png)

これは情報が少なくて、JISの資料をみてもわざとわからなくしているような書き方なんで全く理解できないのですが、こちらのサイトでわかりやすく書いてあります。
⇒[Rubyを使ってHPKIカードのデータを読み取る](https://developer.medley.jp/entry/2018/07/12/152331)


#おつかれさまでした
HPKIカードはJPKIカードとほぼ一緒なんで、あまり書くことがなかったなぁ

##参考
- [公開鍵暗号と電子署名の基礎知識](https://qiita.com/kunichiko/items/ef5efdb41611d6cf7775)
- [OpenSSLから覗いた公開鍵暗号方式の謎](http://hkawa117.hatenablog.com/entry/2015/08/06/005217)
- [Rubyを使ってHPKIカードのデータを読み取る](https://developer.medley.jp/entry/2018/07/12/152331)