FIDO2 / CTAP details
This page documents the FIDO2 / CTAP protocol surface the badge actually
implements, as found in components/mod_fido2/. It is descriptive of the
firmware, not of the FIDO specification: where a feature is advertised but not
implemented, it is called out.
For the generated code reference, see the Code reference.
Transport (CTAPHID)
Section titled “Transport (CTAPHID)”| Property | Value |
|---|---|
| Transport | USB HID, FIDO Alliance usage page (CTAPHID) |
| Report / packet size | 64 bytes |
| CTAPHID commands handled | INIT, PING, WINK, CANCEL, CBOR, MSG |
| Capability flags (INIT) | WINK | CBOR |
| Max message size constant | 2048 bytes |
MSG carries CTAP1 / U2F APDUs (VERSION, REGISTER, AUTHENTICATE); CBOR
carries CTAP2 commands.
authenticatorGetInfo
Section titled “authenticatorGetInfo”The getInfo response is a 10-entry map:
| Key | Field | Value |
|---|---|---|
| 0x01 | versions | FIDO_2_0, FIDO_2_1, U2F_V2 |
| 0x02 | extensions | appid, credProtect, appidExclude |
| 0x03 | aaguid | CDCBAD6E39C30001BAD6E00100000001 |
| 0x04 | options | see below |
| 0x05 | maxMsgSize | 1200 |
| 0x06 | pinUvAuthProtocols | [2] |
| 0x07 | maxCredentialCountInList | 8 |
| 0x08 | maxCredentialIdLength | 64 |
| 0x09 | transports | ["usb"] |
| 0x0A | algorithms | ES256, EdDSA |
Options
Section titled “Options”| Option | Value | Meaning |
|---|---|---|
rk | true | Resident / discoverable keys supported |
up | true | User presence supported |
uv | false | No built-in user verification (e.g. biometric) |
plat | false | Removable authenticator |
credMgmt | true | Credential management supported |
clientPin | true | ClientPIN supported |
pinUvAuthToken | true | pinUvAuthToken supported |
Supported CTAP2 commands
Section titled “Supported CTAP2 commands”| Command | Code | Status |
|---|---|---|
| makeCredential | 0x01 | Implemented |
| getAssertion | 0x02 | Implemented |
| getInfo | 0x04 | Implemented |
| clientPIN | 0x06 | Implemented |
| reset | 0x07 | Implemented (requires on-device user presence) |
| getNextAssertion | 0x08 | Implemented |
| credentialManagement | 0x0A | Implemented |
| selection | 0x0B | Implemented (user presence only) |
| largeBlobs | 0x0C | Returns CTAP2_ERR_UNSUPPORTED_OPTION |
| authenticatorConfig | 0x0D | Returns CTAP2_ERR_UNSUPPORTED_OPTION |
| bioEnrollment | 0x09 | Not dispatched (CTAP1_ERR_INVALID_COMMAND) |
COSE algorithms and curves
Section titled “COSE algorithms and curves”| Algorithm | COSE id | Curve | Used for |
|---|---|---|---|
| ES256 | -7 | P-256 (secp256r1) | Credential keys, attestation |
| EdDSA | -8 | Ed25519 | Credential keys |
| ECDH-ES + HKDF-256 | -25 | P-256 | ClientPIN key agreement |
makeCredential selects ES256 -> P-256 or EdDSA -> Ed25519 from
pubKeyCredParams; any other requested algorithm yields
CTAP2_ERR_UNSUPPORTED_ALGORITHM.
ClientPIN
Section titled “ClientPIN”| Aspect | Value |
|---|---|
| pinUvAuthProtocol | 2 (protocol 0 / unset also accepted) |
| Key agreement | COSE EC2, P-256, alg ECDH-ES+HKDF-256 |
| Protocol-2 encryption | AES-256-CBC, 16-byte IV prefixed to ciphertext |
| pinUvAuthParam | HMAC-SHA-256(pinToken, message), first 32 bytes (protocol 2) |
| PIN retries (max) | 8 |
| UV retries (max) | 3 |
Subcommands:
| Subcommand | Code | Status |
|---|---|---|
| getPINRetries | 0x01 | Implemented |
| getKeyAgreement | 0x02 | Implemented |
| setPIN | 0x03 | CTAP2_ERR_UNSUPPORTED_OPTION |
| changePIN | 0x04 | CTAP2_ERR_UNSUPPORTED_OPTION |
| getPinToken | 0x05 | Implemented |
| getPinUvAuthTokenUsingPinWithPermissions | 0x09 | Implemented |
The PIN is not settable over the wire. The badge verifies the decrypted PIN
hash against its own stored PIN hash, so the FIDO PIN is the badge PIN, set
on-device. getPinToken returns CTAP2_ERR_PIN_NOT_SET when no PIN hash is
available and CTAP2_ERR_PIN_BLOCKED after the retry counter reaches zero.
pinUvAuthToken permissions
Section titled “pinUvAuthToken permissions”The permission bits are defined (mc, ga, cm, be, lbw, acfg), but
only the credential-bound paths consume them:
makeCredential behaviour
Section titled “makeCredential behaviour”upmust be true (false yieldsCTAP2_ERR_INVALID_OPTION);uv=trueis rejected withCTAP2_ERR_UNSUPPORTED_OPTION(no internal UV).- User presence is always requested on the device before a key is created.
- An existing credential for the same RP-ID + user handle is overwritten.
appidExcludematching an existing credential yieldsCTAP2_ERR_CREDENTIAL_EXCLUDED.- Attestation is always returned (see below).
credProtect
Section titled “credProtect”The credProtect extension (levels 1-3) is parsed at registration, stored with
the credential, echoed in the authenticator-data extensions, and reported by
credential management (defaulting to level 1 when unset).
getAssertion and sign counters
Section titled “getAssertion and sign counters”- With no
allowList, all resident credentials for the RP are returned (discoverable flow), withgetNextAssertioniterating the rest. - authData flags:
UP(0x01) is set when user presence was requested;UV(0x04) is set when a pinUvAuth token was verified for the request. - ECDSA assertions are DER-encoded; EdDSA assertions are raw 64-byte signatures, both produced by the secure element.
Signature counter
Section titled “Signature counter”Each credential has its own monotonic signature counter, incremented on every assertion and persisted in TROPIC01 R-Memory. (A separate global authentication counter is also kept in NVS, distinct from the per-credential counter reported in authData.)
Credential management
Section titled “Credential management”- Requires a valid
pinUvAuthTokenbefore any subcommand runs. - Implemented subcommands:
getCredsMetadata,enumerateRPsBegin/GetNext,enumerateCredentialsBegin/GetNext,deleteCredential. - Responses include
credProtectfor each credential.
Attestation format
Section titled “Attestation format”makeCredential returns packed attestation with an x5c certificate array, a
single self-signed per-device certificate, and an ES256 (P-256) signature over
authData || clientDataHash. The attestation private key is a chip-bound key in
TROPIC01 ECC slot 0. See
FIDO2 attestation key & AAGUID for the
certificate fields and key lifecycle.
Capacity
Section titled “Capacity”| Limit | Value | Source |
|---|---|---|
| FIDO2 ECC key slots | 26 (slots 5-30) | main/tropic_slot_map.h |
| FIDO2 R-Memory slots | 27 (slots 5-31) | main/tropic_slot_map.h |
| Max credentials | 26 (one ECC slot each) | bounded by ECC slot count |
| Credential ID length | 64 bytes | FIDO2_CRED_ID_LEN |
Every credential, resident or not, consumes one ECC slot because its private key is generated and held in the secure element; there is no key-wrapping scheme for unlimited server-side credentials.