Skip to content

Commit 012daa7

Browse files
Web IDL support 2/N: drop HMAC from WebAuthn ops
1 parent 69794ff commit 012daa7

File tree

7 files changed

+144
-141
lines changed

7 files changed

+144
-141
lines changed

libwebauthn/examples/prf_test.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ use tokio::sync::broadcast::Receiver;
1313
use tracing_subscriber::{self, EnvFilter};
1414

1515
use libwebauthn::ops::webauthn::{
16-
GetAssertionHmacOrPrfInput, GetAssertionRequest, GetAssertionRequestExtensions, PRFValue,
17-
PrfInput, UserVerificationRequirement,
16+
GetAssertionRequest, GetAssertionRequestExtensions, PRFValue, PrfInput,
17+
UserVerificationRequirement,
1818
};
1919
use libwebauthn::pin::PinRequestReason;
2020
use libwebauthn::proto::ctap2::{Ctap2PublicKeyCredentialDescriptor, Ctap2PublicKeyCredentialType};
@@ -126,16 +126,16 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
126126
});
127127

128128
let eval_by_credential = HashMap::new();
129-
let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput {
129+
let prf = PrfInput {
130130
eval,
131131
eval_by_credential,
132-
});
132+
};
133133

134134
run_success_test(
135135
&mut channel,
136136
&credential,
137137
&challenge,
138-
hmac_or_prf,
138+
prf,
139139
"PRF output: ",
140140
)
141141
.await;
@@ -147,7 +147,7 @@ async fn run_success_test(
147147
channel: &mut HidChannel<'_>,
148148
credential: &Ctap2PublicKeyCredentialDescriptor,
149149
challenge: &[u8; 32],
150-
hmac_or_prf: GetAssertionHmacOrPrfInput,
150+
prf: PrfInput,
151151
printoutput: &str,
152152
) {
153153
let get_assertion = GetAssertionRequest {
@@ -156,7 +156,7 @@ async fn run_success_test(
156156
allow: vec![credential.clone()],
157157
user_verification: UserVerificationRequirement::Preferred,
158158
extensions: Some(GetAssertionRequestExtensions {
159-
hmac_or_prf: Some(hmac_or_prf),
159+
prf: Some(prf),
160160
..Default::default()
161161
}),
162162
timeout: TIMEOUT,

libwebauthn/examples/webauthn_extensions_hid.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ use tokio::sync::broadcast::Receiver;
1010
use tracing_subscriber::{self, EnvFilter};
1111

1212
use libwebauthn::ops::webauthn::{
13-
CredentialProtectionExtension, CredentialProtectionPolicy, GetAssertionHmacOrPrfInput,
14-
GetAssertionRequest, GetAssertionRequestExtensions, HMACGetSecretInput, MakeCredentialRequest,
15-
MakeCredentialsRequestExtensions, ResidentKeyRequirement, UserVerificationRequirement,
13+
CredentialProtectionExtension, CredentialProtectionPolicy, GetAssertionRequest,
14+
GetAssertionRequestExtensions, MakeCredentialRequest, MakeCredentialsRequestExtensions,
15+
PRFValue, PrfInput, ResidentKeyRequirement, UserVerificationRequirement,
1616
};
1717
use libwebauthn::pin::PinRequestReason;
1818
use libwebauthn::proto::ctap2::{
@@ -149,12 +149,13 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
149149
user_verification: UserVerificationRequirement::Discouraged,
150150
extensions: Some(GetAssertionRequestExtensions {
151151
cred_blob: true,
152-
hmac_or_prf: Some(GetAssertionHmacOrPrfInput::HmacGetSecret(
153-
HMACGetSecretInput {
154-
salt1: [1; 32],
155-
salt2: None,
156-
},
157-
)),
152+
prf: Some(PrfInput {
153+
eval: Some(PRFValue {
154+
first: [1; 32],
155+
second: None,
156+
}),
157+
eval_by_credential: std::collections::HashMap::new(),
158+
}),
158159
..Default::default()
159160
}),
160161
timeout: TIMEOUT,

libwebauthn/examples/webauthn_prf_hid.rs

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ use tokio::sync::broadcast::Receiver;
1212
use tracing_subscriber::{self, EnvFilter};
1313

1414
use libwebauthn::ops::webauthn::{
15-
GetAssertionHmacOrPrfInput, GetAssertionRequest, GetAssertionRequestExtensions,
16-
MakeCredentialPrfInput, MakeCredentialRequest, MakeCredentialsRequestExtensions, PRFValue,
17-
PrfInput, ResidentKeyRequirement, UserVerificationRequirement,
15+
GetAssertionRequest, GetAssertionRequestExtensions, MakeCredentialPrfInput,
16+
MakeCredentialRequest, MakeCredentialsRequestExtensions, PRFValue, PrfInput,
17+
ResidentKeyRequirement, UserVerificationRequirement,
1818
};
1919
use libwebauthn::pin::PinRequestReason;
2020
use libwebauthn::proto::ctap2::{
@@ -148,15 +148,15 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
148148
second: None,
149149
},
150150
);
151-
let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput {
151+
let prf = PrfInput {
152152
eval,
153153
eval_by_credential,
154-
});
154+
};
155155
run_success_test(
156156
&mut channel,
157157
&credential,
158158
&challenge,
159-
hmac_or_prf,
159+
prf,
160160
"eval_by_credential only",
161161
)
162162
.await;
@@ -175,15 +175,15 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
175175
second: None,
176176
},
177177
);
178-
let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput {
178+
let prf = PrfInput {
179179
eval,
180180
eval_by_credential,
181-
});
181+
};
182182
run_success_test(
183183
&mut channel,
184184
&credential,
185185
&challenge,
186-
hmac_or_prf,
186+
prf,
187187
"eval and eval_by_credential",
188188
)
189189
.await;
@@ -195,15 +195,15 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
195195
});
196196

