2013年5月31日金曜日

PC/SCに潜む謎

WindowsでNFCなどのICカードを利用するのに便利なPC/SCというインターフェース仕様があります。

通常はリーダライタはそれぞれドライバがあってSDKが提供されたりしてそのリーダ用のプログラムを作成するわけなんですが、PC/SCに対応したリーダライタでPC/SCを利用してプログラミングしてしまえば、他のPC/SC対応リーダに変更してもそのまま使えちゃうわけですね。(まぁ、そんなにうまくはいかないんですが)

こういう共通インターフェース仕様っていうのはぶっ飛び系(なんで?こんだけのことするのに何でこんなにコードがいるわけ?など)が多いわけですが、このPC/SCも結構不思議ちゃんな部分があります。

実際に見てみましょう。ACSさんのACR122リーダを使用します。

PC/SCの実体というかAPIの呼び出し先はwinscard.dllというシステムファイルです。Windowsに含まれてますので、特に何かインストールしなくても普通に使えます。

で、だいたい次のようなAPIの呼び出しをして使います。

 SCardEstablishContext - まあ、これから使うよー的な。
     ↓
 SCardListReaders - これでWindowsが認識しているPC/SCに対応したリーダの一覧を取得します。
     ↓
 SCardGetStatusChange - リーダの状態の変化を察知します。カードが置かれたとかがわかります。
     ↓
 SCardConnect - カードが置かれてるようなら、これでカードと接続(おおげさな)します。
     ↓
 SCardTransmit - カードに対してコマンドを送信します。
     ↓
 SCardDisconnect - カードとの接続を切断(またおおげさな)します。
     ↓
 SCardReleaseContext - 終わったよー的な。

至って普通に見えますね。重要なのは SCardTransmit で、これでAPDU(Application Protocol Data Unit)という形式のバイナリデータを送ることでカードを操作します。たとえば「お前だれー」というときは

 FF CA 00 00 00 (16進数)

といったバイナリ列を送ればカードのIDを返してきます。APDUは定義されたものもあればメーカ独自のものもあります。
先ほどのIDの取得やタグの読み書きなどは定義されていますが、ACR122リーダではブザーを鳴らしたりLEDを点灯したりみたいなこともAPDUを送ることで可能です。

 FF 00 40 50 04 05 05 03 01

なんて送ると、赤のLEDが3回点滅してそれに合わせてピーピーピーと鳴ります。便利ですねー。これを使えばカードをかざしてお前のカード認証されてねーよみたいなときに警告としてピーピー言うこともできそうです。

ところが不都合が1つあります。先ほどのAPDUを送信するAPIなんですが、SCardTransmitなんです。そうです。S「Card」Transmitです。カードなんです。カードに送るんです。
まあ、カードに送るって言っても一旦はリーダに送るんだからいいんじゃね?とも思いますが、実際SCardTransmitの引数はこうなっています。

 SCardTransmit(カードハンドル, 送信パラメータ, 送信データ, 送信データの長さ, 受信パラメータ, 受信用バッファ, 受信用バッファの長さ)

いきなりカードハンドルというのがあります。これは SCardConnect の時に取得できるカードの識別子みたいなもんです。これがないと送信してくれません。0とかにしてもダメです。もちろん送信するときにはカードとリーダが通信できている状態にある必要があります。

要するに、カードが置いてないときにAPDUコマンドは送信できないのです。例えそのAPDUがリーダのブザーを鳴らすとかカードに全く関係のないコマンドであったとしてもです。えー!なんでー?謎。
(注:ACR122リーダではこれを回避?するため DirectTransmit というものがPC/SCとは別に用意されているようです)

※2014/07/04 追記 カードが無くてもコマンド送信は可能でした。お詫びいたします。詳細は新しいエントリー「PC/SCに潜む謎 その2」を参照ください。

0 件のコメント:

コメントを投稿