ATKey。カード NFC 開発者向け参考資料

ATKey。カード NFC これは、FIDO2、指紋認証、個人識別検証(PIV)、およびNFCデータ交換フォーマット(NDEF)をアプレットを介してサポートするスマートカードです。開発者は、アプリケーションプロトコルデータユニット(APDU)コマンドを使用してアプレットとやり取りし、カスタムアプリケーションを作成したり、統合したりできます。 ATKey。カード NFC 既存のスタックで。

チャプター

ATKey。カード NFC PIV APDUコマンドリファレンス

バイオメタデータを取得する

自律的AI ATKey。カード NFC ユーザーは指紋認証でPIVログインを保護できます。 ATKey。カード NFC FIDO2アプレットを介して生体認証を設定する必要があります。生体認証登録が完了したかどうかを確認するには、コマンドを実行します。 バイオメタデータを取得する に使える。

コマンドAPDU情報

CLA INS P1 P2 Lc Rescale データ Le
00 F7 00 96 (不在) (不在) (不在)

応答APDU情報

  • 全長:10 + 2

  • データ長: 10

Rescale データ SW1 SW2
生体メタデータをTLVのセットとして 90 00

データは、タイプ・長さ・値(TLV)のセットで構成されます。有効なタグ(TLVのT)は、以下の表に示されています。長さ(TLVのL)は1です。値(TLVのV)は、以下の表に示されているタグによって異なります。

タグ 名前 意味 Rescale データ
07 構成されています 生体認証設定の状態(例:指紋が登録されているかどうか) 1Bデータ
- 01 (設定済み)
- 00 (未設定)
06 残りの再試行回数 生体認証マッチングの残り試行回数を示します 2Bデータ
- 最初のバイトは最大バイオ再試行回数を示しており、現在は08です。
- 2バイト目は残りの再試行回数で、値の範囲は00~08です。00はPIVでの生体認証の使用がロックされていることを意味します。
08 生体認証によるPIN保護は有効になっていますか? PIN保護のための生体認証が有効になっているかどうかを示します 1Bデータ
- 01 (有効)
- 00 (無効)

PIN保護のための生体認証を有効/無効にする

PIVログインの生体認証保護を有効または無効にするには、このコマンドを使用できます。

CLA INS P1 P2 Lc Rescale データ Le
00 20 00 96 09 8B-PIN + 1B-Val (不在)

1B-Valには以下のような異なる意図があります。

  • 01 - PIN保護のための生体認証を有効にする

  • 00 - PIN保護のための生体認証を無効にする。

注:以下の2つの事象が発生した場合、生体認証によるPIN保護機能は自動的に無効になります。

  • PIVリセット

  • バイオが削除されます。つまり、FIDO2アプレットが削除するか、FIDO2リセットを処理します。

応答APDU情報

結果 Rescale データ SW1 SW2
成功 (データなし) 90 00
失敗、登録された生体認証情報がありません (データなし) 69 86
エラー、PINが無効です (データなし) 63 CX

入力されたPINが間違っている場合、表示されるエラーは63 CXです。 X は残りの試行回数です。試行回数がなくなると、エラーコード0x6983が返されます。

.

生体認証を確認する

このコマンドを実行するには、ユーザーがカード上の指紋を認証する必要があります。

CLA INS P1 P2 Lc Rescale データ Le
00 20 00 96 (不在) (不在) (不在)

応答APDU情報

結果 Rescale データ SW1 SW2
成功
全長16 + 2
- データ長: 16
16B 一時PIN 90 00
生体認証の一致に失敗しました (データなし) 63 CX
生体認証タイムアウト待ち
(約1400ミリ秒)
(データなし) 69 85
生体認証情報は登録されていません (データなし) 69 86

生体認証の一致が失敗した場合、エラーは63 CXです。 X は残りの試行回数です。試行回数がなくなると、生体認証はブロックされ、エラーコード0x6983が返されます。

仮PINを確認する

このコマンドは、一時的なPINが設定された「生体認証の検証」コマンドからの応答が正常に完了した後に使用する必要があります。

CLA INS P1 P2 Lc Rescale データ Le
00 20 00 96 10 一時的なPINコード (不在)

応答APDU情報

結果 Rescale データ SW1 SW2
成功 (データなし) 90 00
無効な一時PIN (データなし) 63 CX

入力された一時PINが間違っている場合、エラーは63 CXです。 X は残りの再試行回数です。再試行回数はPIV-PINと共有されます。再試行回数がなくなると、エラーコード0x6983が返されます。

生体認証試行回数のリセット

