Ethan T. McGee's Blog

FIDO Metadata

This is the fourth post in a multi-part series covering passkeys (or WebAuthn). Each post builds on previous posts in the series, so catch up if needed before continuing.

Table of Contents

Note: will be updated as more posts are completed

We've registered a passkey, and we've used it to authenticate. In the registration ceremony, we discussed the attestation object but didn't explore how to validate that the authenticator is genuinely what it claims to be using the FIDO MDS. For high-security environments, you might want to limit the types of authenticators that can be used, what manufacturers can be used, or you might want to allow certain individual authenticators. The FIDO MDS is the underlying service that permits such checks.

Most of these restrictions depend on the authenticator's ability to produce an attestation certificate, which some software authenticators are unable to do (or they are unable to produce a full attestation certificate). Due to these limitations, unlike previous posts which largely related to any authenticator, this article will focus more heavily on hardware authenticators in some sections.

The FIDO MDS is a service provided by the FIDO Alliance primarily focused on identifying authenticators and their capabilities while also validating the chain of trust to ensure the authenticator is really what it claims to be. This service helps to ensure that someone does not build a clone of a high security authenticator then pass that clone off as the real thing. It also helps organizations enforce policy decisions such as "authenticators used with our service must have biometric capabilities".

While many organizations may choose to ignore such limitations in favor of making life easier for their end users, it is still a good idea to perform basic checks against the FIDO MDS (if possible, recall not all authenticators can produce a valid attestation certificate).

Note: The MDS is updated semi-monthly and using live checks is discouraged. Most systems will cache the MDS on startup, then fetch a fresh copy weekly or monthly.

Below is an example of a FIDO metadata blob (courtesy of the FIDO Alliance):

{
  "legalHeader": "https://fidoalliance.org/metadata/metadata-statement-legal-header/",
  "friendlyNames": {"en-US": "FIDO Sample Security Key"},
  "description": "FIDO Alliance Sample FIDO2 Authenticator",
  "aaguid": "0132d110-bf4e-4208-a403-ab4f5f12efe5",
  "alternativeDescriptions": {
      "ru-RU": "Пример FIDO2 аутентификатора от FIDO Alliance",
      "fr-FR": "Exemple FIDO2 authenticator de FIDO Alliance",
      "zh-CN": "來自FIDO Alliance的示例FIDO2身份驗證器"
  },
  "protocolFamily": "fido2",
  "schema": 3,
  "authenticatorVersion": 5,
  "upv": [
    { "major": 1, "minor": 0 }
  ],
  "authenticationAlgorithms": ["secp256r1_ecdsa_sha256_raw", "rsassa_pkcsv15_sha256_raw"],
  "publicKeyAlgAndEncodings": ["cose"],
  "attestationTypes": ["basic_full"],
  "userVerificationDetails": [
    [
      {"userVerificationMethod": "none"}
    ],
    [
     {"userVerificationMethod": "presence_internal"}
    ],
    [{
      "userVerificationMethod": "passcode_external",
      "caDesc": { 
        "base": 10,
        "minLength": 4
      }
    }],
    [{
      "userVerificationMethod": "passcode_external",
      "caDesc": { 
        "base": 10,
        "minLength": 4
     }},
     {"userVerificationMethod": "presence_internal"}
    ]
  ], 
  "keyProtection": ["hardware", "secure_element"],
  "matcherProtection": ["on_chip"],
  "cryptoStrength": 128,
  "attachmentHint": ["external", "wired", "wireless", "nfc"],
  "tcDisplay": [],
  "attestationRootCertificates": [
    "MIICPTCCAeOgAwIBAgIJAOuexvU3Oy2wMAoGCCqGSM49BAMCMHsxIDAeBgNVBAMM
    F1NhbXBsZSBBdHRlc3RhdGlvbiBSb290MRYwFAYDVQQKDA1GSURPIEFsbGlhbmNl
    MREwDwYDVQQLDAhVQUYgVFdHLDESMBAGA1UEBwwJUGFsbyBBbHRvMQswCQYDVQQI
    DAJDQTELMAkGA1UEBhMCVVMwHhcNMTQwNjE4MTMzMzMyWhcNNDExMTAzMTMzMzMy
    WjB7MSAwHgYDVQQDDBdTYW1wbGUgQXR0ZXN0YXRpb24gUm9vdDEWMBQGA1UECgwN
    RklETyBBbGxpYW5jZTERMA8GA1UECwwIVUFGIFRXRywxEjAQBgNVBAcMCVBhbG8g
    QWx0bzELMAkGA1UECAwCQ0ExCzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZI
    zj0DAQcDQgAEH8hv2D0HXa59/BmpQ7RZehL/FMGzFd1QBg9vAUpOZ3ajnuQ94PR7
    aMzH33nUSBr8fHYDrqOBb58pxGqHJRyX/6NQME4wHQYDVR0OBBYEFPoHA3CLhxFb
    C0It7zE4w8hk5EJ/MB8GA1UdIwQYMBaAFPoHA3CLhxFbC0It7zE4w8hk5EJ/MAwG
    A1UdEwQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIhAJ06QSXt9ihIbEKYKIjsPkri
    VdLIgtfsbDSu7ErJfzr4AiBqoYCZf0+zI55aQeAHjIzA9Xm63rruAxBZ9ps9z2XN
    lQ=="
  ],
  "icon": "data:image/png;base64,
    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",
  "authenticatorGetInfo": {
      "versions": [ "U2F_V2", "FIDO_2_0" ],
      "extensions": [ "credProtect", "hmac-secret" ],
      "aaguid": "0132d110bf4e4208a403ab4f5f12efe5",
      "options": {
        "plat": false,
        "rk": true,
        "clientPin": true,
        "up": true,
        "uv": true,
        "uvToken": false,
        "config": false
      },
      "maxMsgSize": 1200,
      "pinUvAuthProtocols": [1],
      "maxCredentialCountInList": 16,
      "maxCredentialIdLength": 128,
      "transports": ["usb", "nfc"],
      "algorithms": [{
          "type": "public-key",
          "alg": -7
        },
        {
          "type": "public-key",
          "alg": -257
        }
      ],
      "maxAuthenticatorConfigLength": 1024,
      "defaultCredProtect": 2,
      "firmwareVersion": 5
  }
}

