# Conflicts: # src-tauri/src/commands/auth.rs
- commit
- d681500effbbddf2d91e8b81c78d764a97e584fd
- parent
- 10249dedede9b03bd68fe48156fd5ca82db1de42
- parent
- c725f1cebaca6911dd936530aa4634d9e61c0acf
- author
- Dami <dami.etoile@gmail.com>
| M | src-tauri/ | 81 | ++++++++++++++++++++++++++++-- |
@@ -85,14 +85,24 @@ pub fn derive_secret_from_key(pin: &str) -> anyhow::Result<[u8; 32]> {
8585 }8686 8787 pub fn extract_hmac_secret(assertions: &[Assertion]) -> anyhow::Result<[u8; 32]> {88- for ext in &assertions[0].extensions {89- if let Gext::HmacSecret(Some(output)) = ext {90- let mut secret = [0u8; 32];91- secret.copy_from_slice(&output[..]);92- return Ok(secret);88+ let assertion = assertions.first().context(89+ "Security key returned no assertions. Reconnect the key and try the PIN and tap again.",90+ )?;91+92+ for ext in &assertion.extensions {93+ match ext {94+ Gext::HmacSecret(Some(output)) => return Ok(*output),95+ Gext::HmacSecret2(Some(_)) => {96+ anyhow::bail!(97+ "Security key returned a two-output hmac-secret response (64 bytes); Portal requires exactly one 32-byte output. Reconnect the key or use a compatible FIDO2 key."98+ )99+ }100+ _ => {}93101 }94102 }95- anyhow::bail!("No hmac-secret in assertion response")103+ anyhow::bail!(104+ "Security key assertion did not contain hmac-secret output. Use a compatible FIDO2 key and try again."105+ )96106 }97107 98108 pub fn derive_iroh_secret_from_key(pin: &str) -> anyhow::Result<SecretKey> {@@ -253,6 +263,65 @@ pub async fn key_derive_identity(pin: String) -> KeyIdentity {
253263 mod tests {254264 use super::*;255265 266+ 267+ fn extract_hmac_secret_rejects_empty_assertion_list() {268+ let error = extract_hmac_secret(&[]).expect_err("empty assertions must fail closed");269+ assert_eq!(270+ error.to_string(),271+ "Security key returned no assertions. Reconnect the key and try the PIN and tap again."272+ );273+ }274+275+ 276+ fn extract_hmac_secret_rejects_two_output_response() {277+ let assertion = Assertion {278+ extensions: vec![Gext::HmacSecret2(Some(([0x2a; 32], [0x2b; 32])))],279+ ..Default::default()280+ };281+282+ let error =283+ extract_hmac_secret(&[assertion]).expect_err("two-output response must fail closed");284+ assert_eq!(285+ error.to_string(),286+ "Security key returned a two-output hmac-secret response (64 bytes); Portal requires exactly one 32-byte output. Reconnect the key or use a compatible FIDO2 key."287+ );288+ }289+290+ 291+ fn extract_hmac_secret_rejects_extension_without_output() {292+ let assertion = Assertion {293+ extensions: vec![Gext::HmacSecret(None)],294+ ..Default::default()295+ };296+297+ let error = extract_hmac_secret(&[assertion]).expect_err("absent output must fail closed");298+ assert_eq!(299+ error.to_string(),300+ "Security key assertion did not contain hmac-secret output. Use a compatible FIDO2 key and try again."301+ );302+ }303+304+ 305+ fn extract_hmac_secret_rejects_assertion_without_extension() {306+ let error = extract_hmac_secret(&[Assertion::default()])307+ .expect_err("missing extension must fail closed");308+ assert_eq!(309+ error.to_string(),310+ "Security key assertion did not contain hmac-secret output. Use a compatible FIDO2 key and try again."311+ );312+ }313+314+ 315+ fn extract_hmac_secret_returns_exact_output() {316+ let expected = [0x2a; 32];317+ let assertion = Assertion {318+ extensions: vec![Gext::HmacSecret(Some(expected))],319+ ..Default::default()320+ };321+322+ assert_eq!(extract_hmac_secret(&[assertion]).unwrap(), expected);323+ }324+256325 257326 fn portal_identity_compatibility_identifiers_are_golden() {258327 assert_eq!(FIDO_RP_ID, "sigil");