Learn how to use the FIDO Metadata Service (MDS) in your WebAuthn Relying Party
The FIDO Metadata Service (MDS) is a collection of Metadata statements that can be used by a relying party to validate authenticator attestation. Each metadata statement contains data that outlines different characteristics of an authenticator, and to prove that the authenticity of the device where the credential was generated, and who manufactured the device.
Within the Metadata Service, each authenticator is granted an AAID (for authenticators that implement FIDO UAF) or a AAGUID (for authenticators that implement FIDO2). Additional characteristics that can be found in a Metadata statement include: • FIDO status/certification level • Device status • Transports • Attachment hint • Device Icon
Here is an example of a Metadata Statement for the YubiKey 5Ci
{ "attestationCertificateKeyIdentifiers": [ "bf7bcaa0d0c6187a8c6abbdd16a15640e7c7bde2", "753300d65dcc73a39a7db31ef308db9fa0b566ae", "b753a0e460fb2dc7c7c487e35f24cf63b065347c", "b6d44a4b8d4b0407872969b1f6b2263021be627e", "6d491f223af73cdf81784a6c0890f8a1d527a12c" ], "metadataStatement": { "legalHeader": "https://fidoalliance.org/metadata/metadata-statement-legal-header/", "attestationCertificateKeyIdentifiers": [ "bf7bcaa0d0c6187a8c6abbdd16a15640e7c7bde2", "753300d65dcc73a39a7db31ef308db9fa0b566ae", "b753a0e460fb2dc7c7c487e35f24cf63b065347c", "b6d44a4b8d4b0407872969b1f6b2263021be627e", "6d491f223af73cdf81784a6c0890f8a1d527a12c" ], "description": "YubiKey 5Ci", "authenticatorVersion": 2, "protocolFamily": "u2f", "schema": 3, "upv": [ { "major": 1, "minor": 1 } ], "authenticationAlgorithms": [ "secp256r1_ecdsa_sha256_raw" ], "publicKeyAlgAndEncodings": [ "ecc_x962_raw" ], "attestationTypes": [ "basic_full" ], "userVerificationDetails": [ [ { "userVerificationMethod": "presence_internal" } ] ], "keyProtection": [ "hardware", "secure_element", "remote_handle" ], "matcherProtection": [ "on_chip" ], "cryptoStrength": 128, "attachmentHint": [ "external", "wired" ], "tcDisplay": [], "attestationRootCertificates": [ "MIIDHjCCAgagAwIBAgIEG0BT9zANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNZdWJpY28gVTJGIFJvb3QgQ0EgU2VyaWFsIDQ1NzIwMDYzMTAgFw0xNDA4MDEwMDAwMDBaGA8yMDUwMDkwNDAwMDAwMFowLjEsMCoGA1UEAxMjWXViaWNvIFUyRiBSb290IENBIFNlcmlhbCA0NTcyMDA2MzEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/jwYuhBVlqaiYWEMsrWFisgJ+PtM91eSrpI4TK7U53mwCIawSDHy8vUmk5N2KAj9abvT9NP5SMS1hQi3usxoYGonXQgfO6ZXyUA9a+KAkqdFnBnlyugSeCOep8EdZFfsaRFtMjkwz5Gcz2Py4vIYvCdMHPtwaz0bVuzneueIEz6TnQjE63Rdt2zbwnebwTG5ZybeWSwbzy+BJ34ZHcUhPAY89yJQXuE0IzMZFcEBbPNRbWECRKgjq//qT9nmDOFVlSRCt2wiqPSzluwn+v+suQEBsUjTGMEd25tKXXTkNW21wIWbxeSyUoTXwLvGS6xlwQSgNpk2qXYwf8iXg7VWZAgMBAAGjQjBAMB0GA1UdDgQWBBQgIvz0bNGJhjgpToksyKpP9xv9oDAPBgNVHRMECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAjvjuOMDSa+JXFCLyBKsycXtBVZsJ4Ue3LbaEsPY4MYN/hIQ5ZM5p7EjfcnMG4CtYkNsfNHc0AhBLdq45rnT87q/6O3vUEtNMafbhU6kthX7Y+9XFN9NpmYxr+ekVY5xOxi8h9JDIgoMP4VB1uS0aunL1IGqrNooL9mmFnL2kLVVee6/VR6C5+KSTCMCWppMuJIZII2v9o4dkoZ8Y7QRjQlLfYzd3qGtKbw7xaF1UsG/5xUb/Btwb2X2g4InpiB/yt/3CpQXpiWX/K4mBvUKiGn05ZsqeY1gx4g0xLBqcU9psmyPzK+Vsgw2jeRQ5JlKDyqE0hebfC1tvFu0CCrJFcw==" ], "icon": "data:image/png;base64,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" }, "statusReports": [ { "status": "FIDO_CERTIFIED_L1", "effectiveDate": "2020-05-12", "certificationDescriptor": "YubiKey 5Ci", "certificateNumber": "U2F110020191017007", "certificationPolicyVersion": "1.1.1", "certificationRequirementsVersion": "1.3" } ], "timeOfLastStatusChange": "2020-05-12" }
Version 3.0 of the MDS unlocks more ease of use by allowing a more streamlined way of integrating the repository into your own application. Older versions of MDS required you to find (or define) and integrate individual metadata statements. MDS 3.0 allows you to obtain the entire collection from a FIDO supported BLOB that is accessible without the need for registration, or an access token. This means that you can continuously call the central BLOB to pull up-to-date metadata statements into your application as frequently as your business requirements mandate.
MDS 3.0 also makes it easier for manufactures to keep the data related to their devices up-to date in order to allow FIDO applications to quickly react in the case of vulnerabilities on authenticators that were previously trusted.
The newest release of the Yubico java-webauthn-server now has built in support for MDS 3.0, allowing you to grab and store the repository locally, and to perform filtering on the collection. We will cover both concepts in the following section
The following lines should be added to your dependency file
<dependency> <groupId>com.yubico</groupId> <artifactId>webauthn-server-core</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>com.yubico</groupId> <artifactId>webauthn-server-attestation</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>com.yubico</groupId> <artifactId>yubico-util</artifactId> <version>2.0.0</version> </dependency>
The project can also be found on GitHub at https://github.com/Yubico/java-webauthn-server
Your FIDO Server will need to download the MDS directly from the FIDO Alliance. The Yubico java-webauthn-server v2.0.0 has built in capabilities to download the repository. The following Java code sample can be used to initialize the MDS in your application.
downloader = FidoMetadataDownloader.builder() .expectLegalHeader("Put the legal header here (get exact wording from BLOB)") .useDefaultTrustRoot() .useTrustRootCache(new File("/tmp/fido-mds-trust-root-cache.bin")) .useDefaultBlob() .useBlobCache(new File("/tmp/fido-mds-blob-cache.bin")) .build();
Let’s explore this code in more detail. The first point of interest is "expectLegalHeader". By using the FIDO MDS, you will be held to it’s terms of service. This is a way to alert the developer and code reviewers that you are acknowledging the terms of the MDS, and any implications that may have on your application. The input into this method is the Legal Header that exists within the BLOB.
"Retrieval and use of this BLOB indicates acceptance of the appropriate agreement located at https://fidoalliance.org/metadata/metadata-legal-terms/"
Next you will get the Trust Root Certificates for the MDS. You can proceed with the default method using useDefaultTrustRoot() while building your downloader. Next is useTrustRootCache - the FIDO Spec notes that when grabbing the Trust Root Certificate, your app should have some sort of caching logic. Our example above is writing this to a file in a directory named "tmp"
The next two lines are used to download the BLOB repository. In this example we are pulling the default BLOB, and telling the downloader to cache it in the "tmp" directory.
The next step will be to create a FidoMetadataService Object as such
mds = FidoMetadataService.builder() .useDownloader(downloader) .build();
This will provide you with the metadataservice object that can be used when configuring your RelyingParty object:
RelyingParty rp =RelyingParty.builder() .identity(/*... */) .credentialRepository(/*... */) .attestationTrustSource(mds) .allowUntrustedAttestation(true); //Optional step: set to true (default) or false .build();
You may set allowUntrustedAttestation(false) to require trusted attestation for any new registrations.
If you do not wish to use the Default MDS BLOB you may use the following snippet which will allow you to enter in a BLOB that you retrieved from some other mechanism.
mds = FidoMetadataService.builder() .useBlob(/* Enter your BLOB payload here */) .build();
There may be cases where you do not want your WebAuthn server to trust certain authenticators. You may not want to allow credentials to register if they: are a specific authenticator, made by a specific company, have a known vulnerability, or aren’t a certain certification level.
You can add a filtering mechanism when defining the FidoMetadataService object to only include authenticators that have specific characteristics based on your business requirements.
The sample below will demonstrate how to filter for only platform authenticators (metadata statements where the Attachment Hint entry is "Internal").
FidoMetadataService.builder() .useBlob(downloader) .filter(blobEntry -> blobEntry.getMetadataEntry().getMetadataStatement().get() .getAttachmentHint().get().contains(AttachmentHint.ATTACHMENT_HINT_INTERNAL)) .build();
You don’t want to add an additional hurdle to your end users by requiring a specific authenticator, especially in the consumer space. Using the data provided by MDS will allow you to understand the authenticators that are being used by your users - and with that knowledge you can alert users if certain issues are found on their devices. If an authenticator is found to introduce security vulnerabilities, then begin to add it to a deny-list, but otherwise begin your implementation with allowing all trusted authenticators.
In the case of enterprise/high security applications it becomes more acceptable to use this data to filter on specific authenticators, or characteristics during the initial implementation.
The FIDO specification mentions the recommendation to cache the metadata BLOB object. The download example above will only grab the metadata BLOB when the WebAuthn Server is initially started. You may modify this behavior to grab an updated version of the repository on a cadence specified by your business requirements. The FIDO Alliance’s recommendation is to download the updated BLOB once a month. Caching will also help with performance as it may cut down on the time needed to grab the full repository in the case that the server requires a restart before the next scheduled update.
Some applications, especially in the enterprise space, may require the use of specific authenticators. In this case instead of adding all of the repository into a Trusted Attestation group (and additionally filtering to get a subset of the entire BLOB), it might make more sense to construct your own BLOB with the limited authenticators that you plan to allow. MDS acts as a baseline for most Relying Parties, so it’s up to you to determine the affect on your users if you were to deny certain authenticators.