WebAuthn notes¶
What a relying party (a website) sees when you register nixtropic, and how to read it.
AAGUID¶
6e 69 78 74 72 6f 70 69 63 00 00 00 00 00 00 04
└──────── "nixtropic" ───────┘ └── zero ──┘ └ version
Self-assigned: registering with the FIDO Alliance Metadata Service is not affordable
for a hobby open-source project. Sites that look the AAGUID up show the provider as
unknown or unavailable. The last byte is the capability version, 0x04 since v0.3.0.
When it changes: whenever a site can observe a difference — algorithms or options
in GetInfo, supported commands, protocol behaviour. Internal fixes and the OpenPGP
card do not change it. The constant is NIXTROPIC_AAGUID in
firmware/src/fido_hid/ctap2.c.
Attestation¶
Format none. A self-signed attestation would prove nothing with a self-assigned
AAGUID, and some servers fail to verify Ed25519 attestation signatures. With
none, browsers usually zero the AAGUID too; request direct attestation (for
example on webauthn.io: Advanced Settings → Attestation → Direct) to see it.
Credential ID¶
18 bytes:
[0] version = 0x01
[1] ECC key slot (0..28)
[2..17] 16-byte random nonce from the TROPIC01 TRNG
The nonce is stored with the credential: a forged ID would have to guess 128 bits. The slot number is visible and reveals nothing secret. Every credential, discoverable or not, occupies a chip slot, so the dongle holds at most 29.
Algorithms¶
| COSE | Algorithm | Key on the chip |
|---|---|---|
| -8 | EdDSA (Ed25519) | 32-byte public key |
| -7 | ES256 (P-256) | 64-byte public key; the STM32 hashes authData ‖ clientDataHash, the chip signs the digest |
The authenticator takes the first of the two in the order the site lists them. RS256 is not supported (no RSA on the chip).
authData layout¶
[0..31] rpIdHash (SHA-256 of the RP ID)
[32] flags: bit 0 UP, bit 2 UV, bit 6 AT, bit 7 ED
[33..36] signCount (uint32, big-endian)
[37..] attestedCredentialData, when AT is set:
[37..52] AAGUID
[53..54] credential ID length = 18
[55..72] credential ID
[73..] COSE public key
signCount comes from TROPIC01 monotonic counter 0, shared by all credentials
(WebAuthn allows this). The chip's counter counts down; the firmware reports
MAX − value, reserving the value before it signs. The 32-bit range alone would
last about 136 years at one signature per second; in practice the chip’s write
endurance, not the range, is the limit (the datasheet gives 100 000 reprogram cycles as a
typical figure).
GetInfo¶
fido2-token -I /dev/hidrawN reports:
- versions
FIDO_2_0 - AAGUID
6e697874726f70696300000000000004 - options
rk,up,plat=false,clientPin,credMgmt,authnrCfg,pinUvAuthToken,alwaysUv,makeCredUvNotRqd(the last two change with thealwaysUvsetting) - algorithms
eddsa,es256 - PIN protocol 1
GetInfo lists no extensions; MakeCredential still answers the credProps extension
(whether the credential was stored as discoverable) when a site asks for it.
Browsers¶
| Browser / OS | Result |
|---|---|
| Firefox / Linux | works |
| Brave / Linux | works |
| Chrome / Linux | expected to work (same engine as Brave), not verified separately |
| Windows 11 browsers | works from v0.3.1 (Brave, webauthn.io, PIN set); v0.3.0 failed when a PIN was set because Windows abandoned the silent PIN steps (Windows) |
| Windows 10 browsers | works with v0.3.2 (Chromium browser, PIN set, physical laptop) |
| Chrome or Brave / macOS | works with v0.3.2 (registration and login, PIN set) |
| Safari / macOS | untested |
Troubleshooting steps: Linux setup.