1use super::{get_info::AuthenticatorInfo, Command, CommandError, RequestCtap2, StatusCode};
2use crate::crypto::{
3 authenticate, decrypt, encapsulate, encrypt, BackendError, COSEKey, CryptoError, ECDHSecret,
4};
5use crate::transport::errors::HIDError;
6use crate::u2ftypes::U2FDevice;
7use serde::{
8 de::{Error as SerdeError, MapAccess, Visitor},
9 ser::SerializeMap,
10 Deserialize, Deserializer, Serialize, Serializer,
11};
12use serde_bytes::ByteBuf;
13use serde_cbor::de::from_slice;
14use serde_cbor::ser::to_vec;
15use serde_cbor::Value;
16use sha2::{Digest, Sha256};
17use std::error::Error as StdErrorT;
18use std::fmt;
19
20#[derive(Debug, Copy, Clone)]
23#[repr(u8)]
24pub enum PINSubcommand {
25 GetRetries = 0x01,
26 GetKeyAgreement = 0x02,
27 SetPIN = 0x03,
28 ChangePIN = 0x04,
29 GetPINToken = 0x05,
30}
31
32#[derive(Debug)]
33pub struct ClientPIN {
34 pin_protocol: Option<u8>,
35 subcommand: PINSubcommand,
36 key_agreement: Option<COSEKey>,
37 pin_auth: Option<PinAuth>,
38 new_pin_enc: Option<ByteBuf>,
39 pin_hash_enc: Option<ByteBuf>,
40}
41
42impl Default for ClientPIN {
43 fn default() -> Self {
44 ClientPIN {
45 pin_protocol: None,
46 subcommand: PINSubcommand::GetRetries,
47 key_agreement: None,
48 pin_auth: None,
49 new_pin_enc: None,
50 pin_hash_enc: None,
51 }
52 }
53}
54
55impl Serialize for ClientPIN {
56 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
57 where
58 S: Serializer,
59 {
60 let mut map_len = 1;
63 if self.pin_protocol.is_some() {
64 map_len += 1;
65 }
66 if self.key_agreement.is_some() {
67 map_len += 1;
68 }
69 if self.pin_auth.is_some() {
70 map_len += 1;
71 }
72 if self.new_pin_enc.is_some() {
73 map_len += 1;
74 }
75 if self.pin_hash_enc.is_some() {
76 map_len += 1;
77 }
78
79 let mut map = serializer.serialize_map(Some(map_len))?;
80 if let Some(ref pin_protocol) = self.pin_protocol {
81 map.serialize_entry(&1, pin_protocol)?;
82 }
83 let command: u8 = self.subcommand as u8;
84 map.serialize_entry(&2, &command)?;
85 if let Some(ref key_agreement) = self.key_agreement {
86 map.serialize_entry(&3, key_agreement)?;
87 }
88 if let Some(ref pin_auth) = self.pin_auth {
89 map.serialize_entry(&4, &ByteBuf::from(pin_auth.as_ref()))?;
90 }
91 if let Some(ref new_pin_enc) = self.new_pin_enc {
92 map.serialize_entry(&5, new_pin_enc)?;
93 }
94 if let Some(ref pin_hash_enc) = self.pin_hash_enc {
95 map.serialize_entry(&6, pin_hash_enc)?;
96 }
97
98 map.end()
99 }
100}
101
102pub trait ClientPINSubCommand {
103 type Output;
104 fn as_client_pin(&self) -> Result<ClientPIN, CommandError>;
105 fn parse_response_payload(&self, input: &[u8]) -> Result<Self::Output, CommandError>;
106}
107
108struct ClientPinResponse {
109 key_agreement: Option<COSEKey>,
110 pin_token: Option<EncryptedPinToken>,
111 retries: Option<u8>,
113}
114
115impl<'de> Deserialize<'de> for ClientPinResponse {
116 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
117 where
118 D: Deserializer<'de>,
119 {
120 struct ClientPinResponseVisitor;
121
122 impl<'de> Visitor<'de> for ClientPinResponseVisitor {
123 type Value = ClientPinResponse;
124
125 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
126 formatter.write_str("a map")
127 }
128
129 fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
130 where
131 M: MapAccess<'de>,
132 {
133 let mut key_agreement = None;
134 let mut pin_token = None;
135 let mut retries = None;
136 while let Some(key) = map.next_key()? {
137 match key {
138 1 => {
139 if key_agreement.is_some() {
140 return Err(SerdeError::duplicate_field("key_agreement"));
141 }
142 key_agreement = map.next_value()?;
143 }
144 2 => {
145 if pin_token.is_some() {
146 return Err(SerdeError::duplicate_field("pin_token"));
147 }
148 pin_token = map.next_value()?;
149 }
150 3 => {
151 if retries.is_some() {
152 return Err(SerdeError::duplicate_field("retries"));
153 }
154 retries = Some(map.next_value()?);
155 }
156 k => return Err(M::Error::custom(format!("unexpected key: {:?}", k))),
157 }
158 }
159 Ok(ClientPinResponse {
160 key_agreement,
161 pin_token,
162 retries,
163 })
164 }
165 }
166 deserializer.deserialize_bytes(ClientPinResponseVisitor)
167 }
168}
169
170#[derive(Debug)]
171pub struct GetKeyAgreement {
172 pin_protocol: u8,
173}
174
175impl GetKeyAgreement {
176 pub fn new(info: &AuthenticatorInfo) -> Result<Self, CommandError> {
177 if info.pin_protocols.contains(&1) {
178 Ok(GetKeyAgreement { pin_protocol: 1 })
179 } else {
180 Err(CommandError::UnsupportedPinProtocol)
181 }
182 }
183}
184
185impl ClientPINSubCommand for GetKeyAgreement {
186 type Output = KeyAgreement;
187
188 fn as_client_pin(&self) -> Result<ClientPIN, CommandError> {
189 Ok(ClientPIN {
190 pin_protocol: Some(self.pin_protocol),
191 subcommand: PINSubcommand::GetKeyAgreement,
192 ..ClientPIN::default()
193 })
194 }
195
196 fn parse_response_payload(&self, input: &[u8]) -> Result<Self::Output, CommandError> {
197 let value: Value = from_slice(input).map_err(CommandError::Deserializing)?;
198 debug!("GetKeyAgreement::parse_response_payload {:?}", value);
199
200 let get_pin_response: ClientPinResponse =
201 from_slice(input).map_err(CommandError::Deserializing)?;
202 if let Some(key_agreement) = get_pin_response.key_agreement {
203 Ok(KeyAgreement(key_agreement))
204 } else {
205 Err(CommandError::MissingRequiredField("key_agreement"))
206 }
207 }
208}
209
210#[derive(Debug)]
211pub struct GetPinToken<'sc, 'pin> {
212 pin_protocol: u8,
213 shared_secret: &'sc ECDHSecret,
214 pin: &'pin Pin,
215}
216
217impl<'sc, 'pin> GetPinToken<'sc, 'pin> {
218 pub fn new(
219 info: &AuthenticatorInfo,
220 shared_secret: &'sc ECDHSecret,
221 pin: &'pin Pin,
222 ) -> Result<Self, CommandError> {
223 if info.pin_protocols.contains(&1) {
224 Ok(GetPinToken {
225 pin_protocol: 1,
226 shared_secret,
227 pin,
228 })
229 } else {
230 Err(CommandError::UnsupportedPinProtocol)
231 }
232 }
233}
234
235impl<'sc, 'pin> ClientPINSubCommand for GetPinToken<'sc, 'pin> {
236 type Output = PinToken;
237
238 fn as_client_pin(&self) -> Result<ClientPIN, CommandError> {
239 let input = self.pin.for_pin_token();
240 trace!("pin_hash = {:#04X?}", &input.as_ref());
241 let pin_hash_enc = encrypt(self.shared_secret.shared_secret(), input.as_ref())
242 .map_err(|e| CryptoError::Backend(e))?;
243 trace!("pin_hash_enc = {:#04X?}", &pin_hash_enc);
244
245 Ok(ClientPIN {
246 pin_protocol: Some(self.pin_protocol),
247 subcommand: PINSubcommand::GetPINToken,
248 key_agreement: Some(self.shared_secret.my_public_key().clone()),
249 pin_hash_enc: Some(ByteBuf::from(pin_hash_enc)),
250 ..ClientPIN::default()
251 })
252 }
253
254 fn parse_response_payload(&self, input: &[u8]) -> Result<Self::Output, CommandError> {
255 let value: Value = from_slice(input).map_err(CommandError::Deserializing)?;
256 debug!("GetKeyAgreement::parse_response_payload {:?}", value);
257
258 let get_pin_response: ClientPinResponse =
259 from_slice(input).map_err(CommandError::Deserializing)?;
260 match get_pin_response.pin_token {
261 Some(encrypted_pin_token) => {
262 let pin_token = decrypt(
263 self.shared_secret.shared_secret(),
264 encrypted_pin_token.as_ref(),
265 )
266 .map_err(|e| CryptoError::Backend(e))?;
267 let pin_token = PinToken(pin_token);
268 Ok(pin_token)
269 }
270 None => Err(CommandError::MissingRequiredField("key_agreement")),
271 }
272 }
273}
274
275#[derive(Debug)]
276pub struct GetRetries {}
277
278impl GetRetries {
279 pub fn new() -> Self {
280 GetRetries {}
281 }
282}
283
284impl ClientPINSubCommand for GetRetries {
285 type Output = u8;
286
287 fn as_client_pin(&self) -> Result<ClientPIN, CommandError> {
288 Ok(ClientPIN {
289 subcommand: PINSubcommand::GetRetries,
290 ..ClientPIN::default()
291 })
292 }
293
294 fn parse_response_payload(&self, input: &[u8]) -> Result<Self::Output, CommandError> {
295 let value: Value = from_slice(input).map_err(CommandError::Deserializing)?;
296 debug!("GetKeyAgreement::parse_response_payload {:?}", value);
297
298 let get_pin_response: ClientPinResponse =
299 from_slice(input).map_err(CommandError::Deserializing)?;
300 match get_pin_response.retries {
301 Some(retries) => Ok(retries),
302 None => Err(CommandError::MissingRequiredField("retries")),
303 }
304 }
305}
306
307#[derive(Debug)]
308pub struct SetNewPin<'sc, 'pin> {
309 pin_protocol: u8,
310 shared_secret: &'sc ECDHSecret,
311 new_pin: &'pin Pin,
312}
313
314impl<'sc, 'pin> SetNewPin<'sc, 'pin> {
315 pub fn new(
316 info: &AuthenticatorInfo,
317 shared_secret: &'sc ECDHSecret,
318 new_pin: &'pin Pin,
319 ) -> Result<Self, CommandError> {
320 if info.pin_protocols.contains(&1) {
321 Ok(SetNewPin {
322 pin_protocol: 1,
323 shared_secret,
324 new_pin,
325 })
326 } else {
327 Err(CommandError::UnsupportedPinProtocol)
328 }
329 }
330}
331
332impl<'sc, 'pin> ClientPINSubCommand for SetNewPin<'sc, 'pin> {
333 type Output = ();
334
335 fn as_client_pin(&self) -> Result<ClientPIN, CommandError> {
336 if self.new_pin.as_bytes().len() > 63 {
337 return Err(CommandError::StatusCode(
338 StatusCode::PinPolicyViolation,
339 None,
340 ));
341 }
342 let input: Vec<u8> = self
344 .new_pin
345 .as_bytes()
346 .iter()
347 .chain(std::iter::repeat(&0x00))
348 .take(64)
349 .cloned()
350 .collect();
351
352 let shared_secret = self.shared_secret.shared_secret();
353 let new_pin_enc =
355 encrypt(shared_secret, input.as_ref()).map_err(|e| CryptoError::Backend(e))?;
356
357 let pin_auth = PinToken(shared_secret.to_vec())
359 .auth(&new_pin_enc)
360 .map_err(CommandError::Crypto)?;
361
362 Ok(ClientPIN {
363 pin_protocol: Some(self.pin_protocol),
364 subcommand: PINSubcommand::SetPIN,
365 key_agreement: Some(self.shared_secret.my_public_key().clone()),
366 new_pin_enc: Some(ByteBuf::from(new_pin_enc)),
367 pin_auth: Some(pin_auth),
368 ..ClientPIN::default()
369 })
370 }
371
372 fn parse_response_payload(&self, input: &[u8]) -> Result<Self::Output, CommandError> {
373 if input.is_empty() {
375 Ok(())
376 } else {
377 let _: Value = from_slice(input).map_err(CommandError::Deserializing)?;
378 Ok(())
379 }
380 }
381}
382
383#[derive(Debug)]
384pub struct ChangeExistingPin<'sc, 'pin> {
385 pin_protocol: u8,
386 shared_secret: &'sc ECDHSecret,
387 current_pin: &'pin Pin,
388 new_pin: &'pin Pin,
389}
390
391impl<'sc, 'pin> ChangeExistingPin<'sc, 'pin> {
392 pub fn new(
393 info: &AuthenticatorInfo,
394 shared_secret: &'sc ECDHSecret,
395 current_pin: &'pin Pin,
396 new_pin: &'pin Pin,
397 ) -> Result<Self, CommandError> {
398 if info.pin_protocols.contains(&1) {
399 Ok(ChangeExistingPin {
400 pin_protocol: 1,
401 shared_secret,
402 current_pin,
403 new_pin,
404 })
405 } else {
406 Err(CommandError::UnsupportedPinProtocol)
407 }
408 }
409}
410
411impl<'sc, 'pin> ClientPINSubCommand for ChangeExistingPin<'sc, 'pin> {
412 type Output = ();
413
414 fn as_client_pin(&self) -> Result<ClientPIN, CommandError> {
415 if self.new_pin.as_bytes().len() > 63 {
416 return Err(CommandError::StatusCode(
417 StatusCode::PinPolicyViolation,
418 None,
419 ));
420 }
421 let input: Vec<u8> = self
423 .new_pin
424 .as_bytes()
425 .iter()
426 .chain(std::iter::repeat(&0x00))
427 .take(64)
428 .cloned()
429 .collect();
430
431 let shared_secret = self.shared_secret.shared_secret();
432 let new_pin_enc =
434 encrypt(shared_secret, input.as_ref()).map_err(|e| CryptoError::Backend(e))?;
435
436 let input = self.current_pin.for_pin_token();
438 let pin_hash_enc = encrypt(self.shared_secret.shared_secret(), input.as_ref())
439 .map_err(|e| CryptoError::Backend(e))?;
440
441 let pin_auth = PinToken(shared_secret.to_vec())
443 .auth(&[new_pin_enc.as_slice(), pin_hash_enc.as_slice()].concat())
444 .map_err(CommandError::Crypto)?;
445
446 Ok(ClientPIN {
447 pin_protocol: Some(self.pin_protocol),
448 subcommand: PINSubcommand::ChangePIN,
449 key_agreement: Some(self.shared_secret.my_public_key().clone()),
450 new_pin_enc: Some(ByteBuf::from(new_pin_enc)),
451 pin_hash_enc: Some(ByteBuf::from(pin_hash_enc)),
452 pin_auth: Some(pin_auth),
453 })
454 }
455
456 fn parse_response_payload(&self, input: &[u8]) -> Result<Self::Output, CommandError> {
457 if input.is_empty() {
459 Ok(())
460 } else {
461 let _: Value = from_slice(input).map_err(CommandError::Deserializing)?;
462 Ok(())
463 }
464 }
465}
466
467impl<T> RequestCtap2 for T
468where
469 T: ClientPINSubCommand,
470 T: fmt::Debug,
471{
472 type Output = <T as ClientPINSubCommand>::Output;
473
474 fn command() -> Command {
475 Command::ClientPin
476 }
477
478 fn wire_format<Dev>(&self, _dev: &mut Dev) -> Result<Vec<u8>, HIDError>
479 where
480 Dev: U2FDevice,
481 {
482 let client_pin = self.as_client_pin()?;
483 let output = to_vec(&client_pin).map_err(CommandError::Serializing)?;
484 trace!("client subcommmand: {:04X?}", &output);
485
486 Ok(output)
487 }
488
489 fn handle_response_ctap2<Dev>(
490 &self,
491 _dev: &mut Dev,
492 input: &[u8],
493 ) -> Result<Self::Output, HIDError>
494 where
495 Dev: U2FDevice,
496 {
497 trace!("Client pin subcomand response:{:04X?}", &input);
498 if input.is_empty() {
499 return Err(CommandError::InputTooSmall.into());
500 }
501
502 let status: StatusCode = input[0].into();
503 debug!("response status code: {:?}", status);
504 if status.is_ok() {
505 let res = <T as ClientPINSubCommand>::parse_response_payload(self, &input[1..])
506 .map_err(HIDError::Command);
507 res
508 } else {
509 let add_data = if input.len() > 1 {
510 let data: Value = from_slice(&input[1..]).map_err(CommandError::Deserializing)?;
511 Some(data)
512 } else {
513 None
514 };
515 Err(CommandError::StatusCode(status, add_data).into())
516 }
517 }
518}
519
520#[derive(Debug)]
521pub struct KeyAgreement(COSEKey);
522
523impl KeyAgreement {
524 pub fn shared_secret(&self) -> Result<ECDHSecret, CommandError> {
525 encapsulate(&self.0).map_err(|e| CommandError::Crypto(CryptoError::Backend(e)))
526 }
527}
528
529#[derive(Debug, Deserialize)]
530pub struct EncryptedPinToken(ByteBuf);
531
532impl AsRef<[u8]> for EncryptedPinToken {
533 fn as_ref(&self) -> &[u8] {
534 self.0.as_ref()
535 }
536}
537
538#[derive(Debug)]
539pub struct PinToken(Vec<u8>);
540
541impl PinToken {
542 pub fn auth(&self, payload: &[u8]) -> Result<PinAuth, CryptoError> {
543 let hmac = authenticate(self.as_ref(), payload)?;
544
545 let mut out = [0u8; 16];
546 out.copy_from_slice(&hmac[0..16]);
547
548 Ok(PinAuth(out.to_vec()))
549 }
550}
551
552impl AsRef<[u8]> for PinToken {
553 fn as_ref(&self) -> &[u8] {
554 self.0.as_ref()
555 }
556}
557
558#[derive(Debug, Clone)]
559#[cfg_attr(test, derive(Deserialize))]
560pub struct PinAuth(Vec<u8>);
561
562impl PinAuth {
563 pub(crate) fn empty_pin_auth() -> Self {
564 PinAuth(vec![])
565 }
566}
567
568impl AsRef<[u8]> for PinAuth {
569 fn as_ref(&self) -> &[u8] {
570 &self.0
571 }
572}
573
574impl Serialize for PinAuth {
575 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
576 where
577 S: Serializer,
578 {
579 serde_bytes::serialize(&self.0[..], serializer)
580 }
581}
582
583#[derive(Clone)]
584pub struct Pin(String);
585
586impl fmt::Debug for Pin {
587 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
588 write!(f, "Pin(redacted)")
589 }
590}
591
592impl Pin {
593 pub fn new(value: &str) -> Pin {
594 Pin(String::from(value))
595 }
596
597 pub fn for_pin_token(&self) -> PinAuth {
598 let mut hasher = Sha256::new();
599 hasher.update(&self.0.as_bytes());
600
601 let mut output = [0u8; 16];
602 let len = output.len();
603 output.copy_from_slice(&hasher.finalize().as_slice()[..len]);
604
605 PinAuth(output.to_vec())
606 }
607
608 pub fn as_bytes(&self) -> &[u8] {
609 self.0.as_bytes()
610 }
611}
612
613#[derive(Clone, Debug, Serialize)]
614pub enum PinError {
615 PinRequired,
616 PinIsTooShort,
617 PinIsTooLong(usize),
618 InvalidKeyLen,
619 InvalidPin(Option<u8>),
620 PinAuthBlocked,
621 PinBlocked,
622 Backend(BackendError),
623}
624
625impl fmt::Display for PinError {
626 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
627 match *self {
628 PinError::PinRequired => write!(f, "PinError: Pin required."),
629 PinError::PinIsTooShort => write!(f, "PinError: pin is too short"),
630 PinError::PinIsTooLong(len) => write!(f, "PinError: pin is too long ({})", len),
631 PinError::InvalidKeyLen => write!(f, "PinError: invalid key len"),
632 PinError::InvalidPin(ref e) => {
633 let mut res = write!(f, "PinError: Invalid Pin.");
634 if let Some(retries) = e {
635 res = write!(f, " Retries left: {:?}", retries)
636 }
637 res
638 }
639 PinError::PinAuthBlocked => write!(
640 f,
641 "PinError: Pin authentication blocked. Device needs power cycle."
642 ),
643 PinError::PinBlocked => write!(
644 f,
645 "PinError: No retries left. Pin blocked. Device needs reset."
646 ),
647 PinError::Backend(ref e) => write!(f, "PinError: Crypto backend error: {:?}", e),
648 }
649 }
650}
651
652impl StdErrorT for PinError {}
653
654impl From<BackendError> for PinError {
655 fn from(e: BackendError) -> Self {
656 PinError::Backend(e)
657 }
658}