ATKey.Card NFC References for Developers

ATKey.Card NFC is a Smart Card that supports FIDO2, fingerprint authentication, Personal Identity Verification (PIV), and NFC Data Exchange Format (NDEF) through applets. Developers can use application protocol data unit (APDU) commands to interact with the applets and create custom applications or integrate ATKey.Card NFC with their existing stack.

Chapters

ATKey.Card NFC PIV APDU Commands References

Get Bio Metadata

With ATKey.Card NFC users can secure their PIV logins with fingerprint authentication. In order to do it their ATKey.Card NFC needs to have biometrics configured through the FIDO2 applet. to verify if biometric enrollment has been completed the command Get Bio Metadata can be used.

Command APDU Info

CLA INS P1 P2 Lc Data Le
00 F7 00 96 (absent) (absent) (absent)

Response APDU Info

  • Total length: 10 + 2

  • Data length: 10

Data SW1 SW2
bio metadata as set of TLV 90 00

The data consists of a set of Type-Length-Value (TLVs). The possible valid tags (T of TLV) are listed in the table below. The length (L of TLV) is one. The values (V of TLV) are dependent on the tags, described in the table below.

Tag Name Meaning Data
07 IsConfigured state of biometric verification configuration (i.e. fingerprints are enrolled) 1B data
- 01 (configured)
- 00 (not configured)
06 RetriesRemaining indicates how many biometric match attempts are left 2B data
- 1st byte indicates the max bio retry count it’s 08 now.
- 2nd byte is remaining retries count, the value range is 00-08 and 00 means biometric usage in PIV is locked.
08 Bio-for-pin-protection is enabled or not indicates if Bio-for-pin-protection is enabled or not 1B data
- 01 (enabled)
- 00 (disabled)

Enable/Disable Bio-for-pin-protection

To activate, or disactivate, biometric protection for PIV logins this command can be used.

CLA INS P1 P2 Lc Data Le
00 20 00 96 09 8B-PIN + 1B-Val (absent)

The 1B-Val has different intentions as below.

  • 01 - Enable Bio-for-pin-protection

  • 00 - Disable Bio-for-pin-protection.

NB: the Bio-for-pin-protection feature will be disabled automatically in the case of this two events:

  • PIV-Reset

  • Bio is removed, i.e. FIDO2 applet removes it or processes FIDO2-Reset.

Response APDU Info

Outcome Data SW1 SW2
Success (no data) 90 00
Failure, no enrolled biometric (no data) 69 86
Failure, invalid PIN (no data) 63 CX

If the PIN entered is incorrect, then the error displayed is 63 CX where X is the number of attempts remaining. When no attempts remain, the error returned is 0x6983.

.

Verify Biometric

This command requires the user to verify their fingerprint on the card to proceed.

CLA INS P1 P2 Lc Data Le
00 20 00 96 (absent) (absent) (absent)

Response APDU Info

Outcome Data SW1 SW2
Success
- Total length 16 + 2
- Data length: 16
16B temporary PIN 90 00
Failed biometric match (no data) 63 CX
Waiting biometric timeout
(around 1400ms)
(no data) 69 85
No biometric enrolled (no data) 69 86

If the biometric match fails, the error is 63 CX where X is the number of attempts remaining. When no attempts remain, biometric verification is blocked, and the error returned is 0x6983.

Verify Temporary PIN

This command should be used after a successful response from the Verify Bio command, which would have established a temporary PIN.

CLA INS P1 P2 Lc Data Le
00 20 00 96 10 temporary PIN (absent)

Response APDU Info

Outcome Data SW1 SW2
Success (no data) 90 00
Invalid temporary PIN (no data) 63 CX

If the temporary PIN entered is incorrect, then the error is 63 CX where X is the number of retries remaining, the retries value is shared with PIV-PIN. When no retries remain, the error returned is 0x6983.

Reset Biometrics Attempts

CLA INS P1 P2 Lc Data Le
00 2C 00 96 10 8B Current PUK +
8B any data
(absent)

