Skip to content

Commit e918b1c

Browse files
Merge pull request #57 from msirringhaus/save_puat
* Add possibility to cache pinUvAuthToken in PinProvider * Implement review feedback
2 parents c3c1c5e + 6efb938 commit e918b1c

File tree

10 files changed

+327
-101
lines changed

10 files changed

+327
-101
lines changed

libwebauthn/src/management.rs

Lines changed: 86 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
use serde_cbor::ser::to_vec;
22
use std::time::Duration;
3+
use tracing::info;
34

45
use crate::pin::{PinProvider, PinUvAuthProtocol};
56
use crate::proto::ctap2::Ctap2AuthenticatorConfigCommand;
67
pub use crate::transport::error::{CtapError, Error, TransportError};
78
use crate::transport::Channel;
8-
use crate::webauthn::user_verification;
9+
use crate::webauthn::handle_errors;
10+
use crate::webauthn::{user_verification, UsedPinUvAuthToken};
911
use crate::{
1012
ops::webauthn::UserVerificationRequirement,
1113
proto::ctap2::{
12-
ClientPinRequestPermissions, Ctap2, Ctap2AuthenticatorConfigRequest,
14+
Ctap2, Ctap2AuthTokenPermissionRole, Ctap2AuthenticatorConfigRequest,
1315
Ctap2UserVerifiableRequest,
1416
},
1517
};
@@ -64,17 +66,22 @@ where
6466
) -> Result<(), Error> {
6567
let mut req = Ctap2AuthenticatorConfigRequest::new_toggle_always_uv();
6668

67-
user_verification(
68-
self,
69-
UserVerificationRequirement::Required,
70-
&mut req,
71-
pin_provider,
72-
timeout,
73-
)
74-
.await?;
75-
76-
// On success, this is an all-empty Ctap2ClientPinResponse
77-
self.ctap2_authenticator_config(&req, timeout).await
69+
loop {
70+
let uv_auth_used = user_verification(
71+
self,
72+
UserVerificationRequirement::Required,
73+
&mut req,
74+
pin_provider,
75+
timeout,
76+
)
77+
.await?;
78+
// On success, this is an all-empty Ctap2AuthenticatorConfigResponse
79+
handle_errors!(
80+
self,
81+
self.ctap2_authenticator_config(&req, timeout).await,
82+
uv_auth_used
83+
)
84+
}
7885
}
7986

8087
async fn enable_enterprise_attestation(
@@ -84,17 +91,22 @@ where
8491
) -> Result<(), Error> {
8592
let mut req = Ctap2AuthenticatorConfigRequest::new_enable_enterprise_attestation();
8693

87-
user_verification(
88-
self,
89-
UserVerificationRequirement::Required,
90-
&mut req,
91-
pin_provider,
92-
timeout,
93-
)
94-
.await?;
95-
96-
// On success, this is an all-empty Ctap2ClientPinResponse
97-
self.ctap2_authenticator_config(&req, timeout).await
94+
loop {
95+
let uv_auth_used = user_verification(
96+
self,
97+
UserVerificationRequirement::Required,
98+
&mut req,
99+
pin_provider,
100+
timeout,
101+
)
102+
.await?;
103+
// On success, this is an all-empty Ctap2AuthenticatorConfigResponse
104+
handle_errors!(
105+
self,
106+
self.ctap2_authenticator_config(&req, timeout).await,
107+
uv_auth_used
108+
)
109+
}
98110
}
99111

100112
async fn set_min_pin_length(
@@ -105,17 +117,22 @@ where
105117
) -> Result<(), Error> {
106118
let mut req = Ctap2AuthenticatorConfigRequest::new_set_min_pin_length(new_pin_length);
107119

108-
user_verification(
109-
self,
110-
UserVerificationRequirement::Required,
111-
&mut req,
112-
pin_provider,
113-
timeout,
114-
)
115-
.await?;
116-
117-
// On success, this is an all-empty Ctap2ClientPinResponse
118-
self.ctap2_authenticator_config(&req, timeout).await
120+
loop {
121+
let uv_auth_used = user_verification(
122+
self,
123+
UserVerificationRequirement::Required,
124+
&mut req,
125+
pin_provider,
126+
timeout,
127+
)
128+
.await?;
129+
// On success, this is an all-empty Ctap2AuthenticatorConfigResponse
130+
handle_errors!(
131+
self,
132+
self.ctap2_authenticator_config(&req, timeout).await,
133+
uv_auth_used
134+
)
135+
}
119136
}
120137

