Spiegel von
https://github.com/dani-garcia/vaultwarden.git
synchronisiert 2024-11-05 02:28:00 +01:00
fix u2f migration
Dieser Commit ist enthalten in:
Ursprung
257829c6ab
Commit
035a843c71
4 geänderte Dateien mit 73 neuen und 32 gelöschten Zeilen
1
Cargo.lock
generiert
1
Cargo.lock
generiert
|
@ -4143,6 +4143,7 @@ dependencies = [
|
|||
"url",
|
||||
"uuid",
|
||||
"webauthn-rs",
|
||||
"webauthn-rs-core",
|
||||
"which",
|
||||
"yubico",
|
||||
]
|
||||
|
|
|
@ -109,7 +109,8 @@ totp-lite = "2.0.1"
|
|||
yubico = { version = "0.11.0", features = ["online-tokio"], default-features = false }
|
||||
|
||||
# WebAuthn libraries
|
||||
webauthn-rs = { version = "0.4.8", features = ["danger-allow-state-serialisation"] }
|
||||
webauthn-rs = { version = "0.4.8", features = ["danger-allow-state-serialisation", "danger-credential-internals", "resident-key-support"] }
|
||||
webauthn-rs-core = { version = "0.4.9" }
|
||||
|
||||
# Handling of URL's for WebAuthn and favicons
|
||||
url = "2.5.0"
|
||||
|
|
|
@ -22,6 +22,47 @@ pub fn routes() -> Vec<Route> {
|
|||
routes![get_webauthn, generate_webauthn_challenge, activate_webauthn, activate_webauthn_put, delete_webauthn,]
|
||||
}
|
||||
|
||||
// Some old u2f structs still needed for migrating from u2f to WebAuthn
|
||||
// Both `struct Registration` and `struct U2FRegistration` can be removed if we remove the u2f to WebAuthn migration
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Registration {
|
||||
pub key_handle: CredentialID,
|
||||
pub pub_key: Vec<u8>,
|
||||
pub attestation_cert: Option<Vec<u8>>,
|
||||
pub device_name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct U2FRegistration {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
#[serde(with = "Registration")]
|
||||
pub reg: Registration,
|
||||
pub counter: u32,
|
||||
compromised: bool,
|
||||
pub migrated: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct WebauthnRegistration {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub migrated: bool,
|
||||
|
||||
pub security_key: SecurityKey,
|
||||
}
|
||||
|
||||
impl WebauthnRegistration {
|
||||
fn to_json(&self) -> Value {
|
||||
json!({
|
||||
"Id": self.id,
|
||||
"Name": self.name,
|
||||
"migrated": self.migrated,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[post("/two-factor/get-webauthn", data = "<data>")]
|
||||
async fn get_webauthn(data: JsonUpcase<PasswordOrOtpData>, headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||
if !CONFIG.domain_set() {
|
||||
|
@ -168,11 +209,27 @@ async fn delete_webauthn(data: JsonUpcase<DeleteU2FData>, headers: Headers, mut
|
|||
None => err!("Webauthn entry not found"),
|
||||
};
|
||||
|
||||
let _removed_item = data.remove(item_pos);
|
||||
let removed_item = data.remove(item_pos);
|
||||
tf.data = serde_json::to_string(&data)?;
|
||||
tf.save(&mut conn).await?;
|
||||
drop(tf);
|
||||
|
||||
// If entry is migrated from u2f, delete the u2f entry as well
|
||||
if let Some(mut u2f) =
|
||||
TwoFactor::find_by_user_and_type(&headers.user.uuid, TwoFactorType::U2f as i32, &mut conn).await
|
||||
{
|
||||
let mut data: Vec<U2FRegistration> = match serde_json::from_str(&u2f.data) {
|
||||
Ok(d) => d,
|
||||
Err(_) => err!("Error parsing U2F data"),
|
||||
};
|
||||
|
||||
data.retain(|r| r.reg.key_handle != *removed_item.security_key.cred_id());
|
||||
let new_data_str = serde_json::to_string(&data)?;
|
||||
|
||||
u2f.data = new_data_str;
|
||||
u2f.save(&mut conn).await?;
|
||||
}
|
||||
|
||||
let keys_json: Vec<Value> = data.iter().map(WebauthnRegistration::to_json).collect();
|
||||
|
||||
Ok(Json(json!({
|
||||
|
@ -182,26 +239,7 @@ async fn delete_webauthn(data: JsonUpcase<DeleteU2FData>, headers: Headers, mut
|
|||
})))
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct WebauthnRegistration {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub migrated: bool,
|
||||
|
||||
pub security_key: SecurityKey,
|
||||
}
|
||||
|
||||
impl WebauthnRegistration {
|
||||
fn to_json(&self) -> Value {
|
||||
json!({
|
||||
"Id": self.id,
|
||||
"Name": self.name,
|
||||
"migrated": self.migrated,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_webauthn_registrations(
|
||||
pub async fn get_webauthn_registrations(
|
||||
user_uuid: &str,
|
||||
conn: &mut DbConn,
|
||||
) -> Result<(bool, Vec<WebauthnRegistration>), Error> {
|
||||
|
|
|
@ -159,7 +159,7 @@ impl TwoFactor {
|
|||
|
||||
use crate::api::core::two_factor::webauthn::U2FRegistration;
|
||||
use crate::api::core::two_factor::webauthn::{get_webauthn_registrations, WebauthnRegistration};
|
||||
use webauthn_rs::proto::*;
|
||||
use webauthn_rs_core::proto::*;
|
||||
|
||||
for mut u2f in u2f_factors {
|
||||
let mut regs: Vec<U2FRegistration> = serde_json::from_str(&u2f.data)?;
|
||||
|
@ -183,22 +183,23 @@ impl TwoFactor {
|
|||
type_: COSEAlgorithm::ES256,
|
||||
key: COSEKeyType::EC_EC2(COSEEC2Key {
|
||||
curve: ECDSACurve::SECP256R1,
|
||||
x,
|
||||
y,
|
||||
x: x.to_vec().into(),
|
||||
y: y.to_vec().into(),
|
||||
}),
|
||||
};
|
||||
|
||||
let credential = CredentialV3 {
|
||||
counter: reg.counter,
|
||||
verified: false,
|
||||
cred: key,
|
||||
cred_id: reg.reg.key_handle.clone().into(),
|
||||
registration_policy: UserVerificationPolicy::Preferred,
|
||||
};
|
||||
let new_reg = WebauthnRegistration {
|
||||
id: reg.id,
|
||||
migrated: true,
|
||||
name: reg.name.clone(),
|
||||
credential: Credential {
|
||||
counter: reg.counter,
|
||||
verified: false,
|
||||
cred: key,
|
||||
cred_id: reg.reg.key_handle.clone(),
|
||||
registration_policy: UserVerificationPolicy::Discouraged,
|
||||
},
|
||||
security_key: (Credential::from(credential).into()),
|
||||
};
|
||||
|
||||
webauthn_regs.push(new_reg);
|
||||
|
|
Laden …
In neuem Issue referenzieren