Skip to content

X FIDO 2.0 applet profile

Martin Paljak edited this page Dec 13, 2022 · 6 revisions

NOTE: names of fields might change a bit to accommodate "as small as possible, as readable as possible" goals. Meaning of fields is supposed to remain unchanged also in later and extended revisions.

Rules:

  • all readable properties are echoed back to administrator after both get and set
  • only document array elements can be removed with del (ie elements of rules and credentials)
  • all MANDATORY fields must be set when writing a document
  • all OPTIONAL fields stay at existing or default values if not set in same document
  • data types are either boolean (true/false), numeric (0..N), string, or binary (represented as hex strings)
Read-Write flag Meaning Example
RO Read-Only Credential counter
RW Read-Write Rule setting
WO Write-Only PIN value
W1O Write-Once-Only Attestation key
W1RO Write-Once-Read-Only Attestation public key
pin:
  change: true # RW, set if PIN must be changed by user before authenticator can be used
  value: SecretSauce123 # WO, UTF-8 value of plaintext (new) PIN value to set. MUST satisfy current policy
  tries: 8 # W1+RW, default 8 (by FIDO specs) MUST be written before config message, if non-default needed. Re-writing original value resets PIN try counter.
  managed: false # W1RO, default is false. If true, new PIN value can be set and retries reset by administrator.
  destruct: false # W1RO, default is false if managed == true. If true, reaching PIN tries counter 0 will erase all credentials (K.MASTER)
  policy: # RW, default allow all / require none. Sets `pin.change` to `true` if policy is made tighter.
    min: 8 # RW, 4..63 (minimum by FIDO specs and common sense)
    max: 63 # RW, min..63 (maximum by FIDO specs)
    allow_lower: true # RW, allow a-z in plaintext PIN
    require_lower: false # RQ, allow + require a-z in plaintext PIN
    allow_upper: true # RW, allow A-Z in plaintext PIN
    require_upper: false # RW, allow + require A-Z in plaintext PIN
    allow_number: true # RW, allow 0-9 in plaintext PIN
    require_number: false # RW, allow + require 0-9 in plaintext PIN
    allow_special: true # RW, allow not (lower, upper, number) in plaintext PIN
    require_special: false # RW, allow + require not (lower, upper, number) in plaintext PIN

config: # RW, MUST be written to bring authenticator into usable state after manufacturing (applet installation)
  version: 0.1.1 # RO, string identifier (version) of the applet
  aaguid: binary # W1RO, binary, AAGUID of the authenticator; MANDATORY (?)
  rules: 8 # W1RO, default for number of rules that can be stored, including default rule
  credentials: 8 # W1RO, default number for credentials that can be stored (resident keys / discoverable credentials)
  att_key: <binary> # W1O, sets authenticator batch attestation private key (P-256); MANDATORY
  att_cert: <binary> # W1RO, sets authenticator batch attestation certificate (X.509); MANDATORY
  att_self: false # W1RO, default is false, if true uses self-attestation with FIDO2; WIP: rule property
  u2f: true # RW, default is true, indicates if U2F interface is allowed
  gp: false # W1RO, default is false, indicates if lifecycle changes trigger GlobalPlatform lifecycle changes.

# list of stored credentials (resident keys).
# Used to read all credentials with `get: credentials` and `get: next`
# OR importing credentials with `set: {credential: {id: "XXYY", origin: "example.com"}}`
# primary key: id (binary)
credentials: 
- id: <binary> # W1RO, Credential ID, MANDATORY
  origin: idp.example.com # W1RO, RP ID of credential, MANDATORY
  uid: <binary> # W1RO, UID of resident key, MANDATORY
  public_key: <binary> # W1RO, public key (uncompressed P-256 point) of credential, MANDATORY
  private_key: <binary> # W1O, private key of credential (P-256), MANDATORY
  name: <string> # RW, userName property of credential, OPTIONAL
  protection: 1 # W1RO, credProtect extension value, OPTIONAL
  counter: <integer> # W1RO, counter value, MANDATORY
 
