fido_mds/mds.rs
1//! An implementation of the types for the fido metadata service as defined by
2//! <https://fidoalliance.org/specs/mds/fido-metadata-service-v3.0-ps-20210518.html>
3//!
4//! This allows parsing the fido metadata blob and consuming it's content. See `FidoMds`
5//! for more.
6
7use compact_jwt::{crypto::JwsX509VerifierBuilder, JwsCompact, JwsVerifier, JwtError};
8use openssl::x509;
9use serde::{Deserialize, Serialize};
10use std::fmt;
11use std::str::FromStr;
12
13use std::collections::BTreeMap;
14use std::hash::{Hash, Hasher};
15use uuid::Uuid;
16
17static GLOBAL_SIGN_ROOT_CA_R3: &str = r#"
18-----BEGIN CERTIFICATE-----
19MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
20A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
21Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4
22MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG
23A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
24hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8
25RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT
26gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm
27KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd
28QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ
29XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw
30DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o
31LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU
32RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp
33jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK
346fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX
35mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs
36Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
37WD9f
38-----END CERTIFICATE-----
39"#;
40
41// https://fidoalliance.org/specs/mds/fido-metadata-service-v3.0-ps-20210518.html#metadata-blob-format
42
43fn assume_true() -> bool {
44 true
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize)]
48#[serde(deny_unknown_fields, rename_all = "camelCase")]
49/// Unclear
50pub struct Upv {
51 /// Major
52 pub major: u16,
53 /// Minor
54 pub minor: u16,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Hash)]
58#[serde(deny_unknown_fields, rename_all = "camelCase")]
59/// The CodeAccuracyDescriptor describes the relevant accuracy/complexity aspects of passcode user verification methods.
60pub struct CodeAccuracyDescriptor {
61 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
62 ///
63 /// The numeric system base (radix) of the code, e.g. 10 in the case of decimal digits.
64 pub base: u16,
65 /// The minimum number of digits of the given base required for that code, e.g. 4 in the case of 4 digits.
66 pub min_length: u16,
67 /// Maximum number of false attempts before the authenticator will block this method (at least
68 /// for some time). 0 means it will never block.
69 pub max_retries: Option<u16>,
70 /// Enforced minimum number of seconds wait time after blocking (e.g. due to forced reboot or
71 /// similar). 0 means this user verification method will be blocked, either permanently or until
72 /// an alternative user verification method method succeeded. All alternative user verification
73 /// methods must be specified appropriately in the Metadata in userVerificationDetails.
74 pub block_slowdown: Option<u16>,
75}
76
77#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
78#[serde(deny_unknown_fields, rename_all = "camelCase")]
79/// The BiometricAccuracyDescriptor describes relevant accuracy/complexity aspects in the case of a biometric user verification method.
80pub struct BiometricAccuracyDescriptor {
81 /// The false rejection rate [ISOIEC-19795-1] for a single template, i.e. the percentage of
82 /// verification transactions with truthful claims of identity that are incorrectly denied. For
83 /// example a FRR of 10% would be encoded as 0.1.
84 ///
85 /// This value is self attested and, if the authenticator passed biometric certification, the
86 /// data is an independently verified FRR as measured when meeting the FRR target specified in
87 /// the biometric certification requirements FIDOBiometricsRequirements for the indicated
88 /// biometric certification level (see certLevel in related biometricStatusReport as specified
89 /// in FIDOMetadataService).
90 #[serde(rename = "selfAttestedFRR")]
91 pub self_attested_frr: Option<f32>,
92 /// The false acceptance rate ISOIEC-19795-1 for a single template, i.e. the percentage of
93 /// verification transactions with wrongful claims of identity that are incorrectly confirmed.
94 /// For example a FAR of 0.002% would be encoded as 0.00002.
95 ///
96 /// This value is self attested and, if the authenticator passed biometric certification, the
97 /// data is an independently verified FAR specified in the biometric certification requirements
98 /// FIDOBiometricsRequirements for the indicated biomeric certification level (see certLevel
99 /// in related biometricStatusReport as specified in FIDOMetadataService).
100 #[serde(rename = "selfAttestedFAR")]
101 pub self_attested_far: Option<f32>,
102
103 /// Maximum number of alternative templates from different fingers allowed (for other modalities,
104 /// multiple parts of the body that can be used interchangeably), e.g. 3 if the user is allowed
105 /// to enroll up to 3 different fingers to a fingerprint based authenticator.
106 pub max_templates: Option<u16>,
107 /// Maximum number of false attempts before the authenticator will block this method (at least
108 /// for some time). 0 means it will never block.
109 pub max_retries: Option<u16>,
110 /// Enforced minimum number of seconds wait time after blocking (e.g. due to forced reboot or
111 /// similar). 0 means that this user verification method will be blocked either permanently or
112 /// until an alternative user verification method succeeded. All alternative user verification
113 /// methods must be specified appropriately in the metadata in userVerificationDetails.
114 pub block_slowdown: Option<u16>,
115
116 /// ⚠️ WARNING - CONTENT AND USE OF THIS VALUE IS NOT DOCUMENTED BY FIDO
117 #[serde(rename = "iAPARThreshold")]
118 pub iapar_threshold: Option<serde_json::Value>,
119}
120
121impl Hash for BiometricAccuracyDescriptor {
122 fn hash<H: Hasher>(&self, state: &mut H) {
123 self.self_attested_frr
124 .map(|f| f.to_le_bytes())
125 .unwrap_or([0; 4])
126 .hash(state);
127 self.self_attested_far
128 .map(|f| f.to_le_bytes())
129 .unwrap_or([0; 4])
130 .hash(state);
131 self.max_templates.hash(state);
132 self.max_retries.hash(state);
133 self.block_slowdown.hash(state);
134 }
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
138#[serde(deny_unknown_fields, rename_all = "camelCase")]
139/// The PatternAccuracyDescriptor describes relevant accuracy/complexity aspects in the case that a
140/// pattern is used as the user verification method.
141pub struct PatternAccuracyDescriptor {
142 /// ❌ NOTE - The FIDO metadata values for this value are broken and can not be parsed.
143 ///
144 /// Number of possible patterns (having the minimum length) out of which exactly one would be
145 /// the right one, i.e. 1/probability in the case of equal distribution.
146 pub min_complexity: serde_json::Value,
147 /// Maximum number of false attempts before the authenticator will block authentication using
148 /// this method (at least temporarily). 0 means it will never block.
149 pub max_retries: Option<u16>,
150 /// Enforced minimum number of seconds wait time after blocking (due to forced reboot or similar
151 /// mechanism). 0 means this user verification method will be blocked, either permanently or
152 /// until an alternative user verification method method succeeded. All alternative user
153 /// verification methods must be specified appropriately in the metadata under
154 /// userVerificationDetails.
155 pub block_slowdown: Option<u16>,
156}
157
158impl Hash for PatternAccuracyDescriptor {
159 fn hash<H: Hasher>(&self, state: &mut H) {
160 self.max_retries
161 .map(|f| f.to_le_bytes())
162 .unwrap_or([0; 2])
163 .hash(state);
164 self.block_slowdown
165 .map(|f| f.to_le_bytes())
166 .unwrap_or([0; 2])
167 .hash(state);
168 }
169}
170
171/// User Verification Methods
172#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
173pub enum UserVerificationMethod {
174 /// None
175 #[serde(rename = "none")]
176 None,
177 /// All. MUST NOT APPEAR IN ANY UVM.
178 #[serde(rename = "all")]
179 All,
180 /// presence_internal
181 #[serde(rename = "presence_internal")]
182 PresenceInternal,
183 /// passcode_internal
184 #[serde(rename = "passcode_internal")]
185 PasscodeInternal,
186 /// passcode_external
187 #[serde(rename = "passcode_external")]
188 PasscodeExternal,
189 /// fingerprint_internal
190 #[serde(rename = "fingerprint_internal")]
191 FingerprintInternal,
192 /// handprint_internal
193 #[serde(rename = "handprint_internal")]
194 HandprintInternal,
195 /// eyeprint_internal
196 #[serde(rename = "eyeprint_internal")]
197 EyeprintInternal,
198 /// pattern_internal
199 #[serde(rename = "pattern_internal")]
200 PatternInternal,
201 /// voiceprint_internal
202 #[serde(rename = "voiceprint_internal")]
203 VoiceprintInternal,
204 /// location_internal
205 #[serde(rename = "location_internal")]
206 LocationInternal,
207 /// faceprint_internal
208 #[serde(rename = "faceprint_internal")]
209 FaceprintInternal,
210}
211
212#[derive(Debug, Clone, Serialize, Deserialize)]
213#[serde(deny_unknown_fields, rename_all = "camelCase")]
214/// A descriptor for a specific base user verification method as implemented by the authenticator.
215pub struct VerificationMethodAndCombinations {
216 /// a single USER_VERIFY constant case-sensitive string name. See section "User Verification
217 /// Methods" in FIDORegistry (e.g. "presence_internal"). This value MUST NOT be empty.
218 pub user_verification_method: UserVerificationMethod,
219 /// May optionally be used in the case of method USER_VERIFY_PASSCODE_INTERNAL or USER_VERIFY_PASSCODE_EXTERNAL.
220 pub ca_desc: Option<CodeAccuracyDescriptor>,
221 /// May optionally be used in the case of method USER_VERIFY_FINGERPRINT_INTERNAL,
222 /// USER_VERIFY_VOICEPRINT_INTERNAL, USER_VERIFY_FACEPRINT_INTERNAL,
223 /// USER_VERIFY_EYEPRINT_INTERNAL, or USER_VERIFY_HANDPRINT_INTERNAL.
224 pub ba_desc: Option<BiometricAccuracyDescriptor>,
225 /// May optionally be used in case of method USER_VERIFY_PATTERN_INTERNAL or USER_VERIFY_PATTERN_EXTERNAL
226 pub pa_desc: Option<PatternAccuracyDescriptor>,
227}
228
229#[derive(Debug, Clone, Serialize, Deserialize)]
230#[serde(deny_unknown_fields, rename_all = "camelCase")]
231/// In the case of ECDAA attestation, the ECDAA-Issuer's trust anchor must be specified in this field.
232pub struct EcdaaAnchor {
233 /// base64url encoding of the result of ECPoint2ToB of the ECPoint2 X = P_2^xX=P
234 /// See FIDOEcdaaAlgorithm for the definition of ECPoint2ToB.
235 #[serde(rename = "X")]
236 pub x: String,
237 /// base64url encoding of the result of ECPoint2ToB of the ECPoint2 Y = P_2^yY=P
238 /// See FIDOEcdaaAlgorithm for the definition of ECPoint2ToB.
239 #[serde(rename = "Y")]
240 pub y: String,
241 /// base64url encoding of the result of BigNumberToB(cc). See section "Issuer Specific ECDAA Parameters" in FIDOEcdaaAlgorithm for an explanation of cc. See FIDOEcdaaAlgorithm for the definition of BigNumberToB.
242 pub c: String,
243 /// base64url encoding of the result of BigNumberToB(sxsx). See section "Issuer Specific ECDAA Parameters" in FIDOEcdaaAlgorithm for an explanation of sxsx. See FIDOEcdaaAlgorithm for the definition of BigNumberToB.
244 pub sx: String,
245 /// base64url encoding of the result of BigNumberToB(sysy). See section "Issuer Specific ECDAA Parameters" in FIDOEcdaaAlgorithm for an explanation of sysy. See FIDOEcdaaAlgorithm for the definition of BigNumberToB.
246 pub sy: String,
247 /// Name of the Barreto-Naehrig elliptic curve for G1. "BN_P256", "BN_P638", "BN_ISOP256", and "BN_ISOP512" are supported. See section "Supported Curves for ECDAA" in FIDOEcdaaAlgorithm for details.
248 #[serde(rename = "G1Curve")]
249 pub g1curve: String,
250}
251
252#[derive(Debug, Clone, Serialize, Deserialize)]
253#[serde(deny_unknown_fields)]
254/// This descriptor contains an extension supported by the authenticator.
255pub struct ExtensionDescriptor {
256 /// Identifies the extension.
257 pub id: String,
258 /// The TAG of the extension if this was assigned. TAGs are assigned to extensions if they could appear in an assertion.
259 pub tag: Option<u16>,
260 /// Contains arbitrary data further describing the extension and/or data needed to correctly process the extension.
261 pub data: Option<String>,
262 /// Indicates whether unknown extensions must be ignored (false) or must lead to an error (true)
263 /// when the extension is to be processed by the FIDO Server, FIDO Client, ASM, or FIDO Authenticator.
264 ///
265 /// A value of false indicates that unknown extensions must be ignored
266 ///
267 /// A value of true indicates that unknown extensions must result in an error.
268 pub fail_if_unknown: bool,
269}
270
271/// The assertion scheme in use by this device.
272#[derive(Debug, Clone, Default, Serialize, Deserialize)]
273#[serde(deny_unknown_fields)]
274pub enum AssertionScheme {
275 /// No assertion scheme was provided
276 #[default]
277 Unknown,
278 /// Fido 2
279 #[serde(rename = "FIDOV2")]
280 FidoV2,
281}
282
283/// The family of protocols this device belongs to.
284#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
285#[serde(deny_unknown_fields)]
286pub enum ProtocolFamily {
287 /// No protocol family was provided
288 #[default]
289 Unknown,
290 /// Uaf
291 #[serde(rename = "uaf")]
292 Uaf,
293 /// Universal Second Factor
294 #[serde(rename = "u2f")]
295 U2f,
296 /// Fido 2. This is the preferred type
297 #[serde(rename = "fido2")]
298 Fido2,
299}
300
301#[derive(Debug, Clone, Serialize, Deserialize)]
302#[serde(deny_unknown_fields)]
303/// The list of authentication algorithms supported by the authenticator.
304pub enum AuthenticationAlgorithm {
305 /// secp256r1_ecdsa_sha256_raw
306 #[serde(rename = "secp256r1_ecdsa_sha256_raw")]
307 Secp256r1EcdsaSha256Raw,
308 /// secp256r1_ecdsa_sha256_der
309 #[serde(rename = "secp256r1_ecdsa_sha256_der")]
310 Secp256r1EcdsaSha256Der,
311 /// secp256k1_ecdsa_sha256_raw
312 #[serde(rename = "secp256k1_ecdsa_sha256_raw")]
313 Secp256K1EcdsaSha256Raw,
314 /// rsa_emsa_pkcs1_sha256_raw
315 #[serde(rename = "rsa_emsa_pkcs1_sha256_raw")]
316 RsaEmsaPkcs1Sha256Raw,
317 /// ed25519_eddsa_sha512_raw
318 #[serde(rename = "ed25519_eddsa_sha512_raw")]
319 Ed25519EddsaSha512Raw,
320 /// secp384r1_ecdsa_sha384_raw
321 #[serde(rename = "secp384r1_ecdsa_sha384_raw")]
322 Secp384r1EcdsaSha384Raw,
323 /// secp521r1_ecdsa_sha512_raw
324 #[serde(rename = "secp521r1_ecdsa_sha512_raw")]
325 Secp521r1EcdsaSha512Raw,
326 /// rsassa_pkcsv15_sha256_raw
327 #[serde(rename = "rsassa_pkcsv15_sha256_raw")]
328 RsassaPkcsv15Sha256Raw,
329 /// rsassa_pkcsv15_sha1_raw
330 #[serde(rename = "rsassa_pkcsv15_sha1_raw")]
331 RsassaPkcsv15Sha1Raw,
332 /// rsassa_pss_sha256_raw
333 #[serde(rename = "rsassa_pss_sha256_raw")]
334 RsassaPssSha256Raw,
335}
336
337impl fmt::Display for AuthenticationAlgorithm {
338 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
339 match self {
340 AuthenticationAlgorithm::Secp256r1EcdsaSha256Raw => {
341 write!(f, "secp256r1_ecdsa_sha256_raw")
342 }
343 AuthenticationAlgorithm::Secp256r1EcdsaSha256Der => {
344 write!(f, "secp256r1_ecdsa_sha256_der")
345 }
346 AuthenticationAlgorithm::Secp256K1EcdsaSha256Raw => {
347 write!(f, "secp256k1_ecdsa_sha256_raw")
348 }
349 AuthenticationAlgorithm::RsaEmsaPkcs1Sha256Raw => {
350 write!(f, "rsa_emsa_pkcs1_sha256_raw")
351 }
352 AuthenticationAlgorithm::Ed25519EddsaSha512Raw => write!(f, "ed25519_eddsa_sha512_raw"),
353 AuthenticationAlgorithm::Secp384r1EcdsaSha384Raw => {
354 write!(f, "secp384r1_ecdsa_sha384_raw")
355 }
356 AuthenticationAlgorithm::Secp521r1EcdsaSha512Raw => {
357 write!(f, "secp521r1_ecdsa_sha512_raw")
358 }
359 AuthenticationAlgorithm::RsassaPkcsv15Sha256Raw => {
360 write!(f, "rsassa_pkcsv15_sha256_raw")
361 }
362 AuthenticationAlgorithm::RsassaPkcsv15Sha1Raw => {
363 write!(f, "rsassa_pkcsv15_sha1_raw")
364 }
365 AuthenticationAlgorithm::RsassaPssSha256Raw => {
366 write!(f, "rsassa_pss_sha256_raw")
367 }
368 }
369 }
370}
371
372#[derive(Debug, Clone, Serialize, Deserialize)]
373#[serde(deny_unknown_fields)]
374/// The public key format used by the authenticator during registration operations.
375pub enum PublicKeyAlg {
376 /// ecc_x962_raw
377 #[serde(rename = "ecc_x962_raw")]
378 EccX962Raw,
379 /// ecc_x962_der
380 #[serde(rename = "ecc_x962_der")]
381 EccX962Der,
382 /// rsa_2048_raw
383 #[serde(rename = "rsa_2048_raw")]
384 Rsa2048Raw,
385 /// cose
386 #[serde(rename = "cose")]
387 Cose,
388}
389
390#[derive(Debug, Clone, Serialize, Deserialize)]
391#[serde(deny_unknown_fields)]
392/// A type of attestation
393pub enum AttestationType {
394 /// basic_full
395 #[serde(rename = "basic_full")]
396 BasicFull,
397 /// basic_surrogate
398 #[serde(rename = "basic_surrogate")]
399 BasicSurrogate,
400 /// attca
401 #[serde(rename = "attca")]
402 AttCa,
403}
404
405#[derive(Debug, Clone, Serialize, Deserialize)]
406#[serde(deny_unknown_fields)]
407/// The class of key protection.
408pub enum KeyProtection {
409 /// The key is stored in hardware. This is exclusive to `software`
410 #[serde(rename = "hardware")]
411 Hardware,
412 /// Secure Element
413 #[serde(rename = "secure_element")]
414 SecureElement,
415 /// The private key is stored in a key-wrapped-key. This can still be "hardware" backed
416 /// where the KWK can only be decrypted by a specific device's hardware.
417 #[serde(rename = "remote_handle")]
418 RemoteHandle,
419 /// Trusted Execution Environment.
420 #[serde(rename = "tee")]
421 Tee,
422 /// The key is stored in software. This is exclusive to `hardware`
423 #[serde(rename = "software")]
424 Software,
425}
426
427/// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
428///
429#[derive(Debug, Clone, Serialize, Deserialize)]
430#[serde(deny_unknown_fields)]
431pub enum MatcherProtection {
432 /// on_chip
433 #[serde(rename = "on_chip")]
434 OnChip,
435 /// tee
436 #[serde(rename = "tee")]
437 Tee,
438 /// software
439 #[serde(rename = "software")]
440 Software,
441}
442
443/// Attachment hint
444#[derive(Debug, Clone, Serialize, Deserialize)]
445#[serde(deny_unknown_fields)]
446pub enum AttachmentHint {
447 /// external
448 #[serde(rename = "external")]
449 External,
450 /// wired
451 #[serde(rename = "wired")]
452 Wired,
453 /// wireless
454 #[serde(rename = "wireless")]
455 Wireless,
456 /// nfc
457 #[serde(rename = "nfc")]
458 Nfc,
459 /// internal
460 #[serde(rename = "internal")]
461 Internal,
462 /// bluetooth
463 #[serde(rename = "bluetooth")]
464 Bluetooth,
465 /// network
466 #[serde(rename = "network")]
467 Network,
468 /// wifi-direct
469 #[serde(rename = "wifi_direct")]
470 WifiDirect,
471}
472
473/// The authenticator versions this device supports
474#[derive(Debug, Clone, Serialize, Deserialize)]
475pub enum AuthenticatorVersion {
476 /// U2F
477 #[serde(rename = "U2F_V2")]
478 U2fV2,
479 /// FIDO 2.0
480 #[serde(rename = "FIDO_2_0")]
481 Fido2_0,
482 /// FIDO 2.1 PRE
483 #[serde(rename = "FIDO_2_1_PRE")]
484 Fido2_1Pre,
485 /// FIDO 2.1
486 #[serde(rename = "FIDO_2_1")]
487 Fido2_1,
488}
489
490impl fmt::Display for AuthenticatorVersion {
491 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
492 match self {
493 AuthenticatorVersion::U2fV2 => write!(f, "U2F V2"),
494 AuthenticatorVersion::Fido2_0 => write!(f, "FIDO 2.0"),
495 AuthenticatorVersion::Fido2_1Pre => write!(f, "FIDO 2.1 PRE"),
496 AuthenticatorVersion::Fido2_1 => write!(f, "FIDO 2.1"),
497 }
498 }
499}
500
501/// The authenticator transports that this device supports
502#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
503pub enum AuthenticatorTransport {
504 /// usb
505 #[serde(rename = "usb")]
506 Usb,
507 /// nfc
508 #[serde(rename = "nfc")]
509 Nfc,
510 /// lightning
511 #[serde(rename = "lightning")]
512 Lightning,
513 /// ble
514 #[serde(rename = "ble")]
515 Ble,
516 /// internal
517 #[serde(rename = "internal")]
518 Internal,
519 /// wireless
520 #[serde(rename = "wireless")]
521 Wireless,
522 /// hybrid (formerly caBLE)
523 #[serde(rename = "hybrid")]
524 Hybrid,
525}
526
527impl fmt::Display for AuthenticatorTransport {
528 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
529 match self {
530 AuthenticatorTransport::Usb => write!(f, "usb"),
531 AuthenticatorTransport::Nfc => write!(f, "nfc"),
532 AuthenticatorTransport::Lightning => write!(f, "lightning"),
533 AuthenticatorTransport::Ble => write!(f, "ble"),
534 AuthenticatorTransport::Internal => write!(f, "internal"),
535 AuthenticatorTransport::Wireless => write!(f, "wireless"),
536 AuthenticatorTransport::Hybrid => write!(f, "hybrid (caBLE)"),
537 }
538 }
539}
540
541impl FromStr for AuthenticatorTransport {
542 type Err = ();
543
544 fn from_str(s: &str) -> Result<Self, Self::Err> {
545 match s {
546 "usb" => Ok(AuthenticatorTransport::Usb),
547 "nfc" => Ok(AuthenticatorTransport::Nfc),
548 "lightning" => Ok(AuthenticatorTransport::Lightning),
549 "ble" => Ok(AuthenticatorTransport::Ble),
550 "internal" => Ok(AuthenticatorTransport::Internal),
551 "wireless" => Ok(AuthenticatorTransport::Wireless),
552 _ => Err(()),
553 }
554 }
555}
556
557/// Describes this device's capability to allow credentials to be
558/// accessible to a single device, or multiple devices.
559#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
560#[serde(rename_all = "lowercase")]
561pub enum MultiDeviceCredentialSupport {
562 /// Multiple devices are not supported, this credential is bound to one
563 /// device.
564 #[default]
565 Unsupported,
566 /// The authenticator will provide its multiple device support during
567 /// registration through setting the flag "backup eligible".
568 Explicit,
569 /// This authenticator always is multi device
570 Implicit,
571}
572
573impl fmt::Display for MultiDeviceCredentialSupport {
574 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
575 match self {
576 Self::Unsupported => write!(f, "unsupported (no)"),
577 Self::Explicit => write!(f, "explicit (see backup_eligible flag)"),
578 Self::Implicit => write!(f, "implicit (yes)"),
579 }
580 }
581}
582
583/// The output of authenticatorGetInfo. Some fields are hidden as they are duplicated
584/// in the metadata statement.
585#[derive(Debug, Clone, Serialize, Deserialize)]
586#[serde(deny_unknown_fields, rename_all = "camelCase")]
587pub struct AuthenticatorGetInfo {
588 /// The list of supported CTAP versions
589 pub versions: Vec<AuthenticatorVersion>,
590 /// The list of supported extension identifiers.
591 #[serde(default)]
592 pub extensions: Vec<String>,
593 /// The AAGUID (UUID) of this device
594 pub aaguid: Uuid,
595 /// List of supported Options
596 #[serde(default)]
597 pub options: BTreeMap<String, bool>,
598 /// The largest ctap message size this device supports
599 pub max_msg_size: Option<u32>,
600 /// The list of PIN UV auth protocols
601 #[serde(default)]
602 pub pin_uv_auth_protocols: Vec<u32>,
603 /// The maximum number of credentials ID's that can be listed and provided to this device.
604 pub max_credential_count_in_list: Option<u32>,
605 /// The maximum length of a credential ID that can be provided to this device.
606 pub max_credential_id_length: Option<u32>,
607 /// The list of transports this device supports
608 #[serde(default)]
609 pub transports: Vec<AuthenticatorTransport>,
610 #[serde(default)]
611 pub(crate) algorithms: Vec<serde_json::Value>,
612 /// The maximum size of large blob array this device can store, if the extension is supported.
613 pub max_serialized_large_blob_array: Option<u32>,
614 #[serde(rename = "forcePINChange")]
615 force_pin_change: Option<bool>,
616 /// The minimum pin length that this device requires.
617 #[serde(rename = "minPINLength")]
618 pub min_pin_length: Option<u32>,
619 firmware_version: Option<u32>,
620 /// The maximum size of the credBlob if supported
621 pub max_cred_blob_length: Option<u32>,
622 /// The maximum number of discoverable (resident) keys this device supports.
623 #[serde(rename = "maxRPIDsForSetMinPINLength")]
624 pub max_rpids_for_set_min_pin_length: Option<u32>,
625 /// _
626 pub preferred_platform_uv_attempts: Option<u32>,
627 uv_modality: Option<u32>,
628 #[serde(default)]
629 pub certifications: BTreeMap<String, u32>,
630 /// The number of remaining resident keys on this device.
631 pub remaining_discoverable_credentials: Option<u32>,
632 /// Vendor specific details
633 #[serde(default)]
634 pub vendor_prototype_config_commands: Vec<u32>,
635}
636
637#[derive(Debug, Clone, Serialize, Deserialize)]
638#[serde(deny_unknown_fields, rename_all = "camelCase")]
639/// A statement describing a device and it's associated properties.
640pub struct MetadataStatement {
641 /// Legal Header
642 pub legal_header: Option<String>,
643 /// The Authenticator Attestation ID. See UAFProtocol for the definition of the AAID structure.
644 /// This field must be set if the authenticator implements FIDO UAF.
645 pub aaid: Option<String>,
646 /// The Authenticator Attestation GUID. See FIDOKeyAttestation for the definition of the
647 /// AAGUID structure. This field must be set if the authenticator implements FIDO 2.
648 pub aaguid: Option<Uuid>,
649 /// A list of the attestation certificate public key identifiers encoded as hex string. This
650 /// value must be calculated according to method 1 for computing the keyIdentifier as defined
651 /// in RFC5280 section 4.2.1.2. The hex string must not contain any non-hex characters
652 /// (e.g. spaces). All hex letters must be lower case. This field must be set if neither aaid
653 /// nor aaguid are set. Setting this field implies that the attestation certificate(s) are
654 /// dedicated to a single authenticator model.
655 ///
656 /// All attestationCertificateKeyIdentifier values should be unique within the scope of the Metadata Service.
657 pub attestation_certificate_key_identifiers: Option<Vec<String>>,
658 /// A human-readable, short description of the authenticator, in English.
659 pub description: String,
660 /// A list of human-readable short descriptions of the authenticator in different languages.
661 #[serde(default)]
662 pub alternative_descriptions: BTreeMap<String, String>,
663 /// Earliest (i.e. lowest) trustworthy authenticatorVersion meeting the requirements specified
664 /// in this metadata statement.
665 ///
666 /// Adding new StatusReport entries with status UPDATE_AVAILABLE to the metadata TOC object
667 /// FIDOMetadataService must also change this authenticatorVersion if the update fixes severe
668 /// security issues, e.g. the ones reported by preceding StatusReport entries with status code
669 /// USER_VERIFICATION_BYPASS, ATTESTATION_KEY_COMPROMISE, USER_KEY_REMOTE_COMPROMISE, USER_KEY_PHYSICAL_COMPROMISE, REVOKED.
670 ///
671 /// It is recommended to assume increased risk if this version is higher (newer) than the
672 /// firmware version present in an authenticator. For example, if a StatusReport entry with
673 /// status USER_VERIFICATION_BYPASS or USER_KEY_REMOTE_COMPROMISE precedes the UPDATE_AVAILABLE
674 /// entry, than any firmware version lower (older) than the one specified in the metadata statement
675 /// is assumed to be vulnerable.
676 pub authenticator_version: u32,
677 /// The FIDO protocol family. The values "uaf", "u2f", and "fido2" are supported. If this field
678 /// is missing, the assumed protocol family is "uaf". Metadata Statements for U2F authenticators
679 /// must set the value of protocolFamily to "u2f" and FIDO 2.0/WebAuthentication Authenticator
680 /// implementations must set the value of protocolFamily to "fido2".
681 ///
682 /// ❗️ This is represented as an enum in this project to help you understand the possible values
683 /// that *may* exist. This contradicts the MDS spec, but it's better for you the consumer.
684 #[serde(default)]
685 pub protocol_family: ProtocolFamily,
686 /// Version of this structure
687 pub schema: u16,
688 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
689 ///
690 /// The FIDO unified protocol version(s) (related to the specific protocol family) supported by
691 /// this authenticator. See UAFProtocol for the definition of the Version structure.
692 pub upv: Vec<Upv>,
693 /// The list of authentication algorithms supported by the authenticator. Must be set to the
694 /// complete list of the supported ALG_ constants defined in the FIDO Registry of Predefined
695 /// Values FIDORegistry if the authenticator supports multiple algorithms. Each value must be non-zero.
696 ///
697 /// ❗️ This is represented as an enum in this project to help you understand the possible values
698 /// that *may* exist. This contradicts the MDS spec, but it's better for you the consumer.
699 #[serde(default)]
700 pub authentication_algorithms: Vec<AuthenticationAlgorithm>,
701 /// The list of public key formats supported by the authenticator during registration operations.
702 /// Must be set to the complete list of the supported ALG_KEY constants defined in the FIDO Registry
703 /// of Predefined Values FIDORegistry if the authenticator model supports multiple encodings.
704 /// Because this information is not present in APIs related to authenticator discovery or policy,
705 /// a FIDO server must be prepared to accept and process any and all key representations defined
706 /// for any public key algorithm it supports. Each value must be non-zero.
707 ///
708 /// ❗️ This is represented as an enum in this project to help you understand the possible values
709 /// that *may* exist. This contradicts the MDS spec, but it's better for you the consumer.
710 #[serde(default)]
711 pub public_key_alg_and_encodings: Vec<PublicKeyAlg>,
712 /// The supported attestation type(s). (e.g. TAG_ATTESTATION_BASIC_FULL(0x3E07), TAG_ATTESTATION_BASIC_SURROGATE(0x3E08)).
713 ///
714 /// ❗️ This is represented as an enum in this project to help you understand the possible values
715 /// that *may* exist. This contradicts the MDS spec, but it's better for you the consumer.
716 pub attestation_types: Vec<AttestationType>,
717 /// A list of alternative VerificationMethodANDCombinations.
718 ///
719 /// userVerificationDetails is a two dimensional array, that informs RP what
720 /// VerificationMethodANDCombinations user may be required to perform in order to pass user
721 /// verification, e.g User need to pass fingerprint, or faceprint, or password and palm print, etc.
722 ///
723 /// The outer array is an OR over the values, and the inner arrays are ANDs. For example:
724 ///
725 ///
726 /// [
727 /// [
728 /// { user_verification_method: ... }
729 /// ],
730 /// // OR
731 /// [
732 /// { user_verification_method: ... },
733 /// // AND
734 /// { user_verification_method: ... }
735 /// ],
736 /// ]
737 ///
738 pub user_verification_details: Vec<Vec<VerificationMethodAndCombinations>>,
739 /// The list of key protection types supported by the authenticator. Must be set to the complete
740 /// list of the supported KEY_PROTECTION_ constant case-sensitive string names.
741 ///
742 /// ❗️ This is represented as an enum in this project to help you understand the possible values
743 /// that *may* exist. This contradicts the MDS spec, but it's better for you the consumer.
744 pub key_protection: Vec<KeyProtection>,
745 /// This entry is set to true, if the Uauth private key is restricted by the authenticator to
746 /// only sign valid FIDO signature assertions.
747 ///
748 /// This entry is set to false, if the authenticator doesn't restrict the Uauth key to only
749 /// sign valid FIDO signature assertions. In this case, the calling application could potentially
750 /// get any hash value signed by the authenticator.
751 ///
752 /// If this field is missing, the assumed value is isKeyRestricted=true
753 #[serde(default = "assume_true")]
754 pub is_key_restricted: bool,
755 /// This entry is set to true, if Uauth key usage always requires a fresh user verification.
756 ///
757 /// If this field is missing, the assumed value is isFreshUserVerificationRequired=true.
758 ///
759 /// This entry is set to false, if the Uauth key can be used without requiring a fresh user
760 /// verification, e.g. without any additional user interaction, if the user was verified a
761 /// (potentially configurable) caching time ago.
762 ///
763 /// In the case of isFreshUserVerificationRequired=false, the FIDO server must verify the
764 /// registration response and/or authentication response and verify that the (maximum) caching
765 /// time (sometimes also called "authTimeout") is acceptable.
766 ///
767 /// This entry solely refers to the user verification. In the case of transaction confirmation,
768 /// the authenticator must always ask the user to authorize the specific transaction.
769 #[serde(default = "assume_true")]
770 pub is_fresh_user_verification_required: bool,
771 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
772 ///
773 /// ❗️ This is represented as an enum in this project to help you understand the possible values
774 /// that *may* exist. This contradicts the MDS spec, but it's better for you the consumer.
775 pub matcher_protection: Vec<MatcherProtection>,
776 /// The authenticator's overall claimed cryptographic strength in bits (sometimes also called
777 /// security strength or security level). This is the minimum of the cryptographic strength of
778 /// all involved cryptographic methods (e.g. RNG, underlying hash, key wrapping algorithm,
779 /// signing algorithm, attestation algorithm), e.g. see FIPS180-4, FIPS186-4, FIPS198-1,
780 /// SP800-38B, SP800-38C, SP800-38D, SP800-38F, SP800-90C, SP800-90ar1, FIPS140-2 etc.
781 ///
782 /// If this value is absent, the cryptographic strength is unknown. If the cryptographic strength
783 /// of one of the involved cryptographic methods is unknown the overall claimed cryptographic
784 /// strength is also unknown.
785 pub crypto_strength: Option<u16>,
786 /// 🤔 Authors Note: Generally attachment hint is a very problematic thing to provide to browsers
787 /// as they are not always used or expected in work flows. It's likely this field is "useless"
788 /// as a result.
789 ///
790 /// A list of attachment hints that MAY be used with this device.
791 ///
792 /// ❗️ This is represented as an enum in this project to help you understand the possible values
793 /// that *may* exist. This contradicts the MDS spec, but it's better for you the consumer.
794 pub attachment_hint: Vec<AttachmentHint>,
795 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
796 ///
797 /// A 16-bit number representing a combination of the bit flags defined by the
798 /// TRANSACTION_CONFIRMATION_DISPLAY constants in the FIDO Registry of Predefined Values FIDORegistry.
799 /// This value must be 0, if transaction confirmation is not supported by the authenticator.
800 pub tc_display: Vec<String>,
801 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
802 ///
803 pub tc_display_content_type: Option<String>,
804 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
805 ///
806 #[serde(rename = "tcDisplayPNGCharacteristics")]
807 pub tc_display_png_characteristics: Option<serde_json::Value>,
808 /// ❌ NOTE - The FIDO metadata specification defines this as a an array of base64 values, however
809 /// many values are INVALID and contain leading/trailing whitespace that MAY confuse your base64 parser
810 ///
811 /// ⚠️ WARNING - Content of this value MAY have extra leading or trailing whitespace which MAY
812 /// cause issues when parsing.
813 ///
814 /// Each element of this array represents a PKIX RFC5280 X.509 certificate that is a valid
815 /// trust anchor for this authenticator model. Multiple certificates might be used for different
816 /// batches of the same model. The array does not represent a certificate chain, but only the
817 /// trust anchor of that chain. A trust anchor can be a root certificate, an intermediate CA
818 /// certificate or even the attestation certificate itself.
819 ///
820 /// Each array element is a base64-encoded (section 4 of RFC4648), DER-encoded ITU-X690-2008
821 /// PKIX certificate value. Each element must be dedicated for authenticator attestation.
822 ///
823 // /// ❗️ This is decoded from Base64 for you so that you can directly access the DER of the certificate.
824 // attestation_root_certificates: Vec<Base64UrlSafeData>,
825 pub attestation_root_certificates: Vec<String>,
826 /// A list of trust anchors used for ECDAA attestation. This entry must be present if and only
827 /// if attestationType includes TAG_ATTESTATION_ECDAA. The entries in attestationRootCertificates
828 /// have no relevance for ECDAA attestation. Each ecdaaTrustAnchor must be dedicated to a single
829 /// authenticator model (e.g as identified by its AAID/AAGUID).
830 #[serde(default)]
831 pub ecdaa_trust_anchors: Vec<EcdaaAnchor>,
832 /// An icon representing this device.
833 pub icon: Option<serde_json::Value>,
834 /// The list of supported extensions of this authenticator
835 #[serde(default)]
836 pub supported_extensions: Vec<ExtensionDescriptor>,
837 /// Describes supported versions, extensions, AAGUID of the device and its capabilities.
838 ///
839 /// The information is the same reported by an authenticator when invoking the 'authenticatorGetInfo'
840 /// method, see FIDOCTAP.
841 pub authenticator_get_info: Option<AuthenticatorGetInfo>,
842
843 #[serde(default)]
844 /// Defines if credentials in this authenticator can be accessed on multiple
845 /// devices. If set to `unsupported` this means that it is a single device
846 /// credential.
847 pub multi_device_credential_support: MultiDeviceCredentialSupport,
848}
849
850#[derive(Debug, Clone, Default, Serialize, Deserialize)]
851#[serde(rename_all = "camelCase")]
852/// See `BiometricsStatusReport`
853pub enum BiometricModality {
854 /// No valid biometric modality was provided.
855 #[default]
856 Unknown,
857}
858
859#[derive(Debug, Clone, Serialize, Deserialize)]
860#[serde(deny_unknown_fields, rename_all = "camelCase")]
861/// A status report for the device if it provides biometrics
862pub struct BiometricsStatusReport {
863 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
864 ///
865 /// Achieved level of the biometric certification of this biometric component of the authenticator
866 pub cert_level: u16,
867 /// A single a single USER_VERIFY short form case-sensitive string name constant, representing
868 /// biometric modality. See section "User Verification Methods" in FIDORegistry
869 /// (e.g. "fingerprint_internal").
870 ///
871 /// ❗️ This is represented as an enum in this project to help you understand the possible values
872 /// that *may* exist. This contradicts the MDS spec, but it's better for you the consumer.
873 #[serde(default)]
874 pub modality: BiometricModality,
875 /// ISO-8601 formatted date since when the certLevel achieved, if applicable. If no date is
876 /// given, the status is assumed to be effective while present.
877 pub effective_date: Option<String>,
878 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
879 ///
880 /// Describes the externally visible aspects of the Biometric Certification evaluation.
881 ///
882 /// For example, if it states "on chip" this means the biometrics are kept inside the device only
883 pub certification_descriptor: Option<String>,
884 /// The unique identifier for the issued Biometric Certification.
885 pub certificate_number: Option<String>,
886 /// The version of the Biometric Certification Policy the implementation is Certified to, e.g. "1.0.0".
887 pub certification_policy_version: Option<String>,
888 /// The version of the Biometric Requirements FIDOBiometricsRequirements the implementation is certified to, e.g. "1.0.0".
889 pub certification_requirements_version: Option<String>,
890}
891
892/// The fido certification status of the device associated to this aaid/aaguid.
893#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
894pub enum AuthenticatorStatus {
895 /// The device is NOT fido certified
896 #[serde(rename = "NOT_FIDO_CERTIFIED")]
897 NotFidoCertified,
898 /// The divec is fido certified. This will be phased out in favour of the FIDO_CERTIFIED_L1
899 /// field.
900 #[serde(rename = "FIDO_CERTIFIED")]
901 FidoCertified,
902 /// Indicates that malware is able to bypass the user verification. This means that the
903 /// authenticator could be used without the user’s consent and potentially even without the
904 /// user’s knowledge.
905 #[serde(rename = "USER_VERIFICATION_BYPASS")]
906 UserVerificationBypass,
907 /// Indicates that an attestation key for this authenticator is known to be compromised.
908 /// The relying party SHOULD check the certificate field and use it to identify the compromised
909 /// authenticator batch. If the certificate field is not set, the relying party should reject
910 /// all new registrations of the compromised authenticator. The Authenticator manufacturer
911 /// should set the date to the date when compromise has occurred.
912 #[serde(rename = "ATTESTATION_KEY_COMPROMISE")]
913 AttestationKeyCompromise,
914 /// This authenticator has identified weaknesses that allow registered keys to be compromised
915 /// and should not be trusted. This would include both, e.g. weak entropy that causes
916 /// predictable keys to be generated or side channels that allow keys or signatures to be
917 /// forged, guessed or extracted.
918 #[serde(rename = "USER_KEY_REMOTE_COMPROMISE")]
919 UserKeyRemoteCompromise,
920 /// This authenticator has known weaknesses in its key protection mechanism(s) that allow user
921 /// keys to be extracted by an adversary in physical possession of the device.
922 #[serde(rename = "USER_KEY_PHYSICAL_COMPROMISE")]
923 UserKeyPhysicalCompromise,
924 /// A software or firmware update is available for the device. The Authenticator manufacturer
925 /// should set the url to the URL where users can obtain an update and the date the update was
926 /// published. When this status code is used, then the field authenticatorVersion in the
927 /// authenticator Metadata Statement FIDOMetadataStatement MUST be updated, if the update fixes
928 /// severe security issues, e.g. the ones reported by preceding StatusReport entries with status
929 /// code USER_VERIFICATION_BYPASS, ATTESTATION_KEY_COMPROMISE, USER_KEY_REMOTE_COMPROMISE,
930 /// USER_KEY_PHYSICAL_COMPROMISE, REVOKED. The Relying party MUST reject the Metadata Statement
931 /// if the authenticatorVersion has not increased
932 #[serde(rename = "UPDATE_AVAILABLE")]
933 UpdateAvailable,
934 /// The FIDO Alliance has determined that this authenticator should not be trusted for any
935 /// reason. For example if it is known to be a fraudulent product or contain a deliberate
936 /// backdoor. Relying parties SHOULD reject any future registration of this authenticator model.
937 #[serde(rename = "REVOKED")]
938 Revoked,
939 /// The authenticator vendor has completed and submitted the self-certification checklist to
940 /// the FIDO Alliance. If this completed checklist is publicly available, the URL will be
941 /// specified in url.
942 #[serde(rename = "SELF_ASSERTION_SUBMITTED")]
943 SelfAssertionSubmitted,
944 /// This device is certified at level 1
945 #[serde(rename = "FIDO_CERTIFIED_L1")]
946 FidoCertifiedL1,
947 /// This device is certified at level 1 plus
948 #[serde(rename = "FIDO_CERTIFIED_L1plus")]
949 FidoCertifiedL1Plus,
950 /// This device is certified at level 2
951 #[serde(rename = "FIDO_CERTIFIED_L2")]
952 FidoCertifiedL2,
953 /// This device is certified at level 2 plus
954 #[serde(rename = "FIDO_CERTIFIED_L2plus")]
955 FidoCertifiedL2Plus,
956 /// This device is certified at level 3
957 #[serde(rename = "FIDO_CERTIFIED_L3")]
958 FidoCertifiedL3,
959 /// This device is certified at level 3 plus
960 #[serde(rename = "FIDO_CERTIFIED_L3plus")]
961 FidoCertifiedL3Plus,
962}
963
964impl FromStr for AuthenticatorStatus {
965 type Err = ();
966
967 fn from_str(s: &str) -> Result<Self, Self::Err> {
968 match s.to_lowercase().as_str() {
969 "not-certified" => Ok(AuthenticatorStatus::NotFidoCertified),
970 "uv-bypass" => Ok(AuthenticatorStatus::UserVerificationBypass),
971 "key-compromise" => Ok(AuthenticatorStatus::AttestationKeyCompromise),
972 "remote-exploit" => Ok(AuthenticatorStatus::UserKeyRemoteCompromise),
973 "physical-compromise" => Ok(AuthenticatorStatus::UserKeyPhysicalCompromise),
974 "update-available" => Ok(AuthenticatorStatus::UpdateAvailable),
975 "revoked" => Ok(AuthenticatorStatus::Revoked),
976 "self-asserted" => Ok(AuthenticatorStatus::SelfAssertionSubmitted),
977 "valid" | "l1" => Ok(AuthenticatorStatus::FidoCertifiedL1),
978 "l1+" => Ok(AuthenticatorStatus::FidoCertifiedL1Plus),
979 "l2" => Ok(AuthenticatorStatus::FidoCertifiedL2),
980 "l2+" => Ok(AuthenticatorStatus::FidoCertifiedL2Plus),
981 "l3" => Ok(AuthenticatorStatus::FidoCertifiedL3),
982 "l3+" => Ok(AuthenticatorStatus::FidoCertifiedL3Plus),
983 _ => Err(()),
984 }
985 }
986}
987
988impl AuthenticatorStatus {
989 pub(crate) fn numeric(&self) -> u8 {
990 match self {
991 AuthenticatorStatus::NotFidoCertified
992 | AuthenticatorStatus::UserVerificationBypass
993 | AuthenticatorStatus::AttestationKeyCompromise
994 | AuthenticatorStatus::UserKeyRemoteCompromise
995 | AuthenticatorStatus::UserKeyPhysicalCompromise
996 | AuthenticatorStatus::UpdateAvailable
997 | AuthenticatorStatus::Revoked
998 | AuthenticatorStatus::SelfAssertionSubmitted => 0,
999 AuthenticatorStatus::FidoCertified | AuthenticatorStatus::FidoCertifiedL1 => 10,
1000 AuthenticatorStatus::FidoCertifiedL1Plus => 11,
1001 AuthenticatorStatus::FidoCertifiedL2 => 20,
1002 AuthenticatorStatus::FidoCertifiedL2Plus => 21,
1003 AuthenticatorStatus::FidoCertifiedL3 => 30,
1004 AuthenticatorStatus::FidoCertifiedL3Plus => 31,
1005 }
1006 }
1007}
1008
1009#[derive(Debug, Clone, Serialize, Deserialize)]
1010#[serde(deny_unknown_fields, rename_all = "camelCase")]
1011/// Contains an AuthenticatorStatus and additional data associated with it, if any.
1012///
1013/// The latest StatusReport entry MUST reflect the "current" status. For example, if the latest
1014/// entry has status USER_VERIFICATION_BYPASS, then it is recommended assuming an increased risk
1015/// associated with all authenticators of this AAID; if the latest entry has status UPDATE_AVAILABLE,
1016/// then the update is intended to address at least all previous issues reported in this StatusReport
1017/// dictionary.
1018pub struct StatusReport {
1019 /// The status of the authenticator.
1020 pub status: AuthenticatorStatus,
1021 /// ISO-8601 formatted date since when the status code was set, if applicable. If no date is
1022 /// given, the status is assumed to be effective while present.
1023 pub effective_date: Option<String>,
1024 /// The authenticatorVersion that this status report relates to. In the case of FIDO_CERTIFIED*
1025 /// status values, the status applies to higher authenticatorVersions until there is a new statusReport.
1026 pub authenticator_version: Option<u32>,
1027 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
1028 ///
1029 /// Base64-encoded RFC4648 (not base64url!) DER ITU-X690-2008 PKIX certificate value related
1030 /// to the current status, if applicable.
1031 pub certificate: Option<String>,
1032 /// HTTPS URL where additional information may be found related to the current status, if applicable.
1033 pub url: Option<String>,
1034 /// Describes the externally visible aspects of the Authenticator Certification evaluation.
1035 ///
1036 /// For example it could state that the authenticator is a "SecurityKey based on a CC EAL 5
1037 /// certified chip hardware".
1038 pub certification_descriptor: Option<String>,
1039 /// The unique identifier for the issued Certification.
1040 pub certificate_number: Option<String>,
1041 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
1042 ///
1043 /// The version of the Authenticator Certification Policy the implementation is Certified to, e.g. "1.0.0".
1044 pub certification_policy_version: Option<String>,
1045 /// The Document Version of the Authenticator Security Requirements (DV)
1046 /// FIDOAuthenticatorSecurityRequirements the implementation is certified to, e.g. "1.2.0".
1047 pub certification_requirements_version: Option<String>,
1048
1049 /// ⚠️ WARNING - CONTENT AND USE OF THIS VALUE IS NOT DOCUMENTED BY FIDO
1050 certification_profiles: Option<serde_json::Value>,
1051}
1052
1053#[derive(Debug, Clone, Serialize, Deserialize)]
1054#[serde(deny_unknown_fields, rename_all = "camelCase")]
1055/// A statement describing a device and it's associated properties.
1056pub struct FidoDevice {
1057 /// If this device is identified by an aaid, it will be listed here.
1058 pub aaid: Option<String>,
1059 /// Alternately, if the device is identified by an AAGUID it will be set here. Generally all
1060 /// FIDO2 devices will use aaguid.
1061 pub aaguid: Option<Uuid>,
1062 /// A list of the attestation certificate public key identifiers encoded as hex string. This
1063 /// value MUST be calculated according to method 1 for computing the keyIdentifier as defined
1064 /// in RFC5280 section 4.2.1.2.
1065 pub attestation_certificate_key_identifiers: Option<Vec<String>>,
1066 /// The FIDOMetadataStatement pertaining to this device.
1067 pub metadata_statement: MetadataStatement,
1068 /// ⚠️ WARNING - 2022-08-11 - no biometric status reports have been published, so we are unable
1069 /// to validate the correctness of this type and it's parser.
1070 ///
1071 /// Status of the FIDO Biometric Certification of one or more biometric components of the Authenticator
1072 #[serde(default)]
1073 pub biometric_status_reports: Vec<BiometricsStatusReport>,
1074 /// An array of status reports applicable to this authenticator.
1075 pub status_reports: Vec<StatusReport>,
1076 /// ISO-8601 formatted date since when the status report array was set to the current value.
1077 pub time_of_last_status_change: String, // iso 8601 time.
1078 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
1079 ///
1080 /// URL of a list of rogue (i.e. untrusted) individual authenticators.
1081 #[serde(rename = "rogueListURL")]
1082 pub rogue_list_url: Option<String>,
1083 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
1084 ///
1085 /// The hash value computed over the Base64url encoding of the UTF-8 representation of the JSON
1086 /// encoded rogueList available at rogueListURL (with type rogueListEntry). The hash algorithm
1087 /// related to the signature algorithm specified in the JWTHeader (see Metadata BLOB) MUST be used.
1088 ///
1089 /// This hash value MUST be present and non-empty whenever rogueListURL is present.
1090 pub rogue_list_hash: Option<String>,
1091}
1092
1093impl fmt::Display for FidoDevice {
1094 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1095 let s = serde_json::to_string_pretty(self).map_err(|_| fmt::Error)?;
1096 write!(f, "FidoDevice {s}")
1097 }
1098}
1099
1100/// The parsed content of the Fido Metadata Server. This content can be retrieved from it's online
1101/// url at <https://mds.fidoalliance.org/> . It's recommended you re-download this content every few weeks. This can be parsed
1102/// from it's str representation - for from_str to suceed, the metadata jwt content MUST be correctly
1103/// signed be pinned root certificate authority, the full chain is verified, and the content of the
1104/// JWT is signed correctly.
1105///
1106/// The fido metadata specification listed at <https://fidoalliance.org/specs/mds/fido-metadata-service-v3.0-ps-20210518.html>
1107/// has a number of errors (~20 deviations). When they are found, the "true implementation" of the content of the JWT
1108/// is used, rather than the specification.
1109///
1110/// Generally the use of meanings, and definitions of many fields is fuzzy at best. This makes it
1111/// harder for you to fully rely on all the content of this document and what it implies for your
1112/// use case. When a field is un-clear, a `⚠️ WARNING` will be listed.
1113#[derive(Debug, Clone, Serialize, Deserialize)]
1114#[serde(deny_unknown_fields, rename_all = "camelCase")]
1115pub struct FidoMds {
1116 /// The set of device metadata
1117 pub entries: Vec<FidoDevice>,
1118 /// legal header
1119 pub legal_header: String,
1120 /// ISO-8601 formatted date when the next update will be provided at latest.
1121 pub next_update: String,
1122 /// The serial number of this UAF Metadata BLOB Payload. Serial numbers MUST be consecutive and
1123 /// strictly monotonic, i.e. the successor BLOB will have a no value exactly incremented by one.
1124 pub no: u32,
1125}
1126
1127impl FromStr for FidoMds {
1128 type Err = JwtError;
1129
1130 fn from_str(s: &str) -> Result<Self, Self::Err> {
1131 // Setup the trusted CA store so that we can validate the authenticity of the MDS blob.
1132 let root_ca = x509::X509::from_pem(GLOBAL_SIGN_ROOT_CA_R3.as_bytes())
1133 .map_err(|_| JwtError::OpenSSLError)?;
1134
1135 let jws = JwsCompact::from_str(s)?;
1136
1137 let fullchain = jws
1138 .get_x5c_chain()
1139 .and_then(|chain| chain.ok_or(JwtError::InvalidHeaderFormat))?;
1140
1141 let verifier = JwsX509VerifierBuilder::new()
1142 .add_fullchain(fullchain)
1143 .add_trust_root(root_ca)
1144 .build()
1145 .map_err(|_| JwtError::OpenSSLError)?;
1146
1147 // Now we can release the embedded cert, since we have asserted the trust in the chain
1148 // that has signed this metadata.
1149 let released = verifier.verify(&jws)?;
1150
1151 let metadata: FidoMds = released.from_json().map_err(|serde_err| {
1152 tracing::error!(?serde_err);
1153 JwtError::Serde
1154 })?;
1155
1156 // trace!(?metadata);
1157
1158 Ok(metadata)
1159 }
1160}