diff --git a/Cargo.lock b/Cargo.lock index 59aed484..da43c3c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5181,6 +5181,7 @@ dependencies = [ "url", "uuid", "webauthn-rs", + "webauthn-rs-core", "webauthn-rs-proto", "which", "yubico_ng", diff --git a/Cargo.toml b/Cargo.toml index 880d8a4d..e090901e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -125,6 +125,7 @@ yubico = { package = "yubico_ng", version = "0.13.0", features = ["online-tokio" # danger-user-presence-only-security-keys is needed to disable UV webauthn-rs = { version = "0.5.2", features = ["danger-allow-state-serialisation", "danger-credential-internals", "danger-user-presence-only-security-keys"] } webauthn-rs-proto = "0.5.2" +webauthn-rs-core = "0.5.2" # Handling of URL's for WebAuthn and favicons url = "2.5.4" diff --git a/src/db/models/two_factor.rs b/src/db/models/two_factor.rs index b71bb1af..035f88f5 100644 --- a/src/db/models/two_factor.rs +++ b/src/db/models/two_factor.rs @@ -3,6 +3,7 @@ use crate::api::core::two_factor::webauthn::WebauthnRegistration; use crate::{api::EmptyResult, db::DbConn, error::MapResult}; use serde_json::Value; use webauthn_rs::prelude::{Credential, ParsedAttestation}; +use webauthn_rs_core::proto::CredentialV3; use webauthn_rs_proto::{AttestationFormat, RegisteredExtensions}; db_object! { @@ -42,130 +43,6 @@ pub enum TwoFactorType { ProtectedActions = 2000, } -mod webauthn_0_3 { - use webauthn_rs::prelude::ParsedAttestation; - use webauthn_rs_proto::{AttestationFormat, RegisteredExtensions}; - - #[derive(Deserialize)] - pub struct WebauthnRegistration { - pub id: i32, - pub name: String, - pub migrated: bool, - pub credential: Credential, - } - - impl From for crate::api::core::two_factor::webauthn::WebauthnRegistration { - fn from(value: WebauthnRegistration) -> Self { - Self { - id: value.id, - name: value.name, - migrated: value.migrated, - credential: webauthn_rs::prelude::Credential::from(value.credential).into(), - } - } - } - - // Copied from https://docs.rs/webauthn-rs/0.3.2/src/webauthn_rs/proto.rs.html#316-339 - #[derive(Deserialize)] - pub struct Credential { - pub cred_id: Vec, - pub cred: COSEKey, - pub counter: u32, - pub verified: bool, - pub registration_policy: webauthn_rs_proto::UserVerificationPolicy, - } - - impl From for webauthn_rs::prelude::Credential { - fn from(value: Credential) -> Self { - Self { - cred_id: value.cred_id.into(), - cred: value.cred.into(), - counter: value.counter, - transports: None, - user_verified: value.verified, - backup_eligible: false, - backup_state: false, - registration_policy: value.registration_policy, - extensions: RegisteredExtensions::none(), - attestation: ParsedAttestation::default(), - attestation_format: AttestationFormat::None, - } - } - } - - // Copied from https://docs.rs/webauthn-rs/0.3.2/src/webauthn_rs/proto.rs.html#300-305 - #[derive(Deserialize)] - pub struct COSEKey { - pub type_: webauthn_rs::prelude::COSEAlgorithm, - pub key: COSEKeyType, - } - - impl From for webauthn_rs::prelude::COSEKey { - fn from(value: COSEKey) -> Self { - Self { - type_: value.type_, - key: value.key.into(), - } - } - } - - // Copied from https://docs.rs/webauthn-rs/0.3.2/src/webauthn_rs/proto.rs.html#260-278 - #[allow(non_camel_case_types)] - #[allow(clippy::upper_case_acronyms)] - #[derive(Deserialize)] - pub enum COSEKeyType { - EC_OKP, - EC_EC2(COSEEC2Key), - RSA(COSERSAKey), - } - - impl From for webauthn_rs::prelude::COSEKeyType { - fn from(value: COSEKeyType) -> Self { - match value { - COSEKeyType::EC_EC2(a) => Self::EC_EC2(a.into()), - COSEKeyType::RSA(a) => Self::RSA(a.into()), - // This should've never been able to be constructed when webauthn 0.3 was used - // Refer: https://docs.rs/webauthn-rs/0.3.2/src/webauthn_rs/crypto.rs.html#414 - COSEKeyType::EC_OKP => unreachable!(), - } - } - } - - // Copied from https://docs.rs/webauthn-rs/0.3.2/src/webauthn_rs/proto.rs.html#249-254 - #[derive(Deserialize)] - pub struct COSERSAKey { - pub n: Vec, - pub e: [u8; 3], - } - - impl From for webauthn_rs::prelude::COSERSAKey { - fn from(value: COSERSAKey) -> Self { - Self { - n: value.n.into(), - e: value.e, - } - } - } - - // Copied from https://docs.rs/webauthn-rs/0.3.2/src/webauthn_rs/proto.rs.html#235-242 - #[derive(Deserialize)] - pub struct COSEEC2Key { - pub curve: webauthn_rs::prelude::ECDSACurve, - pub x: [u8; 32], - pub y: [u8; 32], - } - - impl From for webauthn_rs::prelude::COSEEC2Key { - fn from(value: COSEEC2Key) -> Self { - Self { - curve: value.curve, - x: value.x.into(), - y: value.y.into(), - } - } - } -} - /// Local methods impl TwoFactor { pub fn new(user_uuid: UserId, atype: TwoFactorType, data: String) -> Self { @@ -365,7 +242,7 @@ impl TwoFactor { for webauthn_factor in webauthn_factors { // assume that a failure to parse into the old struct, means that it was already converted // alternatively this could also be checked via an extra field in the db - let Ok(regs) = serde_json::from_str::>(&webauthn_factor.data) + let Ok(regs) = serde_json::from_str::>(&webauthn_factor.data) else { continue; }; @@ -383,3 +260,22 @@ impl TwoFactor { #[derive(Clone, Debug, DieselNewType, FromForm, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct TwoFactorId(String); + +#[derive(Deserialize)] +pub struct WebauthnRegistrationV3 { + pub id: i32, + pub name: String, + pub migrated: bool, + pub credential: CredentialV3, +} + +impl From for WebauthnRegistration { + fn from(value: WebauthnRegistrationV3) -> Self { + Self { + id: value.id, + name: value.name, + migrated: value.migrated, + credential: Credential::from(value.credential).into(), + } + } +}