マイナンバーカードを使って電子署名できるアプリを作ってみたくて、マイナンバーの仕様に関して調べてまとめてみました。また、実際にOpenSCというツールを使って電子署名・検証し、マイナンバーカードの内部構造の理解を深めました。
前提
- macOS: 12.4
- OpenSSL: LibreSSL 2.8.3
- OpenSC: 0.22.0-rc1-74
マイナンバーカードのインタフェース
まずは、マイナンバーカードの外部からアクセスするためのインタフェースとその規格を確認し、接続に使った機器に関して説明します。
規格
マイナンバーカードは接触・非接触両方のインタフェースを持ち、それぞれ以下の規格に準拠しています。
非接触インターフェースであるNFCの代表的の規格は以下の3つであり、マイナンバーカードは2番目のType Bを採用しています。
分類 | 規格 | 特徴 | 使用例 |
---|---|---|---|
Type-A | ISO/IEC 14443 Type A (MIFARE) | 比較的安価で低機能 | taspo |
Type-B | ISO/IEC 14443 Type B | 高セキュリティ、高処理速度 | パスポート、住民基本台帳カード、免許証 |
Type-F | NFC-F ‐ JIS X 6319-4 (FeliCa) | 高セキュリティ、高処理速度 | Suica、Edy、iD |
使用機器・環境
今回の検証では、接触インターフェース(ISO 7816 準拠) ICカードに対応した以下のカードリーダーを使用し、電子署名・検証してみました。
- SCR3310v2.0 USB Contact Smart Card Reader
- SCR3310-NTTComOEM製造元(Identiv)による互換品
PCからマイナンバーカードの裏面にあるICチップにアクセスできれば接触/非接触どちらのインタフェースでもよかったのですが、2,000円台という安価で壊れても買い直しやすそうだったのでこちらのICカードリーダーで試してみました。
Amazon.co.jp: SCM ICカードリーダー/ライター B-CAS・住基カード対応 SCR3310/v2.0 : パソコン・周辺機器
マイナンバーカードの内部構造
アプリ
総務省のマイナンナーカードの説明によるとマイナンバーカードのICチップには、券面AP・公的個人認証AP(JPKI-AP)・券面入力補助AP・住基APという4つのアプリケーションがあり、以下の概要図のようになっています。
本記事の検証では、OpenSCというツールを使って電子署名をしたいので公的個人認証AP(JPKI-AP)の部分を使っていきます。
データ構造
また、ICチップ内部のデータ構造は公開されていませんが、ICチップの内部にアクセスして確認すると以下のようなデータ構造になっていることがわかります。
本記事では署名用のデータを使います。
電子署名・検証
いよいよOpenSCとマイナンバーカードにある署名証明書を使って電子署名を行なっていきます。
OpenSCとは
OpenSCは、クロスプラットフォームで動作するスマートカード用のライブラリ・ユーティリティ郡です。主に暗号操作をサポートするカードに対して、認証、メール暗号化、デジタル署名などをするアプリケーションを実装しやすくしてくれるものです。
OpenSCのインストール
以下から環境にあったインストーラーをダウンロードして、OpenSCをインストールします。
GitHub - OpenSC/OpenSC: Open source smart card tools and middleware. PKCS#11/MiniDriver/Tokend
インストール後、pkcs15-crypt
, pkcs15-tool
の両コマンドが使えるようになっていることを確認します。
$ pkcs15-crypt --version OpenSC-0.22.0-rc1-74-gc902e199, rev: c902e199, commit-time: 2021-08-10 11:09:03 +0200 $ pkcs15-tool --version OpenSC-0.22.0-rc1-74-gc902e199, rev: c902e199, commit-time: 2021-08-10 11:09:03 +0200
これらのツールの用途はそれぞれ以下の通りです。
- pksc15-creypt
- pkcs15-tool
- PIN・証明書・公開鍵など、カード内部のデータにアクセスするためのツールです。
電子署名
以下のコマンドで署名対象のファイル( plain.txt
)を作成します。(RSA署名できるのは254バイトまでなので、実際には署名対象自体ではなくダイジェストに対して署名します)
$ echo "hello" > plain.txt
次に以下のコマンドで、PKCS#15オブジェクトを全て表示し、署名用の秘密鍵のIDを確認します。
$ pkcs15-tool --dump 〜〜〜 他のPKCS#15オブジェクト 〜〜〜 Private RSA Key [Digital Signature Key] Object Flags : [0x01], private Usage : [0x204], sign, nonRepudiation Access Flags : [0x1D], sensitive, alwaysSensitive, neverExtract, local Algo_refs : 0 ModLength : 2048 Key ref : 2 (0x02) Native : yes Auth ID : 02 ID : 02 MD:guid : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 〜〜〜 他のPKCS#15オブジェクト 〜〜〜
署名用の秘密鍵のIDが 2
だということがわかりました。また、コマンドの結果から、マイナンバーカード内には以下の10個のオブジェクトがあることが分かります。
- PIN [User Authentication PIN] - 認証用PIN
- PIN [Digital Signature PIN] - 署名用PIN
- Private RSA Key [User Authentication Key] - 認証用秘密鍵
- Private RSA Key [Digital Signature Key] - 署名用秘密鍵
- Public RSA Key [User Authentication Public Key] - 認証用公開鍵
- Public RSA Key [Digital Signature Public Key] - 署名用公開鍵
- X.509 Certificate [User Authentication Certificate] - 認証証明書
- X.509 Certificate [Digital Signature Certificate] - 署名証明書
- X.509 Certificate [User Authentication Certificate CA] - 認証用CA証明書
- X.509 Certificate [Digital Signature Certificate CA] - 署名用CA証明書
pkcs15-crypt
の -k
オプションに署名用の秘密鍵のID 2
を指定して、作成したテキストファイルを署名します。また、署名用パスワード(英数字6-16文字)の入力が求められるので入力します。(※英字のアルファベットは大文字を入力する必要があります。)
$ pkcs15-crypt -s -k 2 --pkcs1 -R -i plain.txt -o text.signed
pkcs15-crypt
はデフォルトだと入力データが正しい長さでパディングされたものと見なして扱うので --pkcs1
オプションを指定して入力データをパディングしてあげています。(参考)
パスワードを間違えてしまった場合、以下のコマンドでPINがブロックされるまでの残り回数を確認できます。PINがブロックされると役所に行ってリセットを依頼する必要があるのでご注意を。
$ pkcs15-tool --list-pins
署名済みのファイルtext.signed
ができました。
署名検証
次に署名証明書の公開鍵を使って、署名済みのファイルの署名検証を行います。
以下のコマンドで、署名用のPINと証明書のIDを確認します。それぞれ 2
であることが分かります。
$ pkcs15-tool --dump PIN [Digital Signature PIN] Object Flags : [0x12], modifiable ID : 02 Flags : [0x12], local, initialized Length : min_len:6, max_len:16, stored_len:0 Pad char : 0x00 Reference : 2 (0x02) Type : ascii-numeric Tries left : 5 X.509 Certificate [Digital Signature Certificate] Object Flags : [0x01], private Authority : no Path : 0001 ID : 02 Encoded serial : 00 00 XXXXXXXXX
pkcs15-tool
の --read-certificate
オプションに署名証明書のID 2
、--auth-id
オプションにPINの auth-id
に 02
指定して、署名証明書を取得します。再度、署名用パスワードの入力が求められるので入力します。
$ pkcs15-tool --read-certificate 2 --verify-pin --auth-id 02 Using reader with a card: SCR3310 Smart Card Reader Please enter PIN [Digital Signature PIN]: -----BEGIN CERTIFICATE----- xxxxx -----END CERTIFICATE-----
出力された-----BEGIN CERTIFICATE-----
から-----END CERTIFICATE-----
の箇所をファイル名 sign.crt
として保存します。
以下のコマンドで署名証明書(sign.crt
)から公開鍵の部分を取り出して、ファイル sign.pub
に保存します。
$ openssl x509 -in sign.crt -noout -pubkey > sign.pub
先ほど作成した署名済みファイル(text.signed
)を公開鍵(sign.pub
)で検証すると内容を確認できます。
$ openssl rsautl -verify -pubin -inkey sign.pub -in text.signed hello