The second voice for Data (8B any data) does not have any use in this command but maintain consistent command format with Reset PIN Retries.

Response APDU Info

Outcome Data SW1 SW2
Success (no data) 90 00
Invalid PUK (no data) 63 CX

If the PUK entered is incorrect, then the error is 63 CX where X is the number of retries remaining. When no retries remain, the error returned is 0x6983.

Establishing Fingerprint Verification Policy

The fingerprint verification policy can be chosen for any slot and can be set as:

  • Never: fingerprint verification is never needed when using this slot

  • Always: fingerprint verification is needed for every use

  • Once: fingerprint verification is needed only once per power cycle session

Set management key (0xFF)

CLA INS P1 P2 Lc Data Le
00 FF FF touch policy:
- FF: Never
- FE: Always
- FD: Once
1B new management key data (absent)

Generate asymmetric key pair (0x47)

CLA INS P1 P2 Lc Data Le
00 47 00 slot number data len [AC <remaining bytes> 80 01 <alg> …]
[AA 01 <pin policy> … ]
[AB 01 <touch policy>
- 01: Never
- 02: Always
- 03: Once]
(absent)

Import asymmetric key pair (0xFE)

CLA INS P1 P2 Lc Data Le
00 FE alg slot number data len set of TLV containing key elements
[AA 01 <pin policy> … ]
[AB 01 <touch policy>
- 01: Never
- 02: Always
- 03: Once ]
(absent)

Response APDU Info

Below shows the response for Command APDU Info (0xF7) with P2 = slot number.

  • Note that the values meaning of PIN and Touch policies are different.

Tag Name Meaning Data Slots
02 Policy PIN and Touch policies PIN:
- 00: Default = Never
- 01: Never
- 02: Once
- 03: Always
Touch:
- 00: Default = Never
- 01: Never
- 02: Always
- 03: Once
9a, 9b, 9c, 9d, 9e, f9, 82~

ATKey.Card NFC NDEF APDU Commands References

ATKey.Card NFC NDEF APDU Commands References

The NDEF (NFC Data Exchange Format) feature on the ATKey.Card uses a Javacard applet to emulate NDEF Message over NFC complying NFC Forum Type 4 Tag Operation Specification but only the exact minimum of APDU commands that the NDEF specification prescribes. And the NDEF applet has its own application ID and is processed separately.

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

Available ATKey.Card NFC SKUs

  • Select File and Read Data: 630B02, 630B03, 630B04, 630B12, 630B13

  • Select File, Read Data, and Write Data: 630B04, 630B13

Supported APDU Commands

There are 2 defined files in this NDEF applet, but this document only focuses on NDEF data part.

  • 0xE103 - NDEF capabilities

  • 0xE104 - NDEF data

Commands CLA INS P1 P2 Lc Data Le
Select NDEF data File 0x00 0xA4 0x00 0x0C 0x02 0xE1 0x04 (absent)
Read Data 0x00 0xB0 0x00 0x00 (absent) (absent) 0x00
Write Data 0x00 0xD6 0x00 0x00 6B NDEF Record Header
+
nB NDEF Record Payload
NDEF Record Payload (absent)

The NDEF record header is defined as below:

Field Size Description
Tag 1 Always 0
Length 1 Length of the NDEF record
NDEF Header 1 Always 0xD1: Message Begin+End, Short Record, Type Name Format = NFC Forum well known
Length of record type 1 Always 1
Payload Length 1
Type 1 NFC Forum global type "U” = 0x55
Payload (varies) The actual NDEF message. Of length "payload length" bytes.

NB. The first byte of NDEF record payload is to indicate the following data protocol. In this document, it uses 0x04 meaning “https://” for example value.

Example

  • Below example demo how to use OpenSC to execute by below commands flow

    1. Select applet with NDEF AID

    2. Select NDEF data file to use

    3. Write NDEF Data https://authentrend.com

    4. Read NDEF Data back

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 ................

How to send command to AT-USB-HID interface? Web Sample Code

The below sample code can be run on 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>