Skip to content

Commit 6f08e12

Browse files
feat(pin): add pcmr permission and perCredMgmtRO detection
1 parent 1e84587 commit 6f08e12

2 files changed

Lines changed: 32 additions & 0 deletions

File tree

libwebauthn/src/proto/ctap2/model/client_pin.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ bitflags! {
189189
const BIO_ENROLLMENT = 0x08;
190190
const LARGE_BLOB_WRITE = 0x10;
191191
const AUTHENTICATOR_CONFIGURATION = 0x20;
192+
const PERSISTENT_CREDENTIAL_MANAGEMENT_READ_ONLY = 0x40;
192193
}
193194
}
194195

@@ -249,3 +250,17 @@ pub struct Ctap2ClientPinResponse {
249250
#[serde(index = 0x05)]
250251
pub uv_retries: Option<u32>,
251252
}
253+
254+
#[cfg(test)]
255+
mod test {
256+
use super::Ctap2AuthTokenPermissionRole;
257+
258+
#[test]
259+
fn pcmr_permission_bit() {
260+
let pcmr = Ctap2AuthTokenPermissionRole::PERSISTENT_CREDENTIAL_MANAGEMENT_READ_ONLY;
261+
// CTAP 2.3-PS section 6.5.5.7: pcmr is 0x40.
262+
assert_eq!(pcmr.bits(), 0x40);
263+
// Disjoint from every other permission, so the existing subset test isolates it.
264+
assert!(!pcmr.intersects(Ctap2AuthTokenPermissionRole::all().difference(pcmr)));
265+
}
266+
}

libwebauthn/src/proto/ctap2/model/get_info.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,11 @@ impl Ctap2GetInfoResponse {
188188
self.option_enabled("credMgmt") || self.option_enabled("credentialMgmtPreview")
189189
}
190190

191+
/// CTAP 2.2+ persistent pinUvAuthToken for read-only credential management (pcmr).
192+
pub fn supports_persistent_credential_management_read_only(&self) -> bool {
193+
self.option_enabled("perCredMgmtRO")
194+
}
195+
191196
pub fn supports_bio_enrollment(&self) -> bool {
192197
if let Some(options) = &self.options {
193198
return options.get("bioEnroll").is_some()
@@ -318,6 +323,18 @@ mod test {
318323
assert_eq!(info.uv_operation(true), None);
319324
}
320325

326+
#[test]
327+
fn per_cred_mgmt_ro_detection() {
328+
assert!(
329+
!Ctap2GetInfoResponse::default().supports_persistent_credential_management_read_only()
330+
);
331+
assert!(!create_info(&[]).supports_persistent_credential_management_read_only());
332+
assert!(!create_info(&[("perCredMgmtRO", false)])
333+
.supports_persistent_credential_management_read_only());
334+
assert!(create_info(&[("perCredMgmtRO", true)])
335+
.supports_persistent_credential_management_read_only());
336+
}
337+
321338
#[test]
322339
fn device_legacy_uv() {
323340
// Support legacy UV of CTAP2.0

0 commit comments

Comments
 (0)