🪪

NFCプログラミングの前提知識と勘所

に公開

はじめに

こんにちは!
株式会社ミラボでモバイルアプリ開発をしている西島です。
自分が担当するアプリで、NFCを使用してカードから情報を読み取る仕組みを実装しています。

NFCは身近な存在であり、その動作自体はイメージしやすいと思いますが、実際に開発をするのはそれほど容易なことではありませんでした。
自分自身の開発中の失敗や気づきを踏まえて、事前に理解しておくべきと感じた事項や開発の勘所などを、本記事の内容として残しておきたいと思います!

1. NFCセッション管理

NFC通信はセッション単位で行われ、以下の流れを含みます。

  1. セッション開始
    • スマートフォンやリーダーがNFCタグを検出して通信を開始
    • カードからATR(Answer to Reset)やATS(Answer to Select)が返され、通信準備が整ったことを確認
  2. コマンド送信
    • APDU(Application Protocol Data Unit)コマンドの送信によるカードとのデータ交換
      • 一度セッションが開始されると、そのセッション内で発行されるAPDUコマンドは、カードの状態が変更されない限り、前のコマンドの影響を受けた状態を引き継ぐ
  3. セッション終了
    • 通信終了後、NFCリーダーがセッションを終了し、選択状態や操作履歴がリセットする

2. APDU通信の基礎

NFCセッション開始後、APDU通信によりカードとのデータ交換を行います。

ISO/IEC 7816とAPDU通信

APDU(Application Protocol Data Unit)は、NFC通信で使用されるデータフォーマットで、ISO/IEC 7816に基づいています。

  • APDUの2種類
    • コマンドAPDU: リーダーからカードに送信される命令
    • レスポンスAPDU: カードからリーダーに返される応答

コマンドAPDUの構造

フィールド サイズ(バイト) 説明
CLA 1 クラス(カテゴリ)
INS 1 インストラクション(コマンド種別)
P1 1 パラメータ1(補足情報)
P2 1 パラメータ2(補足情報)
Lc 0または1-3 送信データの長さ(可変)
Data 可変長 コマンドデータ
Le 0または1-3 期待するレスポンスデータ長

レスポンスAPDUの構造

フィールド サイズ(バイト) 説明
Data 可変長 応答データ
SW1, SW2 2 ステータスワード(成功/エラー)

ステータスワードについて

ISO/IEC 7816で定義されているエラーコードの例を以下に示します。
これらは、スマートカードに共通して発生する可能性のあるエラーです。

ステータスワード 意味
90 00 成功
6A 82 ファイルが見つからない
69 85 条件が満たされていない
67 00 長さが正しくない
6A 84 メモリ不足
6D 00 サポートされていないコマンド
6E 00 サポートされていないクラス

一部のスマートカードでは、ISO/IEC 7816で定義されたコードとは別に、独自のレスポンスコードを使用することがあります。これらのコードはカードの発行元や仕様によって異なります

3.カード仕様の確認と設計・実装に落とし込む勘所

前提として把握しておくこと

カードのファイル構造

カードのデータ管理は階層的なファイルシステムで行われており、ISO/IEC 7816準拠のカードでは以下のような構造になっています。

ファイル種類 説明
MF (Master File) ルートディレクトリ。カードの起点になるファイル。
DF (Dedicated File) サブディレクトリやアプリケーションを示す中間ファイル。
EF (Elementary File) 実際のデータが格納されるファイル。

対象のカードの構造に関して、下記を把握する必要があります

  1. MFやDFの構造: カードのルートファイル(MF)から、どのようなサブディレクトリやファイル(DF/EF)が存在するのか。
  2. ファイル識別子: 各ファイルに割り当てられた識別子(FIDやAID)
  3. ファイルのアクセス方法: 読み取り(READ BINARY)、書き込み(UPDATE BINARY)などの操作

サポートされるコマンド

カードがサポートするAPDUコマンドが一覧として記載されているはずです。
一覧がない場合は、仕様整理の一環として一覧の作成をしても良いかと思います。

コマンドの確認ポイント
  • コマンド名(例: SELECT FILE, READ BINARY, VERIFY)
  • コマンドフォーマット(CLA, INS, P1, P2, Lc, Data, Le)
  • コマンドの依存関係(認証後に実行可能なコマンドなど)

実施したい処理から逆算してコマンドシーケンスに落とし込む

  1. 実施したい処理を明確化する
  2. 仕様書で関連する情報を確認する
    • サポートされるコマンド
      • 実施したい処理に対応するINSコードを確認
    • コマンドのフォーマット
      • 必要なパラメータ(CLA, INS, P1, P2, Lc, Data, Le)を確認
    • コマンドの依存関係
      • 特定のコマンドを実行するために必要な事前条件を確認
    • 認証要件
      • 認証が必要か、必要な場合はどのように実施するか
  3. 必要なコマンドのリストアップ
    • 仕様書から関連するコマンドを洗い出し、順序を設計
  4. コマンドシーケンスの設計
    • リストアップしたコマンドを基に、仕様書の条件や依存関係を考慮してシーケンスを設計

4.実装・デバッグの勘所

セッション管理

セッション中の状態保持

多くの場合、一度選択されたAIDやファイルの状態はセッション中保持されています。
これを踏まえて効率的なコマンドシーケンスを実現することで、冗長なコマンドを省略し、通信回数を最小化することができます。

セッション終了

開始したセッションは成功/失敗の結果を問わず、必ず終了するようにしましょう。

ログ出力

出力形式

コマンドAPDUやレスポンスAPDUは基本的にバイト列でやり取りされますが、各バイトがスペースで区切られた2桁の16進数でログ出力することで、仕様書やプロトコル仕様に準じたログ形式になります。
そのため、デバッグや解析が容易になり、仕様書との照合やカード発行元への問い合わせがスムーズに行えます。

APDUの対応関係が分かるようにする

出力形式と同時に、コマンドAPDUとレスポンスAPDUの対応関係が分かるような形でログ出力することも重要です。

5. その他: 必要になるかもしれない知識

APDUコマンドを扱う中で、特定の操作やセキュリティ関連の機能を実装する場合、DigestInfoや ASN.1のようなフォーマットや概念が関わることがあります。以下に、追加の知識や関連するトピックを列挙しておきます。

  1. データ構造
    • DigestInfo(署名やハッシュ)
    • ASN.1(証明書やデータフォーマット)
  2. 暗号化と認証
    • 公開鍵暗号(RSA, ECC)
    • メッセージ認証コード(MAC)
    • ハッシュアルゴリズム(SHA-256など)
  3. 標準プロトコル
    • PKCS仕様(RSA, 証明書)
    • ISO/IEC 7816 セキュアメッセージング
  4. 証明書と鍵管理
    • X.509証明書の解析と利用

おわりに

自分自身の開発中の失敗や気づきを踏まえて、前提知識と勘所を改めて本記事で整理してみました。
本記事の内容はポイントを絞った概要的な前提知識であるため、実際の開発で発生する問題やハマりどころがダイレクトに解決することはほとんどないと思いますが、これからNFC機能を有するアプリ開発に携わる方にとっての入り口となれば幸いです。

Milabo Engineers Blog

Discussion