demo · v143 · capabilities (fugu)
PIV card reader
A fully interactive simulation of reading a PIV (Personal Identity Verification) / CAC smart card using the Web Smart Card API. Insert a virtual card, select the PIV applet, choose a data object, send the GET DATA APDU, and verify a PIN — with hex dumps and parsed field labels throughout.
Origin trial / behind a flag:
navigator.smartCard ships behind
chrome://flags/#web-smart-card-api in Chrome 143. The full simulation below runs
without a physical card or the flag enabled. When the API is present, the "Real API path" panel
at the bottom shows the actual call chain.
1 — Insert card
PIV / CACUS Federal ID
SN: 9876-A
SN: 9876-A
No card present
2 — Select PIV applet
PIV AID
A0 00 00 03 08 00 00 10 00 01 00NIST SP 800-73-4 registered AID
APDU sent
00 A4 04 00 0B A0 00 00 03 08 00 00 10 00 01 00 00SELECT (CLA=00 INS=A4 P1=04 P2=00)
Insert a card first.
3 — Choose data object
5F C1 05
Certificate for PIV Authentication — X.509 cert used for card authentication.
5F C1 07
Card Capability Container — FIPS 201 capabilities and GUID.
5F C1 08
Cardholder Facial Image — JPEG2000 biometric reference.
5F C1 02
CHUID — Cardholder Unique Identifier with FASC-N and expiry date.
Select PIV applet first.
4 — PIN verification
PIV cards use a 6–8 digit PIN. Three consecutive failures (SW 69 83) permanently blocks the PIN reference. Retry counter decrements on each wrong attempt (SW 63 Cx).
Select PIV applet first.
VERIFY APDU detail
CLA=00 INS=20 P1=00 P2=80
Lc=08 (PIN padded to 8 bytes with 0xFF)
Data: PIN bytes + FF padding
Le: (absent — VERIFY has no response data)
Correct PIN → SW 90 00
Wrong PIN, n retries left → SW 63 Cn
Blocked → SW 69 83
Lc=08 (PIN padded to 8 bytes with 0xFF)
Data: PIN bytes + FF padding
Le: (absent — VERIFY has no response data)
Correct PIN → SW 90 00
Wrong PIN, n retries left → SW 63 Cn
Blocked → SW 69 83
Real API path (Web Smart Card API)
1
const ctx = await navigator.smartCard.requestContext();2
const readers = await ctx.listReaders();
const reader = readers[0]; // e.g. "Yubico YubiKey 5"3
const connection = await reader.connect('shared');4
await connection.startTransaction(async () => {
// SELECT PIV applet
const pivAid = new Uint8Array([0xA0,0x00,0x00,0x03,0x08,0x00,0x00,0x10,0x00,0x01,0x00]);
const sel = new Uint8Array([0x00,0xA4,0x04,0x00,pivAid.length,...pivAid,0x00]);
const selResp = await connection.transmit(sel);
// GET DATA for CHUID (tag 5F C1 02)
const getData = new Uint8Array([0x00,0xCB,0x3F,0xFF,0x05,0x5C,0x03,0x5F,0xC1,0x02]);
const resp = await connection.transmit(getData);
// Parse TLV, extract FASC-N, expiry, signature
return resp;
});5
await connection.disconnect();Click to attempt navigator.smartCard.requestContext()