121138
async fn force_change_pin(
@@ -126,17 +143,22 @@ where
126143
) -> Result<(), Error> {
127144
let mut req = Ctap2AuthenticatorConfigRequest::new_force_change_pin(force);
128145

129-
user_verification(
130-
self,
131-
UserVerificationRequirement::Required,
132-
&mut req,
133-
pin_provider,
134-
timeout,
135-
)
136-
.await?;
137-
138-
// On success, this is an all-empty Ctap2ClientPinResponse
139-
self.ctap2_authenticator_config(&req, timeout).await
146+
loop {
147+
let uv_auth_used = user_verification(
148+
self,
149+
UserVerificationRequirement::Required,
150+
&mut req,
151+
pin_provider,
152+
timeout,
153+
)
154+
.await?;
155+
// On success, this is an all-empty Ctap2AuthenticatorConfigResponse
156+
handle_errors!(
157+
self,
158+
self.ctap2_authenticator_config(&req, timeout).await,
159+
uv_auth_used
160+
)
161+
}
140162
}
141163

142164
async fn set_min_pin_length_rpids(
@@ -146,18 +168,22 @@ where
146168
timeout: Duration,
147169
) -> Result<(), Error> {
148170
let mut req = Ctap2AuthenticatorConfigRequest::new_set_min_pin_length_rpids(rpids);
149-
150-
user_verification(
151-
self,
152-
UserVerificationRequirement::Required,
153-
&mut req,
154-
pin_provider,
155-
timeout,
156-
)
157-
.await?;
158-
159-
// On success, this is an all-empty Ctap2ClientPinResponse
160-
self.ctap2_authenticator_config(&req, timeout).await
171+
loop {
172+
let uv_auth_used = user_verification(
173+
self,
174+
UserVerificationRequirement::Required,
175+
&mut req,
176+
pin_provider,
177+
timeout,
178+
)
179+
.await?;
180+
// On success, this is an all-empty Ctap2AuthenticatorConfigResponse
181+
handle_errors!(
182+
self,
183+
self.ctap2_authenticator_config(&req, timeout).await,
184+
uv_auth_used
185+
)
186+
}
161187
}
162188
}
163189

@@ -188,8 +214,8 @@ impl Ctap2UserVerifiableRequest for Ctap2AuthenticatorConfigRequest {
188214
unreachable!()
189215
}
190216

