Skip to content

Commit 393f160

Browse files
authored
Fix #68: Implement legacy preview (#70)
1 parent 5f0e51e commit 393f160

File tree

13 files changed

+119
-23
lines changed

13 files changed

+119
-23
lines changed

libwebauthn/examples/bio_enrollment_hid.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,15 @@ impl Display for Operation {
4646

4747
fn get_supported_options(info: &Ctap2GetInfoResponse) -> Vec<Operation> {
4848
let mut configure_ops = vec![];
49-
if let Some(options) = &info.options {
50-
if options.get("bioEnroll").is_some() {
51-
configure_ops.push(Operation::GetModality);
52-
configure_ops.push(Operation::GetFingerprintSensorInfo);
53-
if options.get("bioEnroll") == Some(&true) {
54-
configure_ops.push(Operation::EnumerateEnrollments);
55-
configure_ops.push(Operation::RemoveEnrollment);
56-
configure_ops.push(Operation::RenameEnrollment);
57-
}
58-
configure_ops.push(Operation::AddNewEnrollment);
49+
if info.supports_bio_enrollment() {
50+
configure_ops.push(Operation::GetModality);
51+
configure_ops.push(Operation::GetFingerprintSensorInfo);
52+
if info.has_bio_enrollments() {
53+
configure_ops.push(Operation::EnumerateEnrollments);
54+
configure_ops.push(Operation::RemoveEnrollment);
55+
configure_ops.push(Operation::RenameEnrollment);
5956
}
57+
configure_ops.push(Operation::AddNewEnrollment);
6058
}
6159
configure_ops
6260
}
@@ -155,7 +153,7 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
155153
};
156154
println!("Which enrollment do you want to remove?");
157155
for (id, enrollment) in enrollments.iter().enumerate() {
158-
println!("{id} {enrollment:?}")
156+
println!("({id}) {enrollment:?}")
159157
}
160158
let idx = ask_for_user_input(enrollments.len());
161159
channel
@@ -186,7 +184,7 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
186184
};
187185
println!("Which enrollment do you want to rename?");
188186
for (id, enrollment) in enrollments.iter().enumerate() {
189-
println!("{id} {enrollment:?}")
187+
println!("({id}) {enrollment:?}")
190188
}
191189
let idx = ask_for_user_input(enrollments.len());
192190
print!("New name: ");

libwebauthn/examples/cred_management.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,9 @@ pub async fn main() -> Result<(), WebAuthnError> {
133133
let mut channel = device.channel().await?;
134134
let info = channel.ctap2_get_info().await?;
135135

136-
if let Some(options) = &info.options {
137-
if options.get("credMgmt") != Some(&true) {
138-
println!("Your token does not support credential management.");
139-
return Err(WebAuthnError::Ctap(CtapError::InvalidCommand));
140-
}
136+
if !info.supports_credential_management() {
137+
println!("Your token does not support credential management.");
138+
return Err(WebAuthnError::Ctap(CtapError::InvalidCommand));
141139
}
142140

143141
let options = [

libwebauthn/src/management/authenticator_config.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,4 +223,8 @@ impl Ctap2UserVerifiableRequest for Ctap2AuthenticatorConfigRequest {
223223
fn can_use_uv(&self, info: &Ctap2GetInfoResponse) -> bool {
224224
info.option_enabled("uvAcfg")
225225
}
226+
227+
fn handle_legacy_preview(&mut self, _info: &Ctap2GetInfoResponse) {
228+
// No-op
229+
}
226230
}

libwebauthn/src/management/bio_enrollment.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ pub trait BioEnrollment {
7070
pub struct Ctap2BioEnrollmentFingerprintSensorInfo {
7171
pub fingerprint_kind: Ctap2BioEnrollmentFingerprintKind,
7272
pub max_capture_samples_required_for_enroll: Option<u64>,
73+
/// Not returned/supported by BioEnrollmentPreview
7374
pub max_template_friendly_name: Option<u64>,
7475
}
7576

@@ -333,4 +334,17 @@ impl Ctap2UserVerifiableRequest for Ctap2BioEnrollmentRequest {
333334
fn can_use_uv(&self, info: &Ctap2GetInfoResponse) -> bool {
334335
info.option_enabled("uvBioEnroll")
335336
}
337+
338+
fn handle_legacy_preview(&mut self, info: &Ctap2GetInfoResponse) {
339+
if let Some(options) = &info.options {
340+
// According to Spec, we would also need to verify the token only
341+
// supports FIDO_2_1_PRE, but let's be a bit less strict here and
342+
// accept it simply reporting preview-support, but not the real one.
343+
if options.get("bioEnroll") != Some(&true)
344+
&& options.get("userVerificationMgmtPreview") == Some(&true)
345+
{
346+
self.use_legacy_preview = true;
347+
}
348+
}
349+
}
336350
}

libwebauthn/src/management/credential_management.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ where
185185
resp.credential_id.unwrap(),
186186
resp.public_key.unwrap(),
187187
resp.cred_protect.unwrap(),
188-
resp.large_blob_key.unwrap(),
188+
resp.large_blob_key.map(|x| x.into_vec()),
189189
);
190190
let total_creds = resp.total_credentials.unwrap();
191191
Ok((cred, total_creds))
@@ -219,7 +219,7 @@ where
219219
resp.credential_id.unwrap(),
220220
resp.public_key.unwrap(),
221221
resp.cred_protect.unwrap(),
222-
resp.large_blob_key.unwrap(),
222+
resp.large_blob_key.map(|x| x.into_vec()),
223223
);
224224
Ok(cred)
225225
}
@@ -270,6 +270,11 @@ where
270270
)
271271
.await?;
272272

273+
// Preview mode does not support "updateUserInfo" subcommand
274+
if req.use_legacy_preview {
275+
return Err(Error::Ctap(CtapError::InvalidCommand));
276+
}
277+
273278
// On success, this is an all-empty Ctap2AuthenticatorConfigResponse
274279
handle_errors!(
275280
self,
@@ -317,4 +322,17 @@ impl Ctap2UserVerifiableRequest for Ctap2CredentialManagementRequest {
317322
fn can_use_uv(&self, _info: &Ctap2GetInfoResponse) -> bool {
318323
true
319324
}
325+
326+
fn handle_legacy_preview(&mut self, info: &Ctap2GetInfoResponse) {
327+
if let Some(options) = &info.options {
328+
// According to Spec, we would also need to verify the token only
329+
// supports FIDO_2_1_PRE, but let's be a bit less strict here and
330+
// accept it simply reporting preview-support, but not the real one.
331+
if options.get("credMgmt") != Some(&true)
332+
&& options.get("credentialMgmtPreview") == Some(&true)
333+
{
334+
self.use_legacy_preview = true;
335+
}
336+
}
337+
}
320338
}

libwebauthn/src/proto/ctap2/cbor/request.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,27 @@ impl From<&Ctap2AuthenticatorConfigRequest> for CborRequest {
7777

7878
impl From<&Ctap2BioEnrollmentRequest> for CborRequest {
7979
fn from(request: &Ctap2BioEnrollmentRequest) -> CborRequest {
80+
let command = if request.use_legacy_preview {
81+
Ctap2CommandCode::AuthenticatorBioEnrollmentPreview
82+
} else {
83+
Ctap2CommandCode::AuthenticatorBioEnrollment
84+
};
8085
CborRequest {
81-
command: Ctap2CommandCode::AuthenticatorBioEnrollment,
86+
command,
8287
encoded_data: to_vec(request).unwrap(),
8388
}
8489
}
8590
}
8691

8792
impl From<&Ctap2CredentialManagementRequest> for CborRequest {
8893
fn from(request: &Ctap2CredentialManagementRequest) -> CborRequest {
94+
let command = if request.use_legacy_preview {
95+
Ctap2CommandCode::AuthenticatorCredentialManagementPreview
96+
} else {
97+
Ctap2CommandCode::AuthenticatorCredentialManagement
98+
};
8999
CborRequest {
90-
command: Ctap2CommandCode::AuthenticatorCredentialManagement,
100+
command,
91101
encoded_data: to_vec(request).unwrap(),
92102
}
93103
}

libwebauthn/src/proto/ctap2/model.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ pub enum Ctap2CommandCode {
4949
AuthenticatorClientPin = 0x06,
5050
AuthenticatorGetNextAssertion = 0x08,
5151
AuthenticatorBioEnrollment = 0x09,
52+
AuthenticatorBioEnrollmentPreview = 0x40,
5253
AuthenticatorCredentialManagement = 0x0A,
54+
AuthenticatorCredentialManagementPreview = 0x41,
5355
AuthenticatorSelection = 0x0B,
5456
AuthenticatorConfig = 0x0D,
5557
}
@@ -198,6 +200,7 @@ pub trait Ctap2UserVerifiableRequest {
198200
fn permissions(&self) -> Ctap2AuthTokenPermissionRole;
199201
fn permissions_rpid(&self) -> Option<&str>;
200202
fn can_use_uv(&self, info: &Ctap2GetInfoResponse) -> bool;
203+
fn handle_legacy_preview(&mut self, info: &Ctap2GetInfoResponse);
201204
}
202205

203206
#[derive(Debug, Clone, Copy)]

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ pub struct Ctap2BioEnrollmentRequest {
3636
#[serde(default)]
3737
#[serde(skip_serializing_if = "Option::is_none")]
3838
pub get_modality: Option<bool>,
39+
40+
#[serde(skip)]
41+
pub use_legacy_preview: bool,
3942
}
4043

4144
#[repr(u32)]
@@ -166,6 +169,7 @@ impl Ctap2BioEnrollmentRequest {
166169
protocol: None, // Get's filled in later
167170
uv_auth_param: None, // Get's filled in later
168171
get_modality: Some(true),
172+
use_legacy_preview: false,
169173
}
170174
}
171175

@@ -177,6 +181,7 @@ impl Ctap2BioEnrollmentRequest {
177181
protocol: None, // Get's filled in later
178182
uv_auth_param: None, // Get's filled in later
179183
get_modality: None,
184+
use_legacy_preview: false,
180185
}
181186
}
182187

@@ -188,6 +193,7 @@ impl Ctap2BioEnrollmentRequest {
188193
protocol: None, // Get's filled in later
189194
uv_auth_param: None, // Get's filled in later
190195
get_modality: None,
196+
use_legacy_preview: false,
191197
}
192198
}
193199

@@ -203,6 +209,7 @@ impl Ctap2BioEnrollmentRequest {
203209
protocol: None, // Get's filled in later
204210
uv_auth_param: None, // Get's filled in later
205211
get_modality: None,
212+
use_legacy_preview: false,
206213
}
207214
}
208215