197197
let eval_by_credential = HashMap::new();
198-
let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput {
198+
let prf = PrfInput {
199199
eval,
200200
eval_by_credential,
201-
});
201+
};
202202
run_success_test(
203203
&mut channel,
204204
&credential,
205205
&challenge,
206-
hmac_or_prf,
206+
prf,
207207
"eval only",
208208
)
209209
.await;
@@ -243,15 +243,15 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
243243
second: None,
244244
},
245245
);
246-
let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput {
246+
let prf = PrfInput {
247247
eval,
248248
eval_by_credential,
249-
});
249+
};
250250
run_success_test(
251251
&mut channel,
252252
&credential,
253253
&challenge,
254-
hmac_or_prf,
254+
prf,
255255
"eval and full list of eval_by_credential",
256256
)
257257
.await;
@@ -284,15 +284,15 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
284284
second: Some([8; 32]),
285285
},
286286
);
287-
let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput {
287+
let prf = PrfInput {
288288
eval,
289289
eval_by_credential,
290-
});
290+
};
291291
run_success_test(
292292
&mut channel,
293293
&credential,
294294
&challenge,
295-
hmac_or_prf,
295+
prf,
296296
"eval and non-fitting list of eval_by_credential",
297297
)
298298
.await;
@@ -322,15 +322,15 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
322322
second: Some([8; 32]),
323323
},
324324
);
325-
let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput {
325+
let prf = PrfInput {
326326
eval,
327327
eval_by_credential,
328-
});
328+
};
329329
run_success_test(
330330
&mut channel,
331331
&credential,
332332
&challenge,
333-
hmac_or_prf,
333+
prf,
334334
"No eval and non-fitting list of eval_by_credential (should have no extension output)",
335335
)
336336
.await;
@@ -349,15 +349,15 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
349349
second: None,
350350
},
351351
);
352-
let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput {
352+
let prf = PrfInput {
353353
eval,
354354
eval_by_credential,
355-
});
355+
};
356356
run_failed_test(
357357
&mut channel,
358358
Some(&credential),
359359
&challenge,
360-
hmac_or_prf,
360+
prf,
361361
"Wrongly encoded credential_id",
362362
WebAuthnError::Platform(PlatformError::SyntaxError),
363363
)
@@ -373,15 +373,15 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
373373
second: None,
374374
},
375375
);
376-
let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput {
376+
let prf = PrfInput {
377377
eval,
378378
eval_by_credential,
379-
});
379+
};
380380
run_failed_test(
381381
&mut channel,
382382
Some(&credential),
383383
&challenge,
384-
hmac_or_prf,
384+
prf,
385385
"Empty credential_id",
386386
WebAuthnError::Platform(PlatformError::SyntaxError),
387387
)
@@ -397,15 +397,15 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
397397
second: None,
398398
},
399399
);
400-
let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput {
400+
let prf = PrfInput {
401401
eval,
402402
eval_by_credential,
403-
});
403+
};
404404
run_failed_test(
405405
&mut channel,
406406
None,
407407
&challenge,
408-
hmac_or_prf,
408+
prf,
409409
"Empty allow_list, set eval_by_credential",
410410
WebAuthnError::Platform(PlatformError::NotSupported),
411411
)
@@ -418,7 +418,7 @@ async fn run_success_test(
418418
channel: &mut HidChannel<'_>,
419419
credential: &Ctap2PublicKeyCredentialDescriptor,
420420
challenge: &[u8; 32],
421-
hmac_or_prf: GetAssertionHmacOrPrfInput,
421+
prf: PrfInput,
422422
printoutput: &str,
423423
) {
424424
let get_assertion = GetAssertionRequest {
@@ -427,7 +427,7 @@ async fn run_success_test(
427427
allow: vec![credential.clone()],
428428
user_verification: UserVerificationRequirement::Discouraged,
429429
extensions: Some(GetAssertionRequestExtensions {
430-
hmac_or_prf: Some(hmac_or_prf),
430+
prf: Some(prf),
431431
..Default::default()
432432
}),
433433
timeout: TIMEOUT,
@@ -444,7 +444,7 @@ async fn run_success_test(
444444
break Err(WebAuthnError::Ctap(ctap_error));
445445
}
446446
Err(err) => break Err(err),
447-
};
447+
}
448448
}
449449
.unwrap();
450450
for (num, assertion) in response.assertions.iter().enumerate() {
@@ -459,7 +459,7 @@ async fn run_failed_test(
459459
channel: &mut HidChannel<'_>,
460460
credential: Option<&Ctap2PublicKeyCredentialDescriptor>,
461461
challenge: &[u8; 32],
462-
hmac_or_prf: GetAssertionHmacOrPrfInput,
462+
prf: PrfInput,
463463
printoutput: &str,
464464
expected_error: WebAuthnError,
465465
) {
@@ -469,7 +469,7 @@ async fn run_failed_test(
469469
allow: credential.map(|x| vec![x.clone()]).unwrap_or_default(),
470470
user_verification: UserVerificationRequirement::Discouraged,
471471
extensions: Some(GetAssertionRequestExtensions {
472-
hmac_or_prf: Some(hmac_or_prf),
472+
prf: Some(prf),
473473
..Default::default()
474474
}),
475475
timeout: TIMEOUT,
@@ -486,7 +486,7 @@ async fn run_failed_test(
486486
break Err(WebAuthnError::Ctap(ctap_error));
487487
}
488488
Err(err) => break Err(err),
489-
};
489+
}
490490
};
491491