191-
fn permissions(&self) -> ClientPinRequestPermissions {
192-
return ClientPinRequestPermissions::AUTHENTICATOR_CONFIGURATION;
217+
fn permissions(&self) -> Ctap2AuthTokenPermissionRole {
218+
return Ctap2AuthTokenPermissionRole::AUTHENTICATOR_CONFIGURATION;
193219
}
194220

195221
fn permissions_rpid(&self) -> Option<&str> {

libwebauthn/src/proto/ctap2/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ mod protocol;
77

88
pub use model::Ctap2GetInfoResponse;
99
pub use model::{
10-
ClientPinRequestPermissions, Ctap2AttestationStatement, Ctap2COSEAlgorithmIdentifier,
10+
Ctap2AuthTokenPermissionRole, Ctap2AttestationStatement, Ctap2COSEAlgorithmIdentifier,
1111
Ctap2ClientPinRequest, Ctap2CommandCode, Ctap2CredentialType, Ctap2MakeCredentialOptions,
1212
Ctap2PinUvAuthProtocol, Ctap2PublicKeyCredentialDescriptor, Ctap2PublicKeyCredentialRpEntity,
1313
Ctap2PublicKeyCredentialType, Ctap2PublicKeyCredentialUserEntity, Ctap2Transport,

libwebauthn/src/proto/ctap2/model.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ pub trait Ctap2UserVerifiableRequest {
478478
uv_auth_token: &[u8],
479479
);
480480
fn client_data_hash(&self) -> &[u8];
481-
fn permissions(&self) -> ClientPinRequestPermissions;
481+
fn permissions(&self) -> Ctap2AuthTokenPermissionRole;
482482
fn permissions_rpid(&self) -> Option<&str>;
483483
}
484484

@@ -506,10 +506,10 @@ impl Ctap2UserVerifiableRequest for Ctap2MakeCredentialRequest {
506506
self.hash.as_slice()
507507
}
508508

509-
fn permissions(&self) -> ClientPinRequestPermissions {
509+
fn permissions(&self) -> Ctap2AuthTokenPermissionRole {
510510
// GET_ASSERTION needed for pre-flight requests
511-
return ClientPinRequestPermissions::MAKE_CREDENTIAL
512-
| ClientPinRequestPermissions::GET_ASSERTION;
511+
return Ctap2AuthTokenPermissionRole::MAKE_CREDENTIAL
512+
| Ctap2AuthTokenPermissionRole::GET_ASSERTION;
513513
}
514514

515515
fn permissions_rpid(&self) -> Option<&str> {
@@ -539,8 +539,8 @@ impl Ctap2UserVerifiableRequest for Ctap2GetAssertionRequest {
539539
self.client_data_hash.as_slice()
540540
}
541541

542-
fn permissions(&self) -> ClientPinRequestPermissions {
543-
return ClientPinRequestPermissions::GET_ASSERTION;
542+
fn permissions(&self) -> Ctap2AuthTokenPermissionRole {
543+
return Ctap2AuthTokenPermissionRole::GET_ASSERTION;
544544
}
545545

546546
fn permissions_rpid(&self) -> Option<&str> {
@@ -801,7 +801,7 @@ impl Ctap2ClientPinRequest {
801801
protocol: Ctap2PinUvAuthProtocol,
802802
public_key: PublicKey,
803803
pin_hash_enc: &[u8],
804-
permissions: ClientPinRequestPermissions,
804+
permissions: Ctap2AuthTokenPermissionRole,
805805
permissions_rpid: Option<&str>,
806806
) -> Self {
807807
Self {
@@ -821,7 +821,7 @@ impl Ctap2ClientPinRequest {
821821
pub fn new_get_uv_token_with_perm(
822822
protocol: Ctap2PinUvAuthProtocol,
823823
public_key: PublicKey,
824-
permissions: ClientPinRequestPermissions,
824+
permissions: Ctap2AuthTokenPermissionRole,
825825
permissions_rpid: Option<&str>,
826826
) -> Self {
827827
Self {
@@ -881,7 +881,8 @@ impl Ctap2ClientPinRequest {
881881
}
882882

883883
bitflags! {
884-
pub struct ClientPinRequestPermissions: u32 {
884+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
885+
pub struct Ctap2AuthTokenPermissionRole: u32 {
885886
const MAKE_CREDENTIAL = 0x01;
886887
const GET_ASSERTION = 0x02;
887888
const CREDENTIAL_MANAGEMENT = 0x04;
@@ -892,7 +893,7 @@ bitflags! {
892893
}
893894

894895
#[repr(u32)]
895-
#[derive(Debug, Clone, Copy, FromPrimitive, PartialEq, Serialize_repr, Deserialize_repr)]
896+
#[derive(Debug, Clone, Copy, FromPrimitive, PartialEq, Eq, Serialize_repr, Deserialize_repr)]
896897
pub enum Ctap2PinUvAuthProtocol {
897898
One = 1,
898899
Two = 2,

libwebauthn/src/proto/ctap2/protocol.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ where
9797
trace!(?request);
9898
self.cbor_send(&request.into(), TIMEOUT_GET_INFO).await?;
9999
let cbor_response = self.cbor_recv(TIMEOUT_GET_INFO).await?;
100+
match cbor_response.status_code {
101+
CtapError::Ok => (),
102+
error => return Err(Error::Ctap(error)),
103+
};
100104
let ctap_response: Ctap2GetAssertionResponse =
101105
from_slice(&cbor_response.data.unwrap()).unwrap();
102106
debug!("CTAP2 GetAssertion successful");

libwebauthn/src/transport/ble/channel.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ use crate::proto::ctap1::apdu::{ApduRequest, ApduResponse};
77
use crate::proto::ctap2::cbor::{CborRequest, CborResponse};
88
use crate::proto::CtapError;
99
use crate::transport::ble::bluez;
10-
use crate::transport::channel::{Channel, ChannelStatus};
10+
use crate::transport::channel::{
11+
Channel, ChannelStatus, Ctap2AuthTokenPermission, Ctap2AuthTokenStore,
12+
};
1113
use crate::transport::device::SupportedProtocols;
1214
use crate::transport::error::{Error, TransportError};
1315

@@ -25,6 +27,7 @@ pub struct BleChannel<'a> {
2527
device: &'a BleDevice,
2628
connection: Connection,
2729
revision: FidoRevision,
30+
auth_token: Option<(Ctap2AuthTokenPermission, Vec<u8>)>,
2831
}
2932

3033
impl<'a> BleChannel<'a> {
@@ -43,6 +46,7 @@ impl<'a> BleChannel<'a> {
4346
device,
4447
connection,
4548
revision,
49+
auth_token: None,
4650
};
4751
bluez::notify_start(&channel.connection)
4852
.await
@@ -153,3 +157,26 @@ impl<'a> Channel for BleChannel<'a> {
153157
Ok(cbor_response)
154158
}
155159
}
160+
161+
impl Ctap2AuthTokenStore for BleChannel<'_> {
162+
fn store_uv_auth_token(
163+
&mut self,
164+
permission: Ctap2AuthTokenPermission,
165+
pin_uv_auth_token: &[u8],
166+
) {
167+
self.auth_token = Some((permission, pin_uv_auth_token.to_vec()));
168+
}
169+
170+
fn get_uv_auth_token(&self, requested_permission: &Ctap2AuthTokenPermission) -> Option<&[u8]> {
171+
if let Some((stored_permission, stored_token)) = &self.auth_token {
172+
if stored_permission.contains(requested_permission) {
173+
return Some(stored_token);
174+
}
175+
}
176+
None
177+
}
178+
179+
fn clear_uv_auth_token_store(&mut self) {
180+
self.auth_token = None;
181+
}
182+
}

libwebauthn/src/transport/cable/channel.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ use crate::proto::{
1111
ctap2::cbor::{CborRequest, CborResponse},
1212
};
1313
use crate::transport::error::{Error, TransportError};
14-
use crate::transport::{channel::ChannelStatus, device::SupportedProtocols, Channel};
14+
use crate::transport::{
15+
channel::ChannelStatus, device::SupportedProtocols, Channel, Ctap2AuthTokenPermission,
16+
Ctap2AuthTokenStore,
17+
};
1518

1619
use super::known_devices::CableKnownDevice;
1720
use super::qr_code_device::CableQrCodeDevice;
@@ -85,3 +88,18 @@ impl<'d> Channel for CableChannel<'d> {
8588
.ok_or(Error::Transport(TransportError::TransportUnavailable))
8689
}
8790
}
91+
92+
impl<'d> Ctap2AuthTokenStore for CableChannel<'d> {
93+
fn store_uv_auth_token(
94+
&mut self,
95+
_permission: Ctap2AuthTokenPermission,
96+
_pin_uv_auth_token: &[u8],
97+
) {
98+
}
99+
100+
fn get_uv_auth_token(&self, _requested_permission: &Ctap2AuthTokenPermission) -> Option<&[u8]> {
101+
None
102+
}
103+
104+
fn clear_uv_auth_token_store(&mut self) {}
105+
}

0 commit comments

Comments
 (0)