Simple minds think alike

より多くの可能性を

APDUプロトコルを通じてマイナンバーカードで電子署名する方法

以下の記事では、OpenSCというツールを使ってマイナンバーカードにアクセスしましたが、今回はOpenSCの内部で使われているAPDUプロトコルを使って電子署名をやってみたいと思います。

simple-minds-think-alike.moritamorie.com

まずは、ADPUプロトコルに関してまとめ、実際にAPDU命令をマイナンバーカードに送って結果をみていきたいと思います。

APDUプロトコルとは

APDU (Application Protocol Data Unit) プロトコルとは、接触ICカードが準拠しているISO/IEC 7816の中で定められている通信規格で、この規格に準じてICカードとカードリーダー間の通信が行われることによって様々なICカードの間の相互互換性を維持できています。

APDUの構成・構成ユニット・パターン

構成

APDUは、以下の2つから構成されています。

  • Command APDU (C-APDU) - カードリーダーからICカードに送る
  • Response APDU (R-APDU) - ICカードからカードリーダに送る

構成ユニット

それぞれの構成ユニットは以下のようになっています。

Command APDU(C-APDU)

Command APDU(C-APDU)の概要図

Response APDU(R-APDU)

Response APDU(R-APDU)の概要図

パターン

C-APDUとR-APDU、それぞれの構成ユニットの組み合わせによって4パターンに分類されます。

C-APDUとR-APDUそれぞれの構成ユニットの組み合わせ

使用するAPDUコマンド

本記事では以下3つのAPDUコマンドを使用します。

コマンド CLS(命令クラス) INS(命令コード) 概要 パターン
SELECT FILE 00 A4 ファイルなどの論理チャネルを開く パターン3
VERIFY 00 20 PINなどの確認 パターン3
COMPUTE DIGITAL SIGNATURE 80 2A 電子署名の計算 パターン4

COMPUTE DIGITAL SIGNATUREのパラメータに関してはマイナンバーカード 独自の仕様のようです。 また、Response CommandのStatus Wordに関しては以下を参照しました。

APDUプロトコルで署名

前記事で使用した opensc-tool というツールを使うとAPDUコマンドを送れるので今回も使います。

紹介する検証手順では opensc-tool の実行を1回ずつ実行しているように記載していますが、実行すると途中でエラーが返ってきます。実際には以下のように && で繋げて実行しています。

$ opensc-tool -s 00:A4:04:0C:0A:D3:92:F0:00:26:01:00:00:00:01 && opensc-tool -s 00:A4:02:0C:02:00:1B && 〜〜〜

署名フロー

左側にフロー、右側にマイナンバーカードのデータ構造とした図を掲載しておきます。

APDUプロトコルを使った署名フロー

公的個人認証APをSELECT FILEする

  • CLS(命令クラス): 00
  • INS(命令コード): A4
  • P1(引数1): 04
  • P2(引数2): 0C
  • Lc(データフィールド長): 0A (10進だと10。)
  • Data: DF名 (D3 92 F0 00 26 01 00 00 00 01)
$ opensc-tool -s 00:A4:04:0C:0A:D3:92:F0:00:26:01:00:00:00:01
Using reader with a card: SCR3310 Smart Card Reader
Sending: 00 A4 04 0C 0A D3 92 F0 00 26 01 00 00 00 01
Received (SW1=0x90, SW2=0x00)

②署名用PINをSELECT FILEする

  • CLS(命令クラス): 00
  • INS(命令コード): A4
  • P1(引数1): 02
  • P2(引数2): 0C
  • Lc(データフィールド長): 02
  • Data: ファイル識別子 (00 1B)
$ opensc-tool -s 00:A4:02:0C:02:00:1B
Using reader with a card: SCR3310 Smart Card Reader
Sending: 00 A4 02 0C 02 00 18
Received (SW1=0x90, SW2=0x00)