@@ -218,6 +225,7 @@ impl Ctap2BioEnrollmentRequest {
218225
protocol: None, // Get's filled in later
219226
uv_auth_param: None, // Get's filled in later
220227
get_modality: None,
228+
use_legacy_preview: false,
221229
}
222230
}
223231

@@ -239,6 +247,7 @@ impl Ctap2BioEnrollmentRequest {
239247
protocol: None, // Get's filled in later
240248
uv_auth_param: None, // Get's filled in later
241249
get_modality: None,
250+
use_legacy_preview: false,
242251
}
243252
}
244253

@@ -256,6 +265,7 @@ impl Ctap2BioEnrollmentRequest {
256265
protocol: None,
257266
uv_auth_param: None,
258267
get_modality: None,
268+
use_legacy_preview: false,
259269
}
260270
}
261271

@@ -267,6 +277,7 @@ impl Ctap2BioEnrollmentRequest {
267277
protocol: None,
268278
uv_auth_param: None,
269279
get_modality: None,
280+
use_legacy_preview: false,
270281
}
271282
}
272283
}

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ pub struct Ctap2CredentialManagementRequest {
2929
#[serde(default)]
3030
#[serde(skip_serializing_if = "Option::is_none")]
3131
pub uv_auth_param: Option<ByteBuf>,
32+
33+
#[serde(skip)]
34+
pub use_legacy_preview: bool,
3235
}
3336