The blob has a large amount of information, and not all of the information is useful to us for validating an authenticator. For example, the icon is useful for helping customers distinguish authenticators in a list of authenticators, but it doesn't really help us validate that authenticator.

Let's walk through the most important fields for validation and policy enforcement:

Core Identity Fields:

Those two fields, combined with verification that the attestation certificate was signed by one of the root keys, are usually enough to determine that an authenticator can be trusted.

Authenticator Capabilities:

Security Properties:

User Verification:

Physical Properties:

CTAP2 Information:

Those core fields provide the foundation for most validation and policy decisions. Additional fields like authenticatorVersion (firmware version) and certification levels can also be checked depending on your requirements. The remaining verifications are largely up to your needs.

A few common scenarios are that the authenticator is certified to a certain level: L1, L2 or L3. Some systems also check that the root certificate is in an approved list of root certificates (or that the authenticator was manufactured by a specific set of vendors).

Note that much of the FIDO MDS is optional so, for the authenticators you wish to support, check which fields their manufacturers provide to the MDS. Also remember that most software authenticators are not listed in the MDS or their listing is very minimal if they can even produce an attestation certificate at all.

Earlier I mentioned that you could limit verification to specific authenticators. This requires enterprise attestation support which can return the unique serial number of the individual authenticator. Not all authenticators support this, but many hardware authenticators do.

Whew, now that we know what the FIDO MDS is, let's show the basic algorithm for how it's used to provide practical validation of an authenticator. During registration, after receiving the attestation object:

  1. Extract the AAGUID from the authenticator data
  2. Look up the AAGUID in your cached MDS data
  3. Verify the attestation certificate chain against the attestationRootCertificates
  4. (Optional) Enforce policy requirements:
    • Check keyProtection includes hardware or secure_element
    • Verify cryptoStrength meets your minimum (e.g., ≥128 bits)
    • Confirm the authenticator is certified to L2 or higher

If the AAGUID isn't in the MDS, you'll need to decide your policy: reject unknown authenticators, or accept them with reduced assurance.

Usage of the FIDO MDS provides a high degree of assurance that your authenticator has certain capabilities or that it comes from certain trusted manufacturers. Verification against the MDS is vital for high security organizations to help better protect themselves, but it can also be used for lower security systems as well.

Up next, we will discuss the packed attestation format produced by many hardware authenticators. Understanding it will be essential for building our toy authenticator.