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#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
584#[serde(rename_all = "lowercase")]
585pub enum AttestationFormat {
586 Packed,
587}
588
589/// The output of authenticatorGetInfo. Some fields are hidden as they are duplicated
590/// in the metadata statement.
591#[derive(Debug, Clone, Serialize, Deserialize)]
592#[serde(deny_unknown_fields, rename_all = "camelCase")]
593pub struct AuthenticatorGetInfo {
594 /// The list of supported CTAP versions
595 pub versions: Vec<AuthenticatorVersion>,
596 /// The list of supported extension identifiers.
597 #[serde(default)]
598 pub extensions: Vec<String>,
599 /// The AAGUID (UUID) of this device
600 pub aaguid: Uuid,
601 /// List of supported Options
602 #[serde(default)]
603 pub options: BTreeMap<String, bool>,
604 /// The largest ctap message size this device supports
605 pub max_msg_size: Option<u32>,
606 /// The list of PIN UV auth protocols
607 #[serde(default)]
608 pub pin_uv_auth_protocols: Vec<u32>,
609 /// The maximum number of credentials ID's that can be listed and provided to this device.
610 pub max_credential_count_in_list: Option<u32>,
611 /// The maximum length of a credential ID that can be provided to this device.
612 pub max_credential_id_length: Option<u32>,
613 /// The list of transports this device supports
614 #[serde(default)]
615 pub transports: Vec<AuthenticatorTransport>,
616 #[serde(default)]
617 pub(crate) algorithms: Vec<serde_json::Value>,
618 /// The maximum size of large blob array this device can store, if the extension is supported.
619 pub max_serialized_large_blob_array: Option<u32>,
620 #[serde(rename = "forcePINChange")]
621 force_pin_change: Option<bool>,
622 /// The minimum pin length that this device requires.
623 #[serde(rename = "minPINLength")]
624 pub min_pin_length: Option<u32>,
625 firmware_version: Option<u32>,
626 /// The maximum size of the credBlob if supported
627 pub max_cred_blob_length: Option<u32>,
628 /// The maximum number of discoverable (resident) keys this device supports.
629 #[serde(rename = "maxRPIDsForSetMinPINLength")]
630 pub max_rpids_for_set_min_pin_length: Option<u32>,
631 /// _
632 pub preferred_platform_uv_attempts: Option<u32>,
633 uv_modality: Option<u32>,
634 #[serde(default)]
635 pub certifications: BTreeMap<String, u32>,
636 /// The number of remaining resident keys on this device.
637 pub remaining_discoverable_credentials: Option<u32>,
638 /// Vendor specific details
639 #[serde(default)]
640 pub vendor_prototype_config_commands: Vec<u32>,
641
642 /// Supported attestation formats
643 #[serde(default)]
644 pub attestation_formats: Vec<AttestationFormat>,
645}
646
647#[derive(Debug, Clone, Serialize, Deserialize)]
648#[serde(deny_unknown_fields, rename_all = "camelCase")]
649/// A statement describing a device and it's associated properties.
650pub struct MetadataStatement {
651 /// Legal Header
652 pub legal_header: Option<String>,
653 /// The Authenticator Attestation ID. See UAFProtocol for the definition of the AAID structure.
654 /// This field must be set if the authenticator implements FIDO UAF.
655 pub aaid: Option<String>,
656 /// The Authenticator Attestation GUID. See FIDOKeyAttestation for the definition of the
657 /// AAGUID structure. This field must be set if the authenticator implements FIDO 2.
658 pub aaguid: Option<Uuid>,
659 /// A list of the attestation certificate public key identifiers encoded as hex string. This
660 /// value must be calculated according to method 1 for computing the keyIdentifier as defined
661 /// in RFC5280 section 4.2.1.2. The hex string must not contain any non-hex characters
662 /// (e.g. spaces). All hex letters must be lower case. This field must be set if neither aaid
663 /// nor aaguid are set. Setting this field implies that the attestation certificate(s) are
664 /// dedicated to a single authenticator model.
665 ///
666 /// All attestationCertificateKeyIdentifier values should be unique within the scope of the Metadata Service.
667 pub attestation_certificate_key_identifiers: Option<Vec<String>>,
668 /// A human-readable, short description of the authenticator, in English.
669 pub description: String,
670 /// A list of human-readable short descriptions of the authenticator in different languages.
671 #[serde(default)]
672 pub alternative_descriptions: BTreeMap<String, String>,
673
674 /// A list of friendly names describing the device.
675 pub friendly_names: BTreeMap<String, String>,
676
677 /// Earliest (i.e. lowest) trustworthy authenticatorVersion meeting the requirements specified
678 /// in this metadata statement.
679 ///
680 /// Adding new StatusReport entries with status UPDATE_AVAILABLE to the metadata TOC object
681 /// FIDOMetadataService must also change this authenticatorVersion if the update fixes severe
682 /// security issues, e.g. the ones reported by preceding StatusReport entries with status code
683 /// USER_VERIFICATION_BYPASS, ATTESTATION_KEY_COMPROMISE, USER_KEY_REMOTE_COMPROMISE, USER_KEY_PHYSICAL_COMPROMISE, REVOKED.
684 ///
685 /// It is recommended to assume increased risk if this version is higher (newer) than the
686 /// firmware version present in an authenticator. For example, if a StatusReport entry with
687 /// status USER_VERIFICATION_BYPASS or USER_KEY_REMOTE_COMPROMISE precedes the UPDATE_AVAILABLE
688 /// entry, than any firmware version lower (older) than the one specified in the metadata statement
689 /// is assumed to be vulnerable.
690 pub authenticator_version: u32,
691 /// The FIDO protocol family. The values "uaf", "u2f", and "fido2" are supported. If this field
692 /// is missing, the assumed protocol family is "uaf". Metadata Statements for U2F authenticators
693 /// must set the value of protocolFamily to "u2f" and FIDO 2.0/WebAuthentication Authenticator
694 /// implementations must set the value of protocolFamily to "fido2".
695 ///
696 /// ❗️ This is represented as an enum in this project to help you understand the possible values
697 /// that *may* exist. This contradicts the MDS spec, but it's better for you the consumer.
698 #[serde(default)]
699 pub protocol_family: ProtocolFamily,
700 /// Version of this structure
701 pub schema: u16,
702 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
703 ///
704 /// The FIDO unified protocol version(s) (related to the specific protocol family) supported by
705 /// this authenticator. See UAFProtocol for the definition of the Version structure.
706 pub upv: Vec<Upv>,
707 /// The list of authentication algorithms supported by the authenticator. Must be set to the
708 /// complete list of the supported ALG_ constants defined in the FIDO Registry of Predefined
709 /// Values FIDORegistry if the authenticator supports multiple algorithms. Each value must be non-zero.
710 ///
711 /// ❗️ This is represented as an enum in this project to help you understand the possible values
712 /// that *may* exist. This contradicts the MDS spec, but it's better for you the consumer.
713 #[serde(default)]
714 pub authentication_algorithms: Vec<AuthenticationAlgorithm>,
715 /// The list of public key formats supported by the authenticator during registration operations.
716 /// Must be set to the complete list of the supported ALG_KEY constants defined in the FIDO Registry
717 /// of Predefined Values FIDORegistry if the authenticator model supports multiple encodings.
718 /// Because this information is not present in APIs related to authenticator discovery or policy,
719 /// a FIDO server must be prepared to accept and process any and all key representations defined
720 /// for any public key algorithm it supports. Each value must be non-zero.
721 ///
722 /// ❗️ This is represented as an enum in this project to help you understand the possible values
723 /// that *may* exist. This contradicts the MDS spec, but it's better for you the consumer.
724 #[serde(default)]
725 pub public_key_alg_and_encodings: Vec<PublicKeyAlg>,
726 /// The supported attestation type(s). (e.g. TAG_ATTESTATION_BASIC_FULL(0x3E07), TAG_ATTESTATION_BASIC_SURROGATE(0x3E08)).
727 ///
728 /// ❗️ This is represented as an enum in this project to help you understand the possible values
729 /// that *may* exist. This contradicts the MDS spec, but it's better for you the consumer.
730 pub attestation_types: Vec<AttestationType>,
731 /// A list of alternative VerificationMethodANDCombinations.
732 ///
733 /// userVerificationDetails is a two dimensional array, that informs RP what
734 /// VerificationMethodANDCombinations user may be required to perform in order to pass user
735 /// verification, e.g User need to pass fingerprint, or faceprint, or password and palm print, etc.
736 ///
737 /// The outer array is an OR over the values, and the inner arrays are ANDs. For example:
738 ///
739 ///
740 /// [
741 /// [
742 /// { user_verification_method: ... }
743 /// ],
744 /// // OR
745 /// [
746 /// { user_verification_method: ... },
747 /// // AND
748 /// { user_verification_method: ... }
749 /// ],
750 /// ]
751 ///
752 pub user_verification_details: Vec<Vec<VerificationMethodAndCombinations>>,
753 /// The list of key protection types supported by the authenticator. Must be set to the complete
754 /// list of the supported KEY_PROTECTION_ constant case-sensitive string names.
755 ///
756 /// ❗️ This is represented as an enum in this project to help you understand the possible values
757 /// that *may* exist. This contradicts the MDS spec, but it's better for you the consumer.
758 pub key_protection: Vec<KeyProtection>,
759 /// This entry is set to true, if the Uauth private key is restricted by the authenticator to
760 /// only sign valid FIDO signature assertions.
761 ///
762 /// This entry is set to false, if the authenticator doesn't restrict the Uauth key to only
763 /// sign valid FIDO signature assertions. In this case, the calling application could potentially
764 /// get any hash value signed by the authenticator.
765 ///
766 /// If this field is missing, the assumed value is isKeyRestricted=true
767 #[serde(default = "assume_true")]
768 pub is_key_restricted: bool,
769 /// This entry is set to true, if Uauth key usage always requires a fresh user verification.
770 ///
771 /// If this field is missing, the assumed value is isFreshUserVerificationRequired=true.
772 ///
773 /// This entry is set to false, if the Uauth key can be used without requiring a fresh user
774 /// verification, e.g. without any additional user interaction, if the user was verified a
775 /// (potentially configurable) caching time ago.
776 ///
777 /// In the case of isFreshUserVerificationRequired=false, the FIDO server must verify the
778 /// registration response and/or authentication response and verify that the (maximum) caching
779 /// time (sometimes also called "authTimeout") is acceptable.
780 ///
781 /// This entry solely refers to the user verification. In the case of transaction confirmation,
782 /// the authenticator must always ask the user to authorize the specific transaction.
783 #[serde(default = "assume_true")]
784 pub is_fresh_user_verification_required: bool,
785 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
786 ///
787 /// ❗️ This is represented as an enum in this project to help you understand the possible values
788 /// that *may* exist. This contradicts the MDS spec, but it's better for you the consumer.
789 pub matcher_protection: Vec<MatcherProtection>,
790 /// The authenticator's overall claimed cryptographic strength in bits (sometimes also called
791 /// security strength or security level). This is the minimum of the cryptographic strength of
792 /// all involved cryptographic methods (e.g. RNG, underlying hash, key wrapping algorithm,
793 /// signing algorithm, attestation algorithm), e.g. see FIPS180-4, FIPS186-4, FIPS198-1,
794 /// SP800-38B, SP800-38C, SP800-38D, SP800-38F, SP800-90C, SP800-90ar1, FIPS140-2 etc.
795 ///
796 /// If this value is absent, the cryptographic strength is unknown. If the cryptographic strength
797 /// of one of the involved cryptographic methods is unknown the overall claimed cryptographic
798 /// strength is also unknown.
799 pub crypto_strength: Option<u16>,
800 /// 🤔 Authors Note: Generally attachment hint is a very problematic thing to provide to browsers
801 /// as they are not always used or expected in work flows. It's likely this field is "useless"
802 /// as a result.
803 ///
804 /// A list of attachment hints that MAY be used with this device.
805 ///
806 /// ❗️ This is represented as an enum in this project to help you understand the possible values
807 /// that *may* exist. This contradicts the MDS spec, but it's better for you the consumer.
808 pub attachment_hint: Vec<AttachmentHint>,
809 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
810 ///
811 /// A 16-bit number representing a combination of the bit flags defined by the
812 /// TRANSACTION_CONFIRMATION_DISPLAY constants in the FIDO Registry of Predefined Values FIDORegistry.
813 /// This value must be 0, if transaction confirmation is not supported by the authenticator.
814 pub tc_display: Vec<String>,
815 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
816 ///
817 pub tc_display_content_type: Option<String>,
818 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
819 ///
820 #[serde(rename = "tcDisplayPNGCharacteristics")]
821 pub tc_display_png_characteristics: Option<serde_json::Value>,
822 /// ❌ NOTE - The FIDO metadata specification defines this as a an array of base64 values, however
823 /// many values are INVALID and contain leading/trailing whitespace that MAY confuse your base64 parser
824 ///
825 /// ⚠️ WARNING - Content of this value MAY have extra leading or trailing whitespace which MAY
826 /// cause issues when parsing.
827 ///
828 /// Each element of this array represents a PKIX RFC5280 X.509 certificate that is a valid
829 /// trust anchor for this authenticator model. Multiple certificates might be used for different
830 /// batches of the same model. The array does not represent a certificate chain, but only the
831 /// trust anchor of that chain. A trust anchor can be a root certificate, an intermediate CA
832 /// certificate or even the attestation certificate itself.
833 ///
834 /// Each array element is a base64-encoded (section 4 of RFC4648), DER-encoded ITU-X690-2008
835 /// PKIX certificate value. Each element must be dedicated for authenticator attestation.
836 ///
837 // /// ❗️ This is decoded from Base64 for you so that you can directly access the DER of the certificate.
838 // attestation_root_certificates: Vec<Base64UrlSafeData>,
839 pub attestation_root_certificates: Vec<String>,
840 /// A list of trust anchors used for ECDAA attestation. This entry must be present if and only
841 /// if attestationType includes TAG_ATTESTATION_ECDAA. The entries in attestationRootCertificates
842 /// have no relevance for ECDAA attestation. Each ecdaaTrustAnchor must be dedicated to a single
843 /// authenticator model (e.g as identified by its AAID/AAGUID).
844 #[serde(default)]
845 pub ecdaa_trust_anchors: Vec<EcdaaAnchor>,
846 /// An icon representing this device.
847 pub icon: Option<serde_json::Value>,
848 /// The list of supported extensions of this authenticator
849 #[serde(default)]
850 pub supported_extensions: Vec<ExtensionDescriptor>,
851 /// Describes supported versions, extensions, AAGUID of the device and its capabilities.
852 ///
853 /// The information is the same reported by an authenticator when invoking the 'authenticatorGetInfo'
854 /// method, see FIDOCTAP.
855 pub authenticator_get_info: Option<AuthenticatorGetInfo>,
856
857 #[serde(default)]
858 /// Defines if credentials in this authenticator can be accessed on multiple
859 /// devices. If set to `unsupported` this means that it is a single device
860 /// credential.
861 pub multi_device_credential_support: MultiDeviceCredentialSupport,
862}
863
864#[derive(Debug, Clone, Default, Serialize, Deserialize)]
865#[serde(rename_all = "camelCase")]
866/// See `BiometricsStatusReport`
867pub enum BiometricModality {
868 /// No valid biometric modality was provided.
869 #[default]
870 Unknown,
871}
872
873#[derive(Debug, Clone, Serialize, Deserialize)]
874#[serde(deny_unknown_fields, rename_all = "camelCase")]
875/// A status report for the device if it provides biometrics
876pub struct BiometricsStatusReport {
877 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
878 ///
879 /// Achieved level of the biometric certification of this biometric component of the authenticator
880 pub cert_level: u16,
881 /// A single a single USER_VERIFY short form case-sensitive string name constant, representing
882 /// biometric modality. See section "User Verification Methods" in FIDORegistry
883 /// (e.g. "fingerprint_internal").
884 ///
885 /// ❗️ This is represented as an enum in this project to help you understand the possible values
886 /// that *may* exist. This contradicts the MDS spec, but it's better for you the consumer.
887 #[serde(default)]
888 pub modality: BiometricModality,
889 /// ISO-8601 formatted date since when the certLevel achieved, if applicable. If no date is
890 /// given, the status is assumed to be effective while present.
891 pub effective_date: Option<String>,
892 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
893 ///
894 /// Describes the externally visible aspects of the Biometric Certification evaluation.
895 ///
896 /// For example, if it states "on chip" this means the biometrics are kept inside the device only
897 pub certification_descriptor: Option<String>,
898 /// The unique identifier for the issued Biometric Certification.
899 pub certificate_number: Option<String>,
900 /// The version of the Biometric Certification Policy the implementation is Certified to, e.g. "1.0.0".
901 pub certification_policy_version: Option<String>,
902 /// The version of the Biometric Requirements FIDOBiometricsRequirements the implementation is certified to, e.g. "1.0.0".
903 pub certification_requirements_version: Option<String>,
904}
905
906/// The fido certification status of the device associated to this aaid/aaguid.
907#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
908pub enum AuthenticatorStatus {
909 /// The device is NOT fido certified
910 #[serde(rename = "NOT_FIDO_CERTIFIED")]
911 NotFidoCertified,
912 /// The divec is fido certified. This will be phased out in favour of the FIDO_CERTIFIED_L1
913 /// field.
914 #[serde(rename = "FIDO_CERTIFIED")]
915 FidoCertified,
916 /// Indicates that malware is able to bypass the user verification. This means that the
917 /// authenticator could be used without the user’s consent and potentially even without the
918 /// user’s knowledge.
919 #[serde(rename = "USER_VERIFICATION_BYPASS")]
920 UserVerificationBypass,
921 /// Indicates that an attestation key for this authenticator is known to be compromised.
922 /// The relying party SHOULD check the certificate field and use it to identify the compromised
923 /// authenticator batch. If the certificate field is not set, the relying party should reject
924 /// all new registrations of the compromised authenticator. The Authenticator manufacturer
925 /// should set the date to the date when compromise has occurred.
926 #[serde(rename = "ATTESTATION_KEY_COMPROMISE")]
927 AttestationKeyCompromise,
928 /// This authenticator has identified weaknesses that allow registered keys to be compromised
929 /// and should not be trusted. This would include both, e.g. weak entropy that causes
930 /// predictable keys to be generated or side channels that allow keys or signatures to be
931 /// forged, guessed or extracted.
932 #[serde(rename = "USER_KEY_REMOTE_COMPROMISE")]
933 UserKeyRemoteCompromise,
934 /// This authenticator has known weaknesses in its key protection mechanism(s) that allow user
935 /// keys to be extracted by an adversary in physical possession of the device.
936 #[serde(rename = "USER_KEY_PHYSICAL_COMPROMISE")]
937 UserKeyPhysicalCompromise,
938 /// A software or firmware update is available for the device. The Authenticator manufacturer
939 /// should set the url to the URL where users can obtain an update and the date the update was
940 /// published. When this status code is used, then the field authenticatorVersion in the
941 /// authenticator Metadata Statement FIDOMetadataStatement MUST be updated, if the update fixes
942 /// severe security issues, e.g. the ones reported by preceding StatusReport entries with status
943 /// code USER_VERIFICATION_BYPASS, ATTESTATION_KEY_COMPROMISE, USER_KEY_REMOTE_COMPROMISE,
944 /// USER_KEY_PHYSICAL_COMPROMISE, REVOKED. The Relying party MUST reject the Metadata Statement
945 /// if the authenticatorVersion has not increased
946 #[serde(rename = "UPDATE_AVAILABLE")]
947 UpdateAvailable,
948 /// The FIDO Alliance has determined that this authenticator should not be trusted for any
949 /// reason. For example if it is known to be a fraudulent product or contain a deliberate
950 /// backdoor. Relying parties SHOULD reject any future registration of this authenticator model.
951 #[serde(rename = "REVOKED")]
952 Revoked,
953 /// The authenticator vendor has completed and submitted the self-certification checklist to
954 /// the FIDO Alliance. If this completed checklist is publicly available, the URL will be
955 /// specified in url.
956 #[serde(rename = "SELF_ASSERTION_SUBMITTED")]
957 SelfAssertionSubmitted,
958 /// This device is certified at level 1
959 #[serde(rename = "FIDO_CERTIFIED_L1")]
960 FidoCertifiedL1,
961 /// This device is certified at level 1 plus
962 #[serde(rename = "FIDO_CERTIFIED_L1plus")]
963 FidoCertifiedL1Plus,
964 /// This device is certified at level 2
965 #[serde(rename = "FIDO_CERTIFIED_L2")]
966 FidoCertifiedL2,
967 /// This device is certified at level 2 plus
968 #[serde(rename = "FIDO_CERTIFIED_L2plus")]
969 FidoCertifiedL2Plus,
970 /// This device is certified at level 3
971 #[serde(rename = "FIDO_CERTIFIED_L3")]
972 FidoCertifiedL3,
973 /// This device is certified at level 3 plus
974 #[serde(rename = "FIDO_CERTIFIED_L3plus")]
975 FidoCertifiedL3Plus,
976}
977
978impl FromStr for AuthenticatorStatus {
979 type Err = ();
980
981 fn from_str(s: &str) -> Result<Self, Self::Err> {
982 match s.to_lowercase().as_str() {
983 "not-certified" => Ok(AuthenticatorStatus::NotFidoCertified),
984 "uv-bypass" => Ok(AuthenticatorStatus::UserVerificationBypass),
985 "key-compromise" => Ok(AuthenticatorStatus::AttestationKeyCompromise),
986 "remote-exploit" => Ok(AuthenticatorStatus::UserKeyRemoteCompromise),
987 "physical-compromise" => Ok(AuthenticatorStatus::UserKeyPhysicalCompromise),
988 "update-available" => Ok(AuthenticatorStatus::UpdateAvailable),
989 "revoked" => Ok(AuthenticatorStatus::Revoked),
990 "self-asserted" => Ok(AuthenticatorStatus::SelfAssertionSubmitted),
991 "valid" | "l1" => Ok(AuthenticatorStatus::FidoCertifiedL1),
992 "l1+" => Ok(AuthenticatorStatus::FidoCertifiedL1Plus),
993 "l2" => Ok(AuthenticatorStatus::FidoCertifiedL2),
994 "l2+" => Ok(AuthenticatorStatus::FidoCertifiedL2Plus),
995 "l3" => Ok(AuthenticatorStatus::FidoCertifiedL3),
996 "l3+" => Ok(AuthenticatorStatus::FidoCertifiedL3Plus),
997 _ => Err(()),
998 }
999 }
1000}
1001
1002impl AuthenticatorStatus {
1003 pub(crate) fn numeric(&self) -> u8 {
1004 match self {
1005 AuthenticatorStatus::NotFidoCertified
1006 | AuthenticatorStatus::UserVerificationBypass
1007 | AuthenticatorStatus::AttestationKeyCompromise
1008 | AuthenticatorStatus::UserKeyRemoteCompromise
1009 | AuthenticatorStatus::UserKeyPhysicalCompromise
1010 | AuthenticatorStatus::UpdateAvailable
1011 | AuthenticatorStatus::Revoked
1012 | AuthenticatorStatus::SelfAssertionSubmitted => 0,
1013 AuthenticatorStatus::FidoCertified | AuthenticatorStatus::FidoCertifiedL1 => 10,
1014 AuthenticatorStatus::FidoCertifiedL1Plus => 11,
1015 AuthenticatorStatus::FidoCertifiedL2 => 20,
1016 AuthenticatorStatus::FidoCertifiedL2Plus => 21,
1017 AuthenticatorStatus::FidoCertifiedL3 => 30,
1018 AuthenticatorStatus::FidoCertifiedL3Plus => 31,
1019 }
1020 }
1021}
1022
1023#[derive(Debug, Clone, Serialize, Deserialize)]
1024#[serde(deny_unknown_fields, rename_all = "camelCase")]
1025/// Contains an AuthenticatorStatus and additional data associated with it, if any.
1026///
1027/// The latest StatusReport entry MUST reflect the "current" status. For example, if the latest
1028/// entry has status USER_VERIFICATION_BYPASS, then it is recommended assuming an increased risk
1029/// associated with all authenticators of this AAID; if the latest entry has status UPDATE_AVAILABLE,
1030/// then the update is intended to address at least all previous issues reported in this StatusReport
1031/// dictionary.
1032pub struct StatusReport {
1033 /// The status of the authenticator.
1034 pub status: AuthenticatorStatus,
1035 /// ISO-8601 formatted date since when the status code was set, if applicable. If no date is
1036 /// given, the status is assumed to be effective while present.
1037 pub effective_date: Option<String>,
1038 /// The authenticatorVersion that this status report relates to. In the case of FIDO_CERTIFIED*
1039 /// status values, the status applies to higher authenticatorVersions until there is a new statusReport.
1040 pub authenticator_version: Option<u32>,
1041 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
1042 ///
1043 /// Base64-encoded RFC4648 (not base64url!) DER ITU-X690-2008 PKIX certificate value related
1044 /// to the current status, if applicable.
1045 pub certificate: Option<String>,
1046 /// HTTPS URL where additional information may be found related to the current status, if applicable.
1047 pub url: Option<String>,
1048 /// Describes the externally visible aspects of the Authenticator Certification evaluation.
1049 ///
1050 /// For example it could state that the authenticator is a "SecurityKey based on a CC EAL 5
1051 /// certified chip hardware".
1052 pub certification_descriptor: Option<String>,
1053 /// The unique identifier for the issued Certification.
1054 pub certificate_number: Option<String>,
1055 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
1056 ///
1057 /// The version of the Authenticator Certification Policy the implementation is Certified to, e.g. "1.0.0".
1058 pub certification_policy_version: Option<String>,
1059 /// The Document Version of the Authenticator Security Requirements (DV)
1060 /// FIDOAuthenticatorSecurityRequirements the implementation is certified to, e.g. "1.2.0".
1061 pub certification_requirements_version: Option<String>,
1062
1063 /// ⚠️ WARNING - CONTENT AND USE OF THIS VALUE IS NOT DOCUMENTED BY FIDO
1064 certification_profiles: Option<serde_json::Value>,
1065}
1066
1067#[derive(Debug, Clone, Serialize, Deserialize)]
1068#[serde(deny_unknown_fields, rename_all = "camelCase")]
1069/// A statement describing a device and it's associated properties.
1070pub struct FidoDevice {
1071 /// If this device is identified by an aaid, it will be listed here.
1072 pub aaid: Option<String>,
1073 /// Alternately, if the device is identified by an AAGUID it will be set here. Generally all
1074 /// FIDO2 devices will use aaguid.
1075 pub aaguid: Option<Uuid>,
1076 /// A list of the attestation certificate public key identifiers encoded as hex string. This
1077 /// value MUST be calculated according to method 1 for computing the keyIdentifier as defined
1078 /// in RFC5280 section 4.2.1.2.
1079 pub attestation_certificate_key_identifiers: Option<Vec<String>>,
1080 /// The FIDOMetadataStatement pertaining to this device.
1081 pub metadata_statement: MetadataStatement,
1082 /// ⚠️ WARNING - 2022-08-11 - no biometric status reports have been published, so we are unable
1083 /// to validate the correctness of this type and it's parser.
1084 ///
1085 /// Status of the FIDO Biometric Certification of one or more biometric components of the Authenticator
1086 #[serde(default)]
1087 pub biometric_status_reports: Vec<BiometricsStatusReport>,
1088 /// An array of status reports applicable to this authenticator.
1089 pub status_reports: Vec<StatusReport>,
1090 /// ISO-8601 formatted date since when the status report array was set to the current value.
1091 pub time_of_last_status_change: String, // iso 8601 time.
1092 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
1093 ///
1094 /// URL of a list of rogue (i.e. untrusted) individual authenticators.
1095 #[serde(rename = "rogueListURL")]
1096 pub rogue_list_url: Option<String>,
1097 /// ⚠️ WARNING - Content of this value is not well documented to it's intent or usage!
1098 ///
1099 /// The hash value computed over the Base64url encoding of the UTF-8 representation of the JSON
1100 /// encoded rogueList available at rogueListURL (with type rogueListEntry). The hash algorithm
1101 /// related to the signature algorithm specified in the JWTHeader (see Metadata BLOB) MUST be used.
1102 ///
1103 /// This hash value MUST be present and non-empty whenever rogueListURL is present.
1104 pub rogue_list_hash: Option<String>,
1105}
1106
1107impl fmt::Display for FidoDevice {
1108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1109 let s = serde_json::to_string_pretty(self).map_err(|_| fmt::Error)?;
1110 write!(f, "FidoDevice {s}")
1111 }
1112}
1113
1114/// The parsed content of the Fido Metadata Server. This content can be retrieved from it's online
1115/// url at <https://mds.fidoalliance.org/> . It's recommended you re-download this content every few weeks. This can be parsed
1116/// from it's str representation - for from_str to suceed, the metadata jwt content MUST be correctly
1117/// signed be pinned root certificate authority, the full chain is verified, and the content of the
1118/// JWT is signed correctly.
1119///
1120/// The fido metadata specification listed at <https://fidoalliance.org/specs/mds/fido-metadata-service-v3.0-ps-20210518.html>
1121/// has a number of errors (~20 deviations). When they are found, the "true implementation" of the content of the JWT
1122/// is used, rather than the specification.
1123///
1124/// Generally the use of meanings, and definitions of many fields is fuzzy at best. This makes it
1125/// harder for you to fully rely on all the content of this document and what it implies for your
1126/// use case. When a field is un-clear, a `⚠️ WARNING` will be listed.
1127#[derive(Debug, Clone, Serialize, Deserialize)]
1128#[serde(deny_unknown_fields, rename_all = "camelCase")]
1129pub struct FidoMds {
1130 /// The set of device metadata
1131 pub entries: Vec<FidoDevice>,
1132 /// legal header
1133 pub legal_header: String,
1134 /// ISO-8601 formatted date when the next update will be provided at latest.
1135 pub next_update: String,
1136 /// The serial number of this UAF Metadata BLOB Payload. Serial numbers MUST be consecutive and
1137 /// strictly monotonic, i.e. the successor BLOB will have a no value exactly incremented by one.
1138 pub no: u32,
1139}
1140
1141impl FromStr for FidoMds {
1142 type Err = JwtError;
1143
1144 fn from_str(s: &str) -> Result<Self, Self::Err> {
1145 // Setup the trusted CA store so that we can validate the authenticity of the MDS blob.
1146 let root_ca = x509::X509::from_pem(GLOBAL_SIGN_ROOT_CA_R3.as_bytes())
1147 .map_err(|_| JwtError::OpenSSLError)?;
1148
1149 let jws = JwsCompact::from_str(s)?;
1150
1151 let fullchain = jws
1152 .get_x5c_chain()
1153 .and_then(|chain| chain.ok_or(JwtError::InvalidHeaderFormat))?;
1154
1155 let verifier = JwsX509VerifierBuilder::new()
1156 .add_fullchain(fullchain)
1157 .add_trust_root(root_ca)
1158 .build()
1159 .map_err(|_| JwtError::OpenSSLError)?;
1160
1161 // Now we can release the embedded cert, since we have asserted the trust in the chain
1162 // that has signed this metadata.
1163 let released = verifier.verify(&jws)?;
1164
1165 let metadata: FidoMds = released.from_json().map_err(|serde_err| {
1166 tracing::error!(?serde_err);
1167 JwtError::Serde
1168 })?;
1169
1170 // trace!(?metadata);
1171
1172 Ok(metadata)
1173 }
1174}