3437
#[repr(u32)]
@@ -128,6 +131,7 @@ impl Ctap2CredentialManagementRequest {
128131
subcommand_params: None,
129132
protocol: None,
130133
uv_auth_param: None,
134+
use_legacy_preview: false,
131135
}
132136
}
133137

@@ -137,6 +141,7 @@ impl Ctap2CredentialManagementRequest {
137141
subcommand_params: None,
138142
protocol: None,
139143
uv_auth_param: None,
144+
use_legacy_preview: false,
140145
}
141146
}
142147

@@ -146,6 +151,7 @@ impl Ctap2CredentialManagementRequest {
146151
subcommand_params: None,
147152
protocol: None,
148153
uv_auth_param: None,
154+
use_legacy_preview: false,
149155
}
150156
}
151157

@@ -159,6 +165,7 @@ impl Ctap2CredentialManagementRequest {
159165
}),
160166
protocol: None,
161167
uv_auth_param: None,
168+
use_legacy_preview: false,
162169
}
163170
}
164171

@@ -170,6 +177,7 @@ impl Ctap2CredentialManagementRequest {
170177
subcommand_params: None,
171178
protocol: None,
172179
uv_auth_param: None,
180+
use_legacy_preview: false,
173181
}
174182
}
175183

@@ -183,6 +191,7 @@ impl Ctap2CredentialManagementRequest {
183191
}),
184192
protocol: None,
185193
uv_auth_param: None,
194+
use_legacy_preview: false,
186195
}
187196
}
188197

@@ -199,6 +208,7 @@ impl Ctap2CredentialManagementRequest {
199208
}),
200209
protocol: None,
201210
uv_auth_param: None,
211+
use_legacy_preview: false,
202212
}
203213
}
204214
}
@@ -227,7 +237,8 @@ pub struct Ctap2CredentialData {
227237
pub credential_id: Ctap2PublicKeyCredentialDescriptor,
228238
pub public_key: PublicKey,
229239
pub cred_protect: u64,
230-
pub large_blob_key: ByteBuf,
240+
/// This is not there in the Preview mode
241+
pub large_blob_key: Option<Vec<u8>>,
231242
}
232243

233244
impl Ctap2CredentialData {
@@ -236,7 +247,7 @@ impl Ctap2CredentialData {
236247
credential_id: Ctap2PublicKeyCredentialDescriptor,
237248
public_key: PublicKey,
238249
cred_protect: u64,
239-
large_blob_key: ByteBuf,
250+
large_blob_key: Option<Vec<u8>>,
240251
) -> Self {
241252
Self {
242253
user,

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,4 +201,8 @@ impl Ctap2UserVerifiableRequest for Ctap2GetAssertionRequest {
201201
fn can_use_uv(&self, _info: &Ctap2GetInfoResponse) -> bool {
202202
true
203203
}
204+
205+
fn handle_legacy_preview(&mut self, _info: &Ctap2GetInfoResponse) {
206+
// No-op
207+
}
204208
}

0 commit comments

Comments
 (0)