③署名用PINをVERIFYする

  • CLS(命令クラス): 00
  • INS(命令コード): 20
  • P1(引数1): 00
  • P2(引数2): 80
  • Lc(データフィールド長): 05
  • Data: パスワード(31 32 33 34 35)
    • パスワードは12345を仮定しています。
    • パスワードはアスキーコードで送ります。
$ opensc-tool -s 00:20:00:80:05:31:32:33:34:35
Sending: 00 A4 02 0C 02 00 0A
Received (SW1=0x90, SW2=0x00)

④署名用秘密鍵をSELECT FILEする

  • CLS(命令クラス): 00
  • INS(命令コード): A4
  • P1(引数1): 02
  • P2(引数2): 0C
  • Lc(データフィールド長): 02
  • Data: ファイル識別子(00 1A)
$ opensc-tool -s 00:A4:02:0C:02:00:1A
Received (SW1=0x90, SW2=0x00)

電子署名する

まず、前記事で作成した署名対象のテキストデータファイルの中身を16進数で確認します。

$ xxd message.txt
00000000: 6865 6c6c 6f0a                           hello.

データは 6865 6c6c 6f0a であることが分かりました。

この値をDataとして、COMPUTE DIGITAL SIGNATUREを実行します。このコマンドによって署名用秘密鍵マイナンバーカード の外に送らずに、署名を行うことができます。

  • CLS(命令クラス): 80
  • INS(命令コード): 2A
  • P1(引数1): 00
  • P2(引数2): 80
  • Lc(データフィールド長): 06
  • Data: 署名対象(68 65 6C 6C 6F 0A)
  • Le(期待するレスポンスデータの長さ): 00
$ opensc-tool -s 80:2A:00:80:06:68:65:6C:6C:6F:0A:00
Received (SW1=0x90, SW2=0x00):
5C 9F CA FD 42 46 E3 A0 7B 34 19 B2 5F 5D 19 DB \...BF..{4.._]..
BD F7 13 34 D0 1A 9D 96 29 15 02 4B 61 6A DA D4 ...4....)..Kaj..
CF 77 5C D0 A7 6D 80 F7 4E 8C FC BF A8 66 74 1F .w\..m..N....ft.
9A 2C ED 49 21 72 BD 74 86 16 73 D7 02 EC 4E C8 .,.I!r.t..s...N.
E5 EB FE D1 EC 7D 76 18 4D D3 21 E6 2C 90 D2 70 .....}v.M.!.,..p
1F 2A 6B 79 DF 8E D3 0A 99 DB 46 61 7D 1C 3B AC .*ky......Fa}.;.
C4 65 B2 BA 1B 76 CA FF 02 1A 7A D5 B1 47 30 4B .e...v....z..G0K
2B 20 0A 3C CE 06 9D D3 AB BD C4 89 A3 2F 7F 09 + .<........./..
86 D9 C7 BE 8A 14 29 F7 6E A8 11 E9 1D 7D AA 01 ......).n....}..
E5 EE D7 F8 5A DC F8 61 ED ED 95 50 59 13 97 0C ....Z..a...PY...
A6 71 22 F8 1E 3C 80 A2 A4 B0 BD 8A F3 F0 DF CF .q"..<..........
BB 65 A7 CD B9 84 2E 07 D8 6E 89 26 31 0C 46 91 .e.......n.&1.F.
AD 1B 07 6A 1C 7F 2B 9B 42 CC AC CF F4 9A 86 23 ...j..+.B......#
9D 96 9D AE 87 D3 82 9A 7B CC C3 C5 91 4B A4 EF ........{....K..
1A CA CC 14 BA 7B A7 CA B4 1E A7 EC 26 5B 49 0C .....{......&[I.
EC 5F 85 92 7B 71 FE D0 6F 6A 40 75 D9 9E 9E 4D ._..{q..oj@u...M

署名付きデータ(5C〜4Dまで)を任意のバイナリエディタで保存し、text.sined のように名前をつけて保存します。

署名検証してみる

前記事で作成した公開鍵(sign.pub)で検証すると同様に内容を確認できます。

$ openssl rsautl -verify -pubin -inkey sign.pub -in text.signed
hello

参考資料