CLA INS P1 P2 Lc Rescale データ Le
00 2C 00 96 10 8B 現在のPUK +
8B 任意のデータ
(不在)

データ用の2番目の音声(8B任意のデータ)はこのコマンドでは使用されませんが、リセットPIN再試行との一貫したコマンド形式を維持します。

応答APDU情報

結果 Rescale データ SW1 SW2
成功 (データなし) 90 00
無効なPUK (データなし) 63 CX

入力された PUK が間違っている場合、エラーは 63 CX です。 X は残りの再試行回数です。再試行回数がなくなると、エラーコード0x6983が返されます。

指紋認証ポリシーの策定

指紋認証ポリシーはどのスロットにも適用でき、以下のように設定できます。

  • 指紋認証は不要です。このスロットを使用する際に指紋認証は必要ありません。

  • 常に:あらゆる使用において指紋認証が必要です

  • 指紋認証は電源サイクルセッションごとに一度だけ必要です。

管理キーを設定します(0xFF)

CLA INS P1 P2 Lc Rescale データ Le
00 FF FF タッチポリシー:
- FF: 決して
- FE: 常に
- FD: 一度
1B 新しい管理キーデータ (不在)

非対称鍵ペアを生成する(0x47)

CLA INS P1 P2 Lc Rescale データ Le
00 47 00 スロット番号 データ長 [AC 80 01 …]
[AA 01 …]
[AB 01
- 01: 決して
- 02: いつも
- 03: 一度]
(不在)

非対称鍵ペア(0xFE)をインポートします

CLA INS P1 P2 Lc Rescale データ Le
00 FE ALG スロット番号 データ長 主要要素を含むTLVのセット
[AA 01 …]
[AB 01
- 01: 決して
- 02: いつも
- 03: 一度]
(不在)

応答APDU情報

以下は、 コマンドAPDU情報(0xF7)、P2 = スロット番号。

  • PINとタッチポリシーの値の意味は異なることに注意してください。

タグ 名前 意味 Rescale データ スロット
02 ポリシー PINとタッチポリシー ピン:
- 00: デフォルト = なし
- 01: 決して
- 02: 一度
- 03: いつも
タッチ:
- 00: デフォルト = なし
- 01: 決して
- 02: いつも
- 03: 一度
9a、9b、9c、9d、9e、f9、82~

ATKey。カード NFC NDEF APDUコマンドリファレンス

ATKey。カード NFC NDEF APDUコマンドリファレンス

NDEF(NFCデータ交換フォーマット)機能は ATKey.Card は JavaCardアプレット NFC を介した NDEF メッセージのエミュレーションに準拠 NFCフォーラムタイプ4タグ動作仕様 ただし、NDEF仕様で規定されている最小限のAPDUコマンドのみが使用されます。また、NDEFアプレットには独自のアプリケーションIDがあり、個別に処理されます。

NDEF AID: 0xD2、0x76、0x00、0x00、0x85、0x01、0x01

利用できます ATKey.Card NFC SKU

  • ファイルを選ぶ (NAIST) と データの読み取り: 630B02、630B03、630B04、630B12、630B13

  • ファイルを選ぶ, データの読み込みとデータの書き込み: 630B04、630B13

サポートされているAPDUコマンド

このNDEFアプレットには2つの定義済みファイルがありますが、このドキュメントではNDEFデータ部分のみに焦点を当てています。

  • 0xE103 - NDEF機能

  • 0xE104 - NDEFデータ

コマンド CLA INS P1 P2 Lc Rescale データ Le
NDEFデータファイルを選択してください 0x00 0xA4 0x00 0x0C 0x02 0xE1 0x04 (不在)
データの読み取り 0x00 0×B0 0x00 0x00 (不在) (不在) 0x00
データを書き込む 0x00 0xD6 0x00 0x00 6B NDEFレコードヘッダー
+
nB NDEF レコードペイロード
NDEF記録ペイロード (不在)

NDEFレコードヘッダーは以下のように定義されます。

フィールド サイズ 詳細説明
タグ 1 常に0
長さ 1 NDEF記録の長さ
NDEFヘッダー 1 常に0xD1: メッセージ開始+終了、ショートレコード、タイプ名フォーマット=NFCフォーラムでよく知られている
レコードタイプの長さ 1 常に1
ペイロードの長さ 1
タイプ 1 NFCフォーラムのグローバルタイプ「U」=0x55
ペイロード (変動あり) 実際のNDEFメッセージ。長さは「ペイロード長」バイト。

注:NDEFレコードペイロードの最初のバイトは、次のデータプロトコルを示します。このドキュメントでは、 0x04 意味 "https://例えば値など。

