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 以下のコマンドフローで実行します
NDEF AID のアプレットを選択してください
使用するNDEFデータファイルを選択してください
NDEFデータを書き込む https://authentrend.com
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>