492492
assert_eq!(response, Err(expected_error), "{printoutput}:");

libwebauthn/src/ops/webauthn/get_assertion.rs

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -81,18 +81,11 @@ impl FromInnerModel<PublicKeyCredentialRequestOptionsJSON, GetAssertionRequestPa
8181
rpid: &RelyingPartyId,
8282
inner: PublicKeyCredentialRequestOptionsJSON,
8383
) -> Result<Self, GetAssertionRequestParsingError> {
84-
let hmac_or_prf = match inner.extensions.clone() {
85-
Some(ext) => {
86-
if let Some(prf) = ext.prf {
87-
let prf_input = PrfInput::try_from(prf)?;
88-
Some(GetAssertionHmacOrPrfInput::Prf(prf_input))
89-
} else if let Some(hmac) = ext.hmac_get_secret {
90-
let hmac_input = HMACGetSecretInput::try_from(hmac)?;
91-
Some(GetAssertionHmacOrPrfInput::HmacGetSecret(hmac_input))
92-
} else {
93-
None
94-
}
95-
}
84+
let prf = match inner.extensions.as_ref() {
85+
Some(ext) => match &ext.prf {
86+
Some(prf_json) => Some(PrfInput::try_from(prf_json.clone())?),
87+
None => None,
88+
},
9689
None => None,
9790
};
9891

@@ -106,7 +99,7 @@ impl FromInnerModel<PublicKeyCredentialRequestOptionsJSON, GetAssertionRequestPa
10699
.large_blob
107100
.clone()
108101
.and_then(|lb| GetAssertionLargeBlobExtension::try_from(lb).ok()),
109-
hmac_or_prf: hmac_or_prf.clone(),
102+
prf: prf.clone(),
110103
});
111104

112105
let timeout: Duration = inner
@@ -137,8 +130,11 @@ impl FromInnerModel<PublicKeyCredentialRequestOptionsJSON, GetAssertionRequestPa
137130
}
138131
}
139132

133+
/// Internal enum for CTAP-level HMAC/PRF handling.
134+
/// At WebAuthn level, only PRF is exposed. This enum is used internally
135+
/// to support both PRF (WebAuthn) and raw HMAC (CTAP testing).
140136
#[derive(Debug, Clone, PartialEq)]
141-
pub enum GetAssertionHmacOrPrfInput {
137+
pub(crate) enum GetAssertionHmacOrPrfInput {
142138
HmacGetSecret(HMACGetSecretInput),
143139
Prf(PrfInput),
144140
}
@@ -279,7 +275,8 @@ pub struct GetAssertionLargeBlobExtensionOutput {
279275
#[derive(Debug, Default, Clone, PartialEq)]
280276
pub struct GetAssertionRequestExtensions {
281277
pub cred_blob: bool,
282-
pub hmac_or_prf: Option<GetAssertionHmacOrPrfInput>,
278+
/// PRF extension input. At the CTAP level, this is converted to HMAC secret.
279+
pub prf: Option<PrfInput>,
283280
pub large_blob: Option<GetAssertionLargeBlobExtension>,
284281
}
285282

@@ -570,11 +567,11 @@ mod tests {
570567

571568
let req: GetAssertionRequest = GetAssertionRequest::from_json(&rpid, &req_json).unwrap();
572569
if let Some(GetAssertionRequestExtensions {
573-
hmac_or_prf:
574-
Some(GetAssertionHmacOrPrfInput::Prf(PrfInput {
570+
prf:
571+
Some(PrfInput {
575572
eval: Some(ref prf_value),
576573
..
577-
})),
574+
}),
578575
..
579576
}) = &req.extensions
580577
{

0 commit comments

Comments
 (0)