1
0
Fork 1
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:
Stefan Melmuk 2024-04-22 21:00:28 +02:00
Ursprung 257829c6ab
Commit 035a843c71
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 817020C608FE9C09
4 geänderte Dateien mit 73 neuen und 32 gelöschten Zeilen

1
Cargo.lock generiert
Datei anzeigen

@ -4143,6 +4143,7 @@ dependencies = [
"url",
"uuid",
"webauthn-rs",
"webauthn-rs-core",
"which",
"yubico",
]

Datei anzeigen

@ -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"

Datei anzeigen

@ -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> {

Datei anzeigen

@ -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);