# Rules that apply to RP-s this authenticator in general
# Wildcard rules (containing *, EXCEPT default rule "*") do NOT apply to U2F, but DO apply to FIDO2
# Default rule matching any RP ("*") is internal rule, always last, can not be deleted, applies to U2F
# Used to read all rules with `get: rules` and `get: next`
# OR importing credentials with `set: {credential: {id: "XXYY", origin: "example.com"}}`
# Primary key: pattern (string)
rules: 
- pattern: 'example.com' # W1RO, simple pattern for matching RP-s with both U2F and FIDO2 protocols (hashed internally), MANDATORY
  i: 0 # RO, position in internal array
  allow: true # RW, default true allows to use authenticator (incl any existing credentials).
- pattern: '*.cust.example.com' # W1RO, simple pattern for matching anything (eg foo.cust.example.com and foo.bar.cust.example.com) under cust.example.com
  i: 1
  allow: true
- pattern: '*' # RO, always present default rule, always last rule, can not be deleted/moved
  i: 3
  allow: false

PIN handling

  • to unblock a PIN or change the PIN value or tries counter by administrator, the PIN must be in managed mode (pin.managed==true)
  • changing pin.managed from false to true is DESTRUCTIVE (erases all credentials created by the user)
  • changing pin.destruct from true to false is DESTRUCTIVE (erases all credentials by re-generating K.MASTER)

Roles and messaging channel(s)

Minimal config file

config:
  att_key: XXYY
  att_cert: XXYY

Will create an U2F+FIDO2 authenticator with no PIN value set, default values for PIN (4..63 free form values with 8 retries) and 8 slots for rules and credentials. Default rule allows all operations as standard FIDO2 authenticator.

Sample config file

pin:
  managed: true
  value: 1234432_
  change: true
  tries: 3
  destruct: true
  policy:
    min: 8
    require_special: true
config:
  rules: 2
  att_key: XXYY
  att_cert: XXYY
rules:
- pattern: "example.com"
  allow: true
- pattern: "*"
  allow: false

Authenticator that can only be used on example.com, requires PIN change before use, allows to change/reset the PIN by administrator and requires a special character in the PIN. After 3 incorrect PIN tries, the authenticator self-destructs. Only two rules are allowed.

.properties format

pin.managed=true
pin.value=1234432_
pin.change=true
pin.tries=3
pin.destruct=true
pin.policy.min=8
pin.policy.require_special=true
config.rules=2
config.att_key=XXYY
config.att_cert=XXYY
rules.1.pattern=example.com
rules.1.allow=true
rules.2.pattern=*
rules.2.allow=false

Default (sample) attestation key/certificate

att_key: 67898b374111e84985acb9f0573752bb9dac1a2e53c05aa6798ec43bfd079f5c
att_cert: 308201cc30820171a003020102020101300a06082a8648ce3d04030230373135303306035504030c2c6a617661636172642e70726f2074657374206174746573746174696f6e20726f6f7420233230323230393237301e170d3232303130313030303030305a170d3435303130313030303030305a305b310b300906035504061302454531173015060355040a0c0e4fc39c204bc3bc62657270756e6b31223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310f300d06035504030c06582d4649444f3059301306072a8648ce3d020106082a8648ce3d03010703420004e88ab209228f7922394ad8abd7085f09a1224c81a4087650d35ffc6ab73e949827216404f8c6bbba956c57f0b01bc7247dd554fb458832cd4c0015eb277483f8a34a3048300c0603551d130101ff040230003015060b2b0601040182e51c02010104060404030204103021060b2b0601040182e51c01010404120410ac5ebf97149e4b1c977300db72d399e2300a06082a8648ce3d0403020349003046022100b364595cb7113a47241e4d9a1dce5c7400cede8d5a6f9ee2dd35f9bc485a30a3022100dc4e7490c782e6939cfa430d8ae83d59080a13380f993291cf2e514c6e300e7d