例:

  • 以下に使用方法のデモ例を示します OpenSC 以下のコマンドフローで実行します

    1. NDEF AID のアプレットを選択してください

    2. 使用するNDEFデータファイルを選択してください

    3. NDEFデータを書き込む https://authentrend.com

    4. NDEFデータを読み戻す

opensc-tool.exe -c default -r 0 -s 00:A4:04:00:07:D2:76:00:00:85:01:01 -s 00:A4:00:0C:02:E1:04 -s  00:D6:00:00:16:00:14:D1:01:10:55:04:61:75:74:68:65:6E:74:72:65:6E:64:2E:63:6F:6D -s 00:B0:00:00:00
Sending: 00 A4 04 00 07 D2 76 00 00 85 01 01
Received (SW1=0x90, SW2=0x00)
Sending: 00 A4 00 0C 02 E1 04
Received (SW1=0x90, SW2=0x00)
Sending: 00 D6 00 00 16 00 14 D1 01 10 55 04 61 75 74 68 65 6E 74 72 65 6E 64 2E 63 6F 6D
Received (SW1=0x90, SW2=0x00)
Sending: 00 B0 00 00 00
Received (SW1=0x90, SW2=0x00):
00 14 D1 01 10 55 04 61 75 74 68 65 6E 74 72 65 .....U.authentre
6E 64 2E 63 6F 6D 00 00 00 00 00 00 00 00 00 00 nd.com..........
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

AT-USB-HIDインターフェースにコマンドを送信する方法?Webサンプルコード

以下のサンプルコードは、 https://seleniumbase.io/w3schools/.

<!DOCTYPE html>

<script>
const CMD_INIT = 0x86;
const CMD_MSG = 0x83;

var usb_device;
var channel_id = [0xFF, 0xFF, 0xFF, 0xFF];

async function request_hid() {
    const filters = [
    {
      vendorId: 0x31bb,
      productId: 0x0635,
      usagePage: 0x4154,
    },
  ];

  const devices = await navigator.hid.requestDevice({ filters });
  usb_device = devices[0];
  await usb_device.open();
  usb_device.addEventListener("inputreport", (event) => {
    const { data, device, reportId } = event;
    const cid = data.getUint32(0);
    const cmd = data.getUint8(4);
                if (cmd == CMD_INIT) {
        const cid = data.buffer.slice(14, 4);
                channel_id = [data.getUint8(15), data.getUint8(16), data.getUint8(17), data.getUint8(18)];
        console.log(`CID: ${channel_id}`);
    }
  });

  //const cmd_get_cid = [0xFF, 0xFF, 0xFF, 0xFF, CMD_INIT, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0];
  let nonce = [0, 0, 0, 0, 0, 0, 0, 0];
  let packet = new ArrayBuffer(64);
  let cmd_get_cid = new Uint8Array(packet);
  cmd_get_cid.set(new Uint8Array(channel_id), 0);
  cmd_get_cid.set(new Uint8Array([CMD_INIT, 0, nonce.length]), 4);
  cmd_get_cid.set(new Uint8Array(nonce), 4 + 3);
  await usb_device.sendReport(0x00, cmd_get_cid);
}

async function get_keycode() {
  usb_device.addEventListener("inputreport", (event) => {
  const { data, device, reportId } = event;
  const cid = data.getUint32(0);
  const cmd = data.getUint8(4);
  if (cmd == CMD_MSG) {
          
          
  //const keycode = [data.getUint8(15), data.getUint8(16), data.getUint8(17), data.getUint8(18)];
  const keycode = data.getUint32(15);
  console.log(`Keycode: ${keycode}`);
        alert(`Keycode: ${keycode.toString(16)}`);
   }
   });


  //const cmd_get_keycode = [??, ??, ??, ??, CMD_MSG, 0, 19, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x55, 0xAA, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x7C, 0x00, 0x00];
    const payload = [0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x55, 0xAA, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x7C, 0x00, 0x00];
    let packet = new ArrayBuffer(64);
    let cmd_get_keycode = new Uint8Array(packet);
    cmd_get_keycode.set(new Uint8Array(channel_id), 0);
                cmd_get_keycode.set(new Uint8Array([CMD_MSG, 0, payload.length]), 4);
    cmd_get_keycode.set(new Uint8Array(payload), 4 + 3);
                await usb_device.sendReport(0x00, cmd_get_keycode);

}

</script>

<html>
<body>

<p>Step 1: </p>
<button onclick="request_hid()">List Devices</button>
<br>
<br>
<p>Step 2: </p>
<button onclick="get_keycode()">Get Keycode</button>

</body>
</html>