webauthn_rs_core/interface.rs
1//! Extended Structs and representations for Webauthn Operations. These types are designed
2//! to allow persistence and should not change.
3
4use crate::attestation::verify_attestation_ca_chain;
5use crate::error::*;
6pub use crate::internals::AttestationObject;
7use std::fmt;
8use webauthn_rs_proto::cose::*;
9use webauthn_rs_proto::extensions::*;
10use webauthn_rs_proto::options::*;
11
12pub use webauthn_attestation_ca::*;
13
14use base64urlsafedata::HumanBinaryData;
15
16use serde::de::DeserializeOwned;
17use serde::{Deserialize, Serialize};
18use std::collections::BTreeMap;
19
20use openssl::{bn, ec, nid, pkey, x509};
21use uuid::Uuid;
22
23/// Representation of an AAGUID
24/// <https://www.w3.org/TR/webauthn/#aaguid>
25pub type Aaguid = [u8; 16];
26
27/// Representation of a credentials activation counter.
28pub type Counter = u32;
29
30/// The in progress state of a credential registration attempt. You must persist this in a server
31/// side location associated to the active session requesting the registration. This contains the
32/// user unique id which you can use to reference the user requesting the registration.
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct RegistrationState {
35 pub(crate) policy: UserVerificationPolicy,
36 pub(crate) exclude_credentials: Vec<CredentialID>,
37 pub(crate) challenge: HumanBinaryData,
38 pub(crate) credential_algorithms: Vec<COSEAlgorithm>,
39 pub(crate) require_resident_key: bool,
40 pub(crate) authenticator_attachment: Option<AuthenticatorAttachment>,
41 pub(crate) extensions: RequestRegistrationExtensions,
42 pub(crate) allow_synchronised_authenticators: bool,
43}
44
45/// The in progress state of an authentication attempt. You must persist this associated to the UserID
46/// requesting the registration.
47#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct AuthenticationState {
49 pub(crate) credentials: Vec<Credential>,
50 pub(crate) policy: UserVerificationPolicy,
51 pub(crate) challenge: HumanBinaryData,
52 pub(crate) appid: Option<String>,
53 pub(crate) allow_backup_eligible_upgrade: bool,
54}
55
56impl AuthenticationState {
57 /// set which credentials the user is allowed to authenticate with. This
58 /// is used as part of resident key authentication flows where we need
59 /// to inject the set of viable credentials after the client has sent us
60 /// their public key credential and we identify the user.
61 pub fn set_allowed_credentials(&mut self, credentials: Vec<Credential>) {
62 self.credentials = credentials;
63 }
64}
65
66/// An EDDSACurve identifier. You probably will never need to alter
67/// or use this value, as it is set inside the Credential for you.
68#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
69pub enum EDDSACurve {
70 // +---------+-------+----------+------------------------------------+
71 // | Name | Value | Key Type | Description |
72 // +---------+-------+----------+------------------------------------+
73 // | X25519 | 4 | OKP | X25519 for use w/ ECDH only |
74 // | X448 | 5 | OKP | X448 for use w/ ECDH only |
75 // | Ed25519 | 6 | OKP | Ed25519 for use w/ EdDSA only |
76 // | Ed448 | 7 | OKP | Ed448 for use w/ EdDSA only |
77 // +---------+-------+----------+------------------------------------+
78 // /// Identifies this curve as X25519 ECDH only
79 // X25519 = 4,
80 // /// Identifies this curve as X448 ECDH only
81 // X448 = 5,
82 /// Identifies this OKP as ED25519
83 ED25519 = 6,
84 /// Identifies this OKP as ED448
85 ED448 = 7,
86}
87
88impl EDDSACurve {
89 /// Returns the size in bytes of the coordinate for the specified curve
90 pub(crate) fn coordinate_size(&self) -> usize {
91 match self {
92 Self::ED25519 => 32,
93 Self::ED448 => 57,
94 }
95 }
96}
97
98/// An ECDSACurve identifier. You probably will never need to alter
99/// or use this value, as it is set inside the Credential for you.
100#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
101pub enum ECDSACurve {
102 // +---------+-------+----------+------------------------------------+
103 // | Name | Value | Key Type | Description |
104 // +---------+-------+----------+------------------------------------+
105 // | P-256 | 1 | EC2 | NIST P-256 also known as secp256r1 |
106 // | P-384 | 2 | EC2 | NIST P-384 also known as secp384r1 |
107 // | P-521 | 3 | EC2 | NIST P-521 also known as secp521r1 |
108 // +---------+-------+----------+------------------------------------+
109 /// Identifies this curve as SECP256R1 (X9_62_PRIME256V1 in OpenSSL)
110 SECP256R1 = 1,
111 /// Identifies this curve as SECP384R1
112 SECP384R1 = 2,
113 /// Identifies this curve as SECP521R1
114 SECP521R1 = 3,
115}
116
117impl ECDSACurve {
118 /// Returns the size in bytes of the coordinate components (x and y) for the specified curve
119 pub(crate) fn coordinate_size(&self) -> usize {
120 match self {
121 Self::SECP256R1 => 32,
122 Self::SECP384R1 => 48,
123 Self::SECP521R1 => 66,
124 }
125 }
126}
127
128impl From<&ECDSACurve> for nid::Nid {
129 fn from(c: &ECDSACurve) -> Self {
130 use ECDSACurve::*;
131 match c {
132 SECP256R1 => nid::Nid::X9_62_PRIME256V1,
133 SECP384R1 => nid::Nid::SECP384R1,
134 SECP521R1 => nid::Nid::SECP521R1,
135 }
136 }
137}
138
139/// A COSE Elliptic Curve Public Key. This is generally the provided credential
140/// that an authenticator registers, and is used to authenticate the user.
141/// You will likely never need to interact with this value, as it is part of the Credential
142/// API.
143#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
144pub struct COSEEC2Key {
145 /// The curve that this key references.
146 pub curve: ECDSACurve,
147 /// The key's public X coordinate.
148 pub x: HumanBinaryData,
149 /// The key's public Y coordinate.
150 pub y: HumanBinaryData,
151}
152
153impl TryFrom<&COSEEC2Key> for ec::EcKey<pkey::Public> {
154 type Error = openssl::error::ErrorStack;
155
156 fn try_from(k: &COSEEC2Key) -> Result<Self, Self::Error> {
157 let group = ec::EcGroup::from_curve_name((&k.curve).into())?;
158 let mut ctx = bn::BigNumContext::new()?;
159 let mut point = ec::EcPoint::new(&group)?;
160 let x = bn::BigNum::from_slice(k.x.as_slice())?;
161 let y = bn::BigNum::from_slice(k.y.as_slice())?;
162 point.set_affine_coordinates_gfp(&group, &x, &y, &mut ctx)?;
163
164 ec::EcKey::from_public_key(&group, &point)
165 }
166}
167
168/// A COSE Elliptic Curve Public Key. This is generally the provided credential
169/// that an authenticator registers, and is used to authenticate the user.
170/// You will likely never need to interact with this value, as it is part of the Credential
171/// API.
172#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
173pub struct COSEOKPKey {
174 /// The curve that this key references.
175 pub curve: EDDSACurve,
176 /// The key's public X coordinate.
177 pub x: HumanBinaryData,
178}
179
180/// A COSE RSA PublicKey. This is a provided credential from a registered
181/// authenticator.
182/// You will likely never need to interact with this value, as it is part of the Credential
183/// API.
184#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
185pub struct COSERSAKey {
186 /// An RSA modulus
187 pub n: HumanBinaryData,
188 /// An RSA exponent
189 pub e: [u8; 3],
190}
191
192/// The type of Key contained within a COSE value. You should never need
193/// to alter or change this type.
194#[allow(non_camel_case_types)]
195#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
196pub enum COSEKeyType {
197 // +-----------+-------+-----------------------------------------------+
198 // | Name | Value | Description |
199 // +-----------+-------+-----------------------------------------------+
200 // | OKP | 1 | Octet Key Pair |
201 // | EC2 | 2 | Elliptic Curve Keys w/ x- and y-coordinate |
202 // | | | pair |
203 // | Symmetric | 4 | Symmetric Keys |
204 // | Reserved | 0 | This value is reserved |
205 // +-----------+-------+-----------------------------------------------+
206 /// Identifies this as an Elliptic Curve octet key pair
207 EC_OKP(COSEOKPKey),
208 /// Identifies this as an Elliptic Curve EC2 key
209 EC_EC2(COSEEC2Key),
210 // EC_Symmetric,
211 // EC_Reserved, // should always be invalid.
212 /// Identifies this as an RSA key
213 RSA(COSERSAKey),
214}
215
216/// The numeric if of the COSEKeyType used in the CBOR fields.
217#[allow(non_camel_case_types)]
218#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
219#[repr(i64)]
220pub enum COSEKeyTypeId {
221 /// Reserved
222 EC_Reserved = 0,
223 /// Octet Key Pair
224 EC_OKP = 1,
225 /// Elliptic Curve Keys w/ x- and y-coordinate
226 EC_EC2 = 2,
227 /// RSA
228 EC_RSA = 3,
229 /// Symmetric
230 EC_Symmetric = 4,
231}
232
233/// A COSE Key as provided by the Authenticator. You should never need
234/// to alter or change these values.
235#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
236pub struct COSEKey {
237 /// The type of key that this contains
238 pub type_: COSEAlgorithm,
239 /// The public key
240 pub key: COSEKeyType,
241}
242
243/// The ID of this Credential
244pub type CredentialID = HumanBinaryData;
245
246/// The current latest Credential Format
247pub type Credential = CredentialV5;
248
249/// A user's authenticator credential. It contains an id, the public key
250/// and a counter of how many times the authenticator has been used.
251#[derive(Clone, Debug, Serialize, Deserialize)]
252pub struct CredentialV5 {
253 /// The ID of this credential.
254 pub cred_id: CredentialID,
255 /// The public key of this credential
256 pub cred: COSEKey,
257 /// The counter for this credential
258 pub counter: Counter,
259 /// The set of transports this credential indicated it could use. This is NOT
260 /// a security property, but a hint for the browser and the user experience to
261 /// how to communicate to this specific device.
262 pub transports: Option<Vec<AuthenticatorTransport>>,
263 /// During registration, if this credential was verified
264 /// then this is true. If not it is false. This is based on
265 /// the policy at the time of registration of the credential.
266 ///
267 /// This is a deviation from the Webauthn specification, because
268 /// it clarifies the user experience of the credentials to UV
269 /// being a per-credential attribute, rather than a per-authentication
270 /// ceremony attribute. For example it can be surprising to register
271 /// a credential as un-verified but then to use verification with it
272 /// in the future.
273 pub user_verified: bool,
274 /// During registration, this credential indicated that it *may* be possible
275 /// for it to exist between multiple hardware authenticators, or be backed up.
276 ///
277 /// This means the private key is NOT sealed within a hardware cryptograhic
278 /// processor, and may have impacts on your risk assessments and modeling.
279 pub backup_eligible: bool,
280 /// This credential has indicated that it is currently backed up OR that it
281 /// is shared between multiple devices.
282 pub backup_state: bool,
283 /// During registration, the policy that was requested from this
284 /// credential. This is used to understand if the how the verified
285 /// component interacts with the device, i.e. an always verified authenticator
286 /// vs one that can dynamically request it.
287 pub registration_policy: UserVerificationPolicy,
288 /// The set of extensions that were verified at registration, that can
289 /// be used in future authentication attempts
290 pub extensions: RegisteredExtensions,
291 /// The attestation certificate of this credential, including parsed metadata from the
292 /// credential.
293 pub attestation: ParsedAttestation,
294 /// the format of the attestation
295 pub attestation_format: AttestationFormat,
296}
297
298impl Credential {
299 /// Re-verify this Credential's attestation chain. This re-applies the same process
300 /// for certificate authority verification that occurred at registration. This can
301 /// be useful if you want to re-assert your credentials match an updated or changed
302 /// ca_list from the time that registration occurred. This can also be useful to
303 /// re-determine certain properties of your device that may exist.
304 pub fn verify_attestation<'a>(
305 &'_ self,
306 ca_list: &'a AttestationCaList,
307 ) -> Result<Option<&'a AttestationCa>, WebauthnError> {
308 // Formerly we disabled this due to apple, but they no longer provide
309 // meaningful attestation so we can re-enable it.
310 let danger_disable_certificate_time_checks = false;
311 verify_attestation_ca_chain(
312 &self.attestation.data,
313 ca_list,
314 danger_disable_certificate_time_checks,
315 )
316 }
317}
318
319impl From<CredentialV3> for Credential {
320 fn from(other: CredentialV3) -> Credential {
321 let CredentialV3 {
322 cred_id,
323 cred,
324 counter,
325 verified,
326 registration_policy,
327 } = other;
328
329 // prior to 20220520 no multi-device credentials existed to migrate from.
330 Credential {
331 cred_id: HumanBinaryData::from(cred_id),
332 cred,
333 counter,
334 transports: None,
335 user_verified: verified,
336 backup_eligible: false,
337 backup_state: false,
338 registration_policy,
339 extensions: RegisteredExtensions::none(),
340 attestation: ParsedAttestation {
341 data: ParsedAttestationData::None,
342 metadata: AttestationMetadata::None,
343 },
344 attestation_format: AttestationFormat::None,
345 }
346 }
347}
348
349/// A legacy serialisation from version 3 of Webauthn RS. Only useful for migrations.
350#[derive(Clone, Debug, Serialize, Deserialize)]
351pub struct CredentialV3 {
352 /// The ID of this credential.
353 pub cred_id: Vec<u8>,
354 /// The public key of this credential
355 pub cred: COSEKey,
356 /// The counter for this credential
357 pub counter: u32,
358 /// During registration, if this credential was verified
359 /// then this is true. If not it is false. This is based on
360 /// the policy at the time of registration of the credential.
361 ///
362 /// This is a deviation from the Webauthn specification, because
363 /// it clarifies the user experience of the credentials to UV
364 /// being a per-credential attribute, rather than a per-authentication
365 /// ceremony attribute. For example it can be surprising to register
366 /// a credential as un-verified but then to use verification with it
367 /// in the future.
368 pub verified: bool,
369 /// During registration, the policy that was requested from this
370 /// credential. This is used to understand if the how the verified
371 /// component interacts with the device, IE an always verified authenticator
372 /// vs one that can dynamically request it.
373 pub registration_policy: UserVerificationPolicy,
374}
375
376/// Serialised Attestation Data which can be stored in a stable database or similar.
377#[derive(Clone, Serialize, Deserialize)]
378pub enum SerialisableAttestationData {
379 /// See [ParsedAttestationData::Basic]
380 Basic(Vec<HumanBinaryData>),
381 /// See [ParsedAttestationData::Self_]
382 Self_,
383 /// See [ParsedAttestationData::AttCa]
384 AttCa(Vec<HumanBinaryData>),
385 /// See [ParsedAttestationData::AnonCa]
386 AnonCa(Vec<HumanBinaryData>),
387 /// See [ParsedAttestationData::ECDAA]
388 ECDAA,
389 /// See [ParsedAttestationData::None]
390 None,
391 /// See [ParsedAttestationData::Uncertain]
392 Uncertain,
393}
394
395impl fmt::Debug for SerialisableAttestationData {
396 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
397 match self {
398 SerialisableAttestationData::Basic(_) => {
399 write!(f, "SerialisableAttestationData::Basic")
400 }
401 SerialisableAttestationData::Self_ => write!(f, "SerialisableAttestationData::Self_"),
402 SerialisableAttestationData::AttCa(_) => {
403 write!(f, "SerialisableAttestationData::AttCa")
404 }
405 SerialisableAttestationData::AnonCa(_) => {
406 write!(f, "SerialisableAttestationData::AnonCa")
407 }
408 SerialisableAttestationData::ECDAA => write!(f, "SerialisableAttestationData::ECDAA"),
409 SerialisableAttestationData::None => write!(f, "SerialisableAttestationData::None"),
410 SerialisableAttestationData::Uncertain => {
411 write!(f, "SerialisableAttestationData::Uncertain")
412 }
413 }
414 }
415}
416
417/// The processed attestation and its metadata
418#[derive(Debug, Clone, Serialize, Deserialize)]
419pub struct ParsedAttestation {
420 /// the attestation chain data
421 pub data: ParsedAttestationData,
422 /// possible metadata (i.e. flags set) about the attestation
423 pub metadata: AttestationMetadata,
424}
425
426impl Default for ParsedAttestation {
427 fn default() -> Self {
428 ParsedAttestation {
429 data: ParsedAttestationData::None,
430 metadata: AttestationMetadata::None,
431 }
432 }
433}
434
435/// The processed Attestation that the Authenticator is providing in its AttestedCredentialData. This
436/// metadata may allow identification of the device and its specific properties.
437#[derive(Debug, Clone, Serialize, Deserialize)]
438pub enum AttestationMetadata {
439 /// no metadata available for this device.
440 None,
441 /// This is commonly found on Fido Authenticators.
442 Packed {
443 /// This is the unique id of the class/type of device. Often this id can imply the
444 /// properties of the device.
445 aaguid: Uuid,
446 },
447 /// This is found on TPM authenticators.
448 Tpm {
449 /// This is the unique id of the class/type of device. Often this id can imply the
450 /// properties of the device.
451 aaguid: Uuid,
452 /// The firmware version of the device at registration. It can NOT be determined
453 /// if this updates later, which may require you to re-register the device if
454 /// you need to enforce a version update.
455 firmware_version: u64,
456 },
457 /// various attestation flags set by the device (attested by OS)
458 AndroidKey {
459 /// is the key master running in a Trusted Execution Environment
460 is_km_tee: bool,
461 /// did the attestation come from a Trusted Execution Environment
462 is_attest_tee: bool,
463 },
464 /// various attestation flags set by the device (attested via safety-net)
465 /// <https://developer.android.com/training/safetynet/attestation#use-response-server>
466 AndroidSafetyNet {
467 /// the name of apk that originated this key operation
468 apk_package_name: String,
469 /// cert chain for this apk
470 apk_certificate_digest_sha256: Vec<HumanBinaryData>,
471 /// A stricter verdict of device integrity. If the value of ctsProfileMatch is true, then the profile of the device running your app matches the profile of a device that has passed Android compatibility testing and has been approved as a Google-certified Android device.
472 cts_profile_match: bool,
473 /// A more lenient verdict of device integrity. If only the value of basicIntegrity is true, then the device running your app likely wasn't tampered with. However, the device hasn't necessarily passed Android compatibility testing.
474 basic_integrity: bool,
475 /// Types of measurements that contributed to the current API response
476 evaluation_type: Option<String>,
477 },
478}
479
480/// The processed Attestation that the Authenticator is providing in its AttestedCredentialData
481#[derive(Debug, Clone, Serialize, Deserialize)]
482#[serde(
483 try_from = "SerialisableAttestationData",
484 into = "SerialisableAttestationData"
485)]
486pub enum ParsedAttestationData {
487 /// The credential is authenticated by a signing X509 Certificate
488 /// from a vendor or provider.
489 Basic(Vec<x509::X509>),
490 /// The credential is authenticated using surrogate basic attestation
491 /// it uses the credential private key to create the attestation signature
492 Self_,
493 /// The credential is authenticated using a CA, and may provide a
494 /// ca chain to validate to its root.
495 AttCa(Vec<x509::X509>),
496 /// The credential is authenticated using an anonymization CA, and may provide a ca chain to
497 /// validate to its root.
498 AnonCa(Vec<x509::X509>),
499 /// Unimplemented
500 ECDAA,
501 /// No Attestation type was provided with this Credential. If in doubt
502 /// reject this Credential.
503 None,
504 /// Uncertain Attestation was provided with this Credential, which may not
505 /// be trustworthy in all cases. If in doubt, reject this type.
506 Uncertain,
507}
508
509#[allow(clippy::from_over_into)]
510impl Into<SerialisableAttestationData> for ParsedAttestationData {
511 fn into(self) -> SerialisableAttestationData {
512 match self {
513 ParsedAttestationData::Basic(chain) => SerialisableAttestationData::Basic(
514 chain
515 .into_iter()
516 .map(|c| HumanBinaryData::from(c.to_der().expect("Invalid DER")))
517 .collect(),
518 ),
519 ParsedAttestationData::Self_ => SerialisableAttestationData::Self_,
520 ParsedAttestationData::AttCa(chain) => SerialisableAttestationData::AttCa(
521 // HumanBinaryData::from(c.to_der().expect("Invalid DER")),
522 chain
523 .into_iter()
524 .map(|c| HumanBinaryData::from(c.to_der().expect("Invalid DER")))
525 .collect(),
526 ),
527 ParsedAttestationData::AnonCa(chain) => SerialisableAttestationData::AnonCa(
528 // HumanBinaryData::from(c.to_der().expect("Invalid DER")),
529 chain
530 .into_iter()
531 .map(|c| HumanBinaryData::from(c.to_der().expect("Invalid DER")))
532 .collect(),
533 ),
534 ParsedAttestationData::ECDAA => SerialisableAttestationData::ECDAA,
535 ParsedAttestationData::None => SerialisableAttestationData::None,
536 ParsedAttestationData::Uncertain => SerialisableAttestationData::Uncertain,
537 }
538 }
539}
540
541impl TryFrom<SerialisableAttestationData> for ParsedAttestationData {
542 type Error = WebauthnError;
543
544 fn try_from(data: SerialisableAttestationData) -> Result<Self, Self::Error> {
545 Ok(match data {
546 SerialisableAttestationData::Basic(chain) => ParsedAttestationData::Basic(
547 chain
548 .into_iter()
549 .map(|c| {
550 x509::X509::from_der(c.as_slice()).map_err(WebauthnError::OpenSSLError)
551 })
552 .collect::<WebauthnResult<_>>()?,
553 ),
554 SerialisableAttestationData::Self_ => ParsedAttestationData::Self_,
555 SerialisableAttestationData::AttCa(chain) => ParsedAttestationData::AttCa(
556 // x509::X509::from_der(&c.0).map_err(WebauthnError::OpenSSLError)?,
557 chain
558 .into_iter()
559 .map(|c| {
560 x509::X509::from_der(c.as_slice()).map_err(WebauthnError::OpenSSLError)
561 })
562 .collect::<WebauthnResult<_>>()?,
563 ),
564 SerialisableAttestationData::AnonCa(chain) => ParsedAttestationData::AnonCa(
565 // x509::X509::from_der(&c.0).map_err(WebauthnError::OpenSSLError)?,
566 chain
567 .into_iter()
568 .map(|c| {
569 x509::X509::from_der(c.as_slice()).map_err(WebauthnError::OpenSSLError)
570 })
571 .collect::<WebauthnResult<_>>()?,
572 ),
573 SerialisableAttestationData::ECDAA => ParsedAttestationData::ECDAA,
574 SerialisableAttestationData::None => ParsedAttestationData::None,
575 SerialisableAttestationData::Uncertain => ParsedAttestationData::Uncertain,
576 })
577 }
578}
579
580/// Marker type parameter for data related to registration ceremony
581#[derive(Debug)]
582pub struct Registration;
583
584/// Marker type parameter for data related to authentication ceremony
585#[derive(Debug)]
586pub struct Authentication;
587
588/// Trait for ceremony marker structs
589pub trait Ceremony {
590 /// The type of the extension outputs of the ceremony
591 type SignedExtensions: DeserializeOwned + std::fmt::Debug + std::default::Default;
592}
593
594impl Ceremony for Registration {
595 type SignedExtensions = RegistrationSignedExtensions;
596}
597
598impl Ceremony for Authentication {
599 type SignedExtensions = AuthenticationSignedExtensions;
600}
601
602/// The client's response to the request that it use the `credProtect` extension
603///
604/// Implemented as wrapper struct to (de)serialize
605/// [CredentialProtectionPolicy] as a number
606#[derive(Debug, Serialize, Clone, Deserialize)]
607#[serde(try_from = "u8", into = "u8")]
608pub struct CredProtectResponse(pub CredentialProtectionPolicy);
609
610/// The output for registration ceremony extensions.
611///
612/// Implements the registration bits of \[AuthenticatorExtensionsClientOutputs\]
613/// from the spec
614#[derive(Debug, Clone, Serialize, Deserialize, Default)]
615pub struct RegistrationSignedExtensions {
616 /// The `credProtect` extension
617 #[serde(rename = "credProtect")]
618 pub cred_protect: Option<CredProtectResponse>,
619 /// The `hmac-secret` extension response to a create request
620 #[serde(rename = "hmac-secret")]
621 pub hmac_secret: Option<bool>,
622 /// Extension key-values that we have parsed, but don't strictly recognise.
623 #[serde(flatten)]
624 pub unknown_keys: BTreeMap<String, serde_cbor_2::Value>,
625}
626
627/// The output for authentication cermeony extensions.
628///
629/// Implements the authentication bits of
630/// \[AuthenticationExtensionsClientOutputs] from the spec
631#[derive(Debug, Clone, Serialize, Deserialize, Default)]
632#[serde(rename_all = "camelCase")]
633pub struct AuthenticationSignedExtensions {
634 /// Extension key-values that we have parsed, but don't strictly recognise.
635 #[serde(flatten)]
636 pub unknown_keys: BTreeMap<String, serde_cbor_2::Value>,
637}
638
639/// Attested Credential Data
640#[derive(Debug, Clone)]
641pub struct AttestedCredentialData {
642 /// The guid of the authenticator. May indicate manufacturer.
643 pub aaguid: Aaguid,
644 /// The credential ID.
645 pub credential_id: CredentialID,
646 /// The credentials public Key.
647 pub credential_pk: serde_cbor_2::Value,
648}
649
650/// Information about the authentication that occurred.
651#[derive(Debug, Serialize, Clone, Deserialize)]
652pub struct AuthenticationResult {
653 /// The credential ID that was used to authenticate.
654 pub(crate) cred_id: CredentialID,
655 /// If the credential associated needs updating
656 pub(crate) needs_update: bool,
657 /// If the authentication provided user_verification.
658 pub(crate) user_verified: bool,
659 /// The current backup state of the authenticator. It may have
660 /// changed since registration.
661 pub(crate) backup_state: bool,
662 /// The current backup eligibility of the authenticator. It may have
663 /// changed since registration in rare cases. This transition may ONLY
664 /// be false to true, never the reverse. This is common on passkeys
665 /// during some upgrades.
666 pub(crate) backup_eligible: bool,
667 /// The state of the counter
668 pub(crate) counter: Counter,
669 /// The response from associated extensions.
670 pub(crate) extensions: AuthenticationExtensions,
671}
672
673impl AuthenticationResult {
674 /// The credential ID that was used to authenticate.
675 pub fn cred_id(&self) -> &CredentialID {
676 &self.cred_id
677 }
678
679 /// If this authentication result should be applied to the associated
680 /// credential to update its properties.
681 pub fn needs_update(&self) -> bool {
682 self.needs_update
683 }
684
685 /// If the authentication provided user_verification.
686 pub fn user_verified(&self) -> bool {
687 self.user_verified
688 }
689
690 /// The current backup state of the authenticator. It may have
691 /// changed since registration.
692 pub fn backup_state(&self) -> bool {
693 self.backup_state
694 }
695
696 /// The current backup eligibility of the authenticator. It may have
697 /// changed since registration in rare cases. This transition may ONLY
698 /// be false to true, never the reverse. This is common on passkeys
699 /// during some upgrades.
700 pub fn backup_eligible(&self) -> bool {
701 self.backup_eligible
702 }
703
704 /// The state of the counter
705 pub fn counter(&self) -> Counter {
706 self.counter
707 }
708
709 /// The response from associated extensions.
710 pub fn extensions(&self) -> &AuthenticationExtensions {
711 &self.extensions
712 }
713}