1use crate::errors::AuthenticatorError;
6use crate::{ctap2::commands::CommandError, transport::errors::HIDError};
7use serde::{
8 de::{Error as SerdeError, MapAccess, Unexpected, Visitor},
9 ser::SerializeMap,
10 Deserialize, Deserializer, Serialize, Serializer,
11};
12use serde_bytes::ByteBuf;
13use serde_cbor::Value;
14use std::convert::TryFrom;
15use std::fmt;
16
17cfg_if::cfg_if! {
18 if #[cfg(feature = "crypto_ring")] {
19 #[path = "ring.rs"]
20 pub mod imp;
21 } else if #[cfg(feature = "crypto_openssl")] {
22 #[path = "openssl.rs"]
23 pub mod imp;
24 } else if #[cfg(feature = "crypto_dummy")] {
25 #[path = "dummy.rs"]
26 pub mod imp;
27 } else {
28 #[path = "nss.rs"]
29 pub mod imp;
30 }
31}
32
33pub(crate) use imp::{authenticate, decrypt, encapsulate, encrypt, serialize_key, BackendError};
34
35#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
38pub enum ECDSACurve {
39 SECP256R1 = 1,
52 SECP384R1 = 2,
54 SECP521R1 = 3,
56 X25519 = 4,
58 X448 = 5,
60 Ed25519 = 6,
62 Ed448 = 7,
64}
65
66impl TryFrom<u64> for ECDSACurve {
67 type Error = CryptoError;
68 fn try_from(i: u64) -> Result<Self, Self::Error> {
69 match i {
70 1 => Ok(ECDSACurve::SECP256R1),
71 2 => Ok(ECDSACurve::SECP384R1),
72 3 => Ok(ECDSACurve::SECP521R1),
73 4 => Ok(ECDSACurve::X25519),
74 5 => Ok(ECDSACurve::X448),
75 6 => Ok(ECDSACurve::Ed25519),
76 7 => Ok(ECDSACurve::Ed448),
77 _ => Err(CryptoError::UnknownKeyType),
78 }
79 }
80}
81#[allow(non_camel_case_types)]
85#[derive(Copy, Clone, Debug, PartialEq, Eq)]
86pub enum COSEAlgorithm {
87 INSECURE_RS1 = -65535, RS512 = -259, RS384 = -258, RS256 = -257, ES256K = -47, HSS_LMS = -46, SHAKE256 = -45, SHA512 = -44, SHA384 = -43, RSAES_OAEP_SHA_512 = -42, RSAES_OAEP_SHA_256 = -41, RSAES_OAEP_RFC_8017_default = -40, PS512 = -39, PS384 = -38, PS256 = -37, ES512 = -36, ES384 = -35, ECDH_SS_A256KW = -34, ECDH_SS_A192KW = -33, ECDH_SS_A128KW = -32, ECDH_ES_A256KW = -31, ECDH_ES_A192KW = -30, ECDH_ES_A128KW = -29, ECDH_SS_HKDF512 = -28, ECDH_SS_HKDF256 = -27, ECDH_ES_HKDF512 = -26, ECDH_ES_HKDF256 = -25, SHAKE128 = -18, SHA512_256 = -17, SHA256 = -16, SHA256_64 = -15, SHA1 = -14, Direct_HKDF_AES256 = -13, Direct_HKDF_AES128 = -12, Direct_HKDF_SHA512 = -11, Direct_HKDF_SHA256 = -10, EDDSA = -8, ES256 = -7, Direct = -6, A256KW = -5, A192KW = -4, A128KW = -3, A128GCM = 1, A192GCM = 2, A256GCM = 3, HMAC256_64 = 4, HMAC256_256 = 5, HMAC384_384 = 6, HMAC512_512 = 7, AES_CCM_16_64_128 = 10, AES_CCM_16_64_256 = 11, AES_CCM_64_64_128 = 12, AES_CCM_64_64_256 = 13, AES_MAC_128_64 = 14, AES_MAC_256_64 = 15, ChaCha20_Poly1305 = 24, AES_MAC_128_128 = 25, AES_MAC_256_128 = 26, AES_CCM_16_128_128 = 30, AES_CCM_16_128_256 = 31, AES_CCM_64_128_128 = 32, AES_CCM_64_128_256 = 33, IV_GENERATION = 34, }
177
178impl Serialize for COSEAlgorithm {
179 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
180 where
181 S: Serializer,
182 {
183 match *self {
184 COSEAlgorithm::RS512 => serializer.serialize_i16(-259),
185 COSEAlgorithm::RS384 => serializer.serialize_i16(-258),
186 COSEAlgorithm::RS256 => serializer.serialize_i16(-257),
187 COSEAlgorithm::ES256K => serializer.serialize_i8(-47),
188 COSEAlgorithm::HSS_LMS => serializer.serialize_i8(-46),
189 COSEAlgorithm::SHAKE256 => serializer.serialize_i8(-45),
190 COSEAlgorithm::SHA512 => serializer.serialize_i8(-44),
191 COSEAlgorithm::SHA384 => serializer.serialize_i8(-43),
192 COSEAlgorithm::RSAES_OAEP_SHA_512 => serializer.serialize_i8(-42),
193 COSEAlgorithm::RSAES_OAEP_SHA_256 => serializer.serialize_i8(-41),
194 COSEAlgorithm::RSAES_OAEP_RFC_8017_default => serializer.serialize_i8(-40),
195 COSEAlgorithm::PS512 => serializer.serialize_i8(-39),
196 COSEAlgorithm::PS384 => serializer.serialize_i8(-38),
197 COSEAlgorithm::PS256 => serializer.serialize_i8(-37),
198 COSEAlgorithm::ES512 => serializer.serialize_i8(-36),
199 COSEAlgorithm::ES384 => serializer.serialize_i8(-35),
200 COSEAlgorithm::ECDH_SS_A256KW => serializer.serialize_i8(-34),
201 COSEAlgorithm::ECDH_SS_A192KW => serializer.serialize_i8(-33),
202 COSEAlgorithm::ECDH_SS_A128KW => serializer.serialize_i8(-32),
203 COSEAlgorithm::ECDH_ES_A256KW => serializer.serialize_i8(-31),
204 COSEAlgorithm::ECDH_ES_A192KW => serializer.serialize_i8(-30),
205 COSEAlgorithm::ECDH_ES_A128KW => serializer.serialize_i8(-29),
206 COSEAlgorithm::ECDH_SS_HKDF512 => serializer.serialize_i8(-28),
207 COSEAlgorithm::ECDH_SS_HKDF256 => serializer.serialize_i8(-27),
208 COSEAlgorithm::ECDH_ES_HKDF512 => serializer.serialize_i8(-26),
209 COSEAlgorithm::ECDH_ES_HKDF256 => serializer.serialize_i8(-25),
210 COSEAlgorithm::SHAKE128 => serializer.serialize_i8(-18),
211 COSEAlgorithm::SHA512_256 => serializer.serialize_i8(-17),
212 COSEAlgorithm::SHA256 => serializer.serialize_i8(-16),
213 COSEAlgorithm::SHA256_64 => serializer.serialize_i8(-15),
214 COSEAlgorithm::SHA1 => serializer.serialize_i8(-14),
215 COSEAlgorithm::Direct_HKDF_AES256 => serializer.serialize_i8(-13),
216 COSEAlgorithm::Direct_HKDF_AES128 => serializer.serialize_i8(-12),
217 COSEAlgorithm::Direct_HKDF_SHA512 => serializer.serialize_i8(-11),
218 COSEAlgorithm::Direct_HKDF_SHA256 => serializer.serialize_i8(-10),
219 COSEAlgorithm::EDDSA => serializer.serialize_i8(-8),
220 COSEAlgorithm::ES256 => serializer.serialize_i8(-7),
221 COSEAlgorithm::Direct => serializer.serialize_i8(-6),
222 COSEAlgorithm::A256KW => serializer.serialize_i8(-5),
223 COSEAlgorithm::A192KW => serializer.serialize_i8(-4),
224 COSEAlgorithm::A128KW => serializer.serialize_i8(-3),
225 COSEAlgorithm::A128GCM => serializer.serialize_i8(1),
226 COSEAlgorithm::A192GCM => serializer.serialize_i8(2),
227 COSEAlgorithm::A256GCM => serializer.serialize_i8(3),
228 COSEAlgorithm::HMAC256_64 => serializer.serialize_i8(4),
229 COSEAlgorithm::HMAC256_256 => serializer.serialize_i8(5),
230 COSEAlgorithm::HMAC384_384 => serializer.serialize_i8(6),
231 COSEAlgorithm::HMAC512_512 => serializer.serialize_i8(7),
232 COSEAlgorithm::AES_CCM_16_64_128 => serializer.serialize_i8(10),
233 COSEAlgorithm::AES_CCM_16_64_256 => serializer.serialize_i8(11),
234 COSEAlgorithm::AES_CCM_64_64_128 => serializer.serialize_i8(12),
235 COSEAlgorithm::AES_CCM_64_64_256 => serializer.serialize_i8(13),
236 COSEAlgorithm::AES_MAC_128_64 => serializer.serialize_i8(14),
237 COSEAlgorithm::AES_MAC_256_64 => serializer.serialize_i8(15),
238 COSEAlgorithm::ChaCha20_Poly1305 => serializer.serialize_i8(24),
239 COSEAlgorithm::AES_MAC_128_128 => serializer.serialize_i8(25),
240 COSEAlgorithm::AES_MAC_256_128 => serializer.serialize_i8(26),
241 COSEAlgorithm::AES_CCM_16_128_128 => serializer.serialize_i8(30),
242 COSEAlgorithm::AES_CCM_16_128_256 => serializer.serialize_i8(31),
243 COSEAlgorithm::AES_CCM_64_128_128 => serializer.serialize_i8(32),
244 COSEAlgorithm::AES_CCM_64_128_256 => serializer.serialize_i8(33),
245 COSEAlgorithm::IV_GENERATION => serializer.serialize_i8(34),
246 COSEAlgorithm::INSECURE_RS1 => serializer.serialize_i32(-65535),
247 }
248 }
249}
250
251impl<'de> Deserialize<'de> for COSEAlgorithm {
252 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
253 where
254 D: Deserializer<'de>,
255 {
256 struct COSEAlgorithmVisitor;
257
258 impl<'de> Visitor<'de> for COSEAlgorithmVisitor {
259 type Value = COSEAlgorithm;
260
261 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
262 formatter.write_str("a signed integer")
263 }
264
265 fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
266 where
267 E: SerdeError,
268 {
269 COSEAlgorithm::try_from(v).map_err(|_| {
270 SerdeError::invalid_value(Unexpected::Signed(v), &"valid COSEAlgorithm")
271 })
272 }
273 }
274
275 deserializer.deserialize_any(COSEAlgorithmVisitor)
276 }
277}
278
279impl TryFrom<i64> for COSEAlgorithm {
280 type Error = CryptoError;
281 fn try_from(i: i64) -> Result<Self, Self::Error> {
282 match i {
283 -259 => Ok(COSEAlgorithm::RS512),
284 -258 => Ok(COSEAlgorithm::RS384),
285 -257 => Ok(COSEAlgorithm::RS256),
286 -47 => Ok(COSEAlgorithm::ES256K),
287 -46 => Ok(COSEAlgorithm::HSS_LMS),
288 -45 => Ok(COSEAlgorithm::SHAKE256),
289 -44 => Ok(COSEAlgorithm::SHA512),
290 -43 => Ok(COSEAlgorithm::SHA384),
291 -42 => Ok(COSEAlgorithm::RSAES_OAEP_SHA_512),
292 -41 => Ok(COSEAlgorithm::RSAES_OAEP_SHA_256),
293 -40 => Ok(COSEAlgorithm::RSAES_OAEP_RFC_8017_default),
294 -39 => Ok(COSEAlgorithm::PS512),
295 -38 => Ok(COSEAlgorithm::PS384),
296 -37 => Ok(COSEAlgorithm::PS256),
297 -36 => Ok(COSEAlgorithm::ES512),
298 -35 => Ok(COSEAlgorithm::ES384),
299 -34 => Ok(COSEAlgorithm::ECDH_SS_A256KW),
300 -33 => Ok(COSEAlgorithm::ECDH_SS_A192KW),
301 -32 => Ok(COSEAlgorithm::ECDH_SS_A128KW),
302 -31 => Ok(COSEAlgorithm::ECDH_ES_A256KW),
303 -30 => Ok(COSEAlgorithm::ECDH_ES_A192KW),
304 -29 => Ok(COSEAlgorithm::ECDH_ES_A128KW),
305 -28 => Ok(COSEAlgorithm::ECDH_SS_HKDF512),
306 -27 => Ok(COSEAlgorithm::ECDH_SS_HKDF256),
307 -26 => Ok(COSEAlgorithm::ECDH_ES_HKDF512),
308 -25 => Ok(COSEAlgorithm::ECDH_ES_HKDF256),
309 -18 => Ok(COSEAlgorithm::SHAKE128),
310 -17 => Ok(COSEAlgorithm::SHA512_256),
311 -16 => Ok(COSEAlgorithm::SHA256),
312 -15 => Ok(COSEAlgorithm::SHA256_64),
313 -14 => Ok(COSEAlgorithm::SHA1),
314 -13 => Ok(COSEAlgorithm::Direct_HKDF_AES256),
315 -12 => Ok(COSEAlgorithm::Direct_HKDF_AES128),
316 -11 => Ok(COSEAlgorithm::Direct_HKDF_SHA512),
317 -10 => Ok(COSEAlgorithm::Direct_HKDF_SHA256),
318 -8 => Ok(COSEAlgorithm::EDDSA),
319 -7 => Ok(COSEAlgorithm::ES256),
320 -6 => Ok(COSEAlgorithm::Direct),
321 -5 => Ok(COSEAlgorithm::A256KW),
322 -4 => Ok(COSEAlgorithm::A192KW),
323 -3 => Ok(COSEAlgorithm::A128KW),
324 1 => Ok(COSEAlgorithm::A128GCM),
325 2 => Ok(COSEAlgorithm::A192GCM),
326 3 => Ok(COSEAlgorithm::A256GCM),
327 4 => Ok(COSEAlgorithm::HMAC256_64),
328 5 => Ok(COSEAlgorithm::HMAC256_256),
329 6 => Ok(COSEAlgorithm::HMAC384_384),
330 7 => Ok(COSEAlgorithm::HMAC512_512),
331 10 => Ok(COSEAlgorithm::AES_CCM_16_64_128),
332 11 => Ok(COSEAlgorithm::AES_CCM_16_64_256),
333 12 => Ok(COSEAlgorithm::AES_CCM_64_64_128),
334 13 => Ok(COSEAlgorithm::AES_CCM_64_64_256),
335 14 => Ok(COSEAlgorithm::AES_MAC_128_64),
336 15 => Ok(COSEAlgorithm::AES_MAC_256_64),
337 24 => Ok(COSEAlgorithm::ChaCha20_Poly1305),
338 25 => Ok(COSEAlgorithm::AES_MAC_128_128),
339 26 => Ok(COSEAlgorithm::AES_MAC_256_128),
340 30 => Ok(COSEAlgorithm::AES_CCM_16_128_128),
341 31 => Ok(COSEAlgorithm::AES_CCM_16_128_256),
342 32 => Ok(COSEAlgorithm::AES_CCM_64_128_128),
343 33 => Ok(COSEAlgorithm::AES_CCM_64_128_256),
344 34 => Ok(COSEAlgorithm::IV_GENERATION),
345 -65535 => Ok(COSEAlgorithm::INSECURE_RS1),
346 _ => Err(CryptoError::UnknownAlgorithm),
347 }
348 }
349}
350#[derive(Clone, Debug, PartialEq, Eq)]
353pub struct COSEEC2Key {
354 pub curve: ECDSACurve,
356 pub x: Vec<u8>,
358 pub y: Vec<u8>,
360}
361
362#[derive(Clone, Debug, PartialEq, Eq)]
366pub struct COSEOKPKey {
367 pub curve: ECDSACurve,
369 pub x: Vec<u8>,
371}
372
373#[derive(Clone, Debug, PartialEq, Eq)]
378pub struct COSERSAKey {
379 pub n: Vec<u8>,
381 pub e: Vec<u8>,
383}
384
385#[derive(Clone, Debug, PartialEq, Eq)]
389pub struct COSESymmetricKey {
390 pub key: Vec<u8>,
392}
393
394#[allow(non_camel_case_types)]
396#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
397#[repr(i64)]
398pub enum COSEKeyTypeId {
399 OKP = 1,
403 EC2 = 2,
405 RSA = 3,
407 Symmetric = 4,
409}
410
411impl TryFrom<u64> for COSEKeyTypeId {
412 type Error = CryptoError;
413 fn try_from(i: u64) -> Result<Self, Self::Error> {
414 match i {
415 1 => Ok(COSEKeyTypeId::OKP),
416 2 => Ok(COSEKeyTypeId::EC2),
417 3 => Ok(COSEKeyTypeId::RSA),
418 4 => Ok(COSEKeyTypeId::Symmetric),
419 _ => Err(CryptoError::UnknownKeyType),
420 }
421 }
422}
423
424#[allow(non_camel_case_types)]
427#[derive(Clone, Debug, PartialEq, Eq)]
428pub enum COSEKeyType {
429 OKP(COSEOKPKey), EC2(COSEEC2Key),
443 RSA(COSERSAKey), Symmetric(COSESymmetricKey), }
448
449#[derive(Clone, Debug, PartialEq, Eq)]
452pub struct COSEKey {
453 pub alg: COSEAlgorithm,
456 pub key: COSEKeyType,
458}
459
460impl<'de> Deserialize<'de> for COSEKey {
461 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
462 where
463 D: Deserializer<'de>,
464 {
465 struct COSEKeyVisitor;
466
467 impl<'de> Visitor<'de> for COSEKeyVisitor {
468 type Value = COSEKey;
469
470 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
471 formatter.write_str("a map")
472 }
473
474 fn visit_map<M>(self, mut map: M) -> std::result::Result<Self::Value, M::Error>
475 where
476 M: MapAccess<'de>,
477 {
478 let mut curve: Option<ECDSACurve> = None;
479 let mut key_type: Option<COSEKeyTypeId> = None;
480 let mut alg: Option<COSEAlgorithm> = None;
481 let mut x: Option<Vec<u8>> = None;
482 let mut y: Option<Vec<u8>> = None;
483
484 while let Some(key) = map.next_key()? {
485 trace!("cose key {:?}", key);
486 match key {
487 1 => {
488 if key_type.is_some() {
489 return Err(SerdeError::duplicate_field("key_type"));
490 }
491 let value: u64 = map.next_value()?;
492 let val = COSEKeyTypeId::try_from(value).map_err(|_| {
493 SerdeError::custom(format!("unsupported key_type {}", value))
494 })?;
495 key_type = Some(val);
496 }
498 -1 => {
499 let key_type = key_type.ok_or(SerdeError::missing_field("key_type"))?;
500 if key_type == COSEKeyTypeId::RSA {
501 if y.is_some() {
502 return Err(SerdeError::duplicate_field("y"));
503 }
504 let value: ByteBuf = map.next_value()?;
505 y = Some(value.to_vec());
506 } else {
507 if curve.is_some() {
508 return Err(SerdeError::duplicate_field("curve"));
509 }
510 let value: u64 = map.next_value()?;
511 let val = ECDSACurve::try_from(value).map_err(|_| {
512 SerdeError::custom(format!("unsupported curve {}", value))
513 })?;
514 curve = Some(val);
515 }
517 }
518 -2 => {
519 if x.is_some() {
520 return Err(SerdeError::duplicate_field("x"));
521 }
522 let value: ByteBuf = map.next_value()?;
523 x = Some(value.to_vec());
524 }
525 -3 => {
526 if y.is_some() {
527 return Err(SerdeError::duplicate_field("y"));
528 }
529 let value: ByteBuf = map.next_value()?;
530 y = Some(value.to_vec());
531 }
532 3 => {
533 if alg.is_some() {
534 return Err(SerdeError::duplicate_field("alg"));
535 }
536 let value: i64 = map.next_value()?;
537 let val = COSEAlgorithm::try_from(value).map_err(|_| {
538 SerdeError::custom(format!("unsupported algorithm {}", value))
539 })?;
540 alg = Some(val);
541 }
543 _ => {
544 let value: Value = map.next_value()?;
549 trace!("cose unknown value {:?}:{:?}", key, value);
550 }
551 };
552 }
553
554 let key_type = key_type.ok_or(SerdeError::missing_field("key_type"))?;
555 let x = x.ok_or(SerdeError::missing_field("x"))?;
556 let alg = alg.ok_or(SerdeError::missing_field("alg"))?;
557
558 let res = match key_type {
559 COSEKeyTypeId::OKP => {
560 let curve = curve.ok_or(SerdeError::missing_field("curve"))?;
561 COSEKeyType::OKP(COSEOKPKey { curve, x })
562 }
563 COSEKeyTypeId::EC2 => {
564 let curve = curve.ok_or(SerdeError::missing_field("curve"))?;
565 let y = y.ok_or(SerdeError::missing_field("y"))?;
566 COSEKeyType::EC2(COSEEC2Key { curve, x, y })
567 }
568 COSEKeyTypeId::RSA => {
569 let e = y.ok_or(SerdeError::missing_field("y"))?;
570 COSEKeyType::RSA(COSERSAKey { e, n: x })
571 }
572 COSEKeyTypeId::Symmetric => COSEKeyType::Symmetric(COSESymmetricKey { key: x }),
573 };
574 Ok(COSEKey { alg, key: res })
575 }
576 }
577
578 deserializer.deserialize_bytes(COSEKeyVisitor)
579 }
580}
581
582impl Serialize for COSEKey {
583 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
584 where
585 S: Serializer,
586 {
587 let map_len = match &self.key {
588 COSEKeyType::OKP(_) => 3,
589 COSEKeyType::EC2(_) => 5,
590 COSEKeyType::RSA(_) => 4,
591 COSEKeyType::Symmetric(_) => 3,
592 };
593 let mut map = serializer.serialize_map(Some(map_len))?;
594 match &self.key {
595 COSEKeyType::OKP(key) => {
596 map.serialize_entry(&1, &COSEKeyTypeId::OKP)?;
597 map.serialize_entry(&3, &self.alg)?;
598 map.serialize_entry(&-1, &key.curve)?;
599 map.serialize_entry(&-2, &key.x)?;
600 }
601 COSEKeyType::EC2(key) => {
602 map.serialize_entry(&1, &(COSEKeyTypeId::EC2 as u8))?;
603 map.serialize_entry(&3, &self.alg)?;
604 map.serialize_entry(&-1, &(key.curve as u8))?;
605 map.serialize_entry(&-2, &serde_bytes::Bytes::new(&key.x))?;
606 map.serialize_entry(&-3, &serde_bytes::Bytes::new(&key.y))?;
607 }
608 COSEKeyType::RSA(key) => {
609 map.serialize_entry(&1, &COSEKeyTypeId::RSA)?;
610 map.serialize_entry(&3, &self.alg)?;
611 map.serialize_entry(&-1, &key.n)?;
612 map.serialize_entry(&-2, &key.e)?;
613 }
614 COSEKeyType::Symmetric(key) => {
615 map.serialize_entry(&1, &COSEKeyTypeId::Symmetric)?;
616 map.serialize_entry(&3, &self.alg)?;
617 map.serialize_entry(&-1, &key.key)?;
618 }
619 }
620
621 map.end()
622 }
623}
624
625#[derive(Debug)]
627pub enum CryptoError {
628 UnknownKeyType,
640 UnknownSignatureScheme,
641 UnknownAlgorithm,
642 WrongSaltLength,
643 Backend(BackendError),
644}
645
646impl From<BackendError> for CryptoError {
647 fn from(e: BackendError) -> Self {
648 CryptoError::Backend(e)
649 }
650}
651
652impl From<CryptoError> for CommandError {
653 fn from(e: CryptoError) -> Self {
654 CommandError::Crypto(e)
655 }
656}
657
658impl From<CryptoError> for AuthenticatorError {
659 fn from(e: CryptoError) -> Self {
660 AuthenticatorError::HIDError(HIDError::Command(CommandError::Crypto(e)))
661 }
662}
663
664#[derive(Clone)]
665pub struct ECDHSecret {
666 remote: COSEKey,
667 my: COSEKey,
668 shared_secret: Vec<u8>,
669}
670
671impl ECDHSecret {
672 pub fn my_public_key(&self) -> &COSEKey {
673 &self.my
674 }
675
676 pub fn shared_secret(&self) -> &[u8] {
677 &self.shared_secret
678 }
679}
680
681impl fmt::Debug for ECDHSecret {
682 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
683 write!(
684 f,
685 "ECDHSecret(remote: {:?}, my: {:?})",
686 self.remote,
687 self.my_public_key()
688 )
689 }
690}
691
692#[cfg(all(test, not(feature = "crypto_dummy")))]
693mod test {
694 use super::{
695 authenticate, decrypt, encrypt, imp::parse_key, imp::test_encapsulate, serialize_key,
696 COSEAlgorithm, COSEKey, ECDSACurve,
697 };
698 use crate::crypto::{COSEEC2Key, COSEKeyType};
699 use crate::ctap2::commands::client_pin::Pin;
700 use crate::util::decode_hex;
701 use serde_cbor::de::from_slice;
702
703 #[test]
704 fn test_serialize_key() {
705 let x = [
706 0xfc, 0x9e, 0xd3, 0x6f, 0x7c, 0x1a, 0xa9, 0x15, 0xce, 0x3e, 0xa1, 0x77, 0xf0, 0x75,
707 0x67, 0xf0, 0x7f, 0x16, 0xf9, 0x47, 0x9d, 0x95, 0xad, 0x8e, 0xd4, 0x97, 0x1d, 0x33,
708 0x05, 0xe3, 0x1a, 0x80,
709 ];
710 let y = [
711 0x50, 0xb7, 0x33, 0xaf, 0x8c, 0x0b, 0x0e, 0xe1, 0xda, 0x8d, 0xe0, 0xac, 0xf9, 0xd8,
712 0xe1, 0x32, 0x82, 0xf0, 0x63, 0xb7, 0xb3, 0x0d, 0x73, 0xd4, 0xd3, 0x2c, 0x9a, 0xad,
713 0x6d, 0xfa, 0x8b, 0x27,
714 ];
715 let serialized_key = [
716 0x04, 0xfc, 0x9e, 0xd3, 0x6f, 0x7c, 0x1a, 0xa9, 0x15, 0xce, 0x3e, 0xa1, 0x77, 0xf0,
717 0x75, 0x67, 0xf0, 0x7f, 0x16, 0xf9, 0x47, 0x9d, 0x95, 0xad, 0x8e, 0xd4, 0x97, 0x1d,
718 0x33, 0x05, 0xe3, 0x1a, 0x80, 0x50, 0xb7, 0x33, 0xaf, 0x8c, 0x0b, 0x0e, 0xe1, 0xda,
719 0x8d, 0xe0, 0xac, 0xf9, 0xd8, 0xe1, 0x32, 0x82, 0xf0, 0x63, 0xb7, 0xb3, 0x0d, 0x73,
720 0xd4, 0xd3, 0x2c, 0x9a, 0xad, 0x6d, 0xfa, 0x8b, 0x27,
721 ];
722
723 let (res_x, res_y) =
724 serialize_key(ECDSACurve::SECP256R1, &serialized_key).expect("Failed to serialize key");
725 assert_eq!(res_x, x);
726 assert_eq!(res_y, y);
727
728 let res_key = parse_key(ECDSACurve::SECP256R1, &x, &y).expect("Failed to parse key");
729
730 assert_eq!(res_key, serialized_key)
731 }
732
733 #[test]
734 fn test_parse_es256_serialize_key() {
735 let key_data = decode_hex("A5010203262001215820A5FD5CE1B1C458C530A54FA61B31BF6B04BE8B97AFDE54DD8CBB69275A8A1BE1225820FA3A3231DD9DEED9D1897BE5A6228C59501E4BCD12975D3DFF730F01278EA61C");
737 let key: COSEKey = from_slice(&key_data).unwrap();
738 assert_eq!(key.alg, COSEAlgorithm::ES256);
739 if let COSEKeyType::EC2(ec2key) = &key.key {
740 assert_eq!(ec2key.curve, ECDSACurve::SECP256R1);
741 assert_eq!(
742 ec2key.x,
743 decode_hex("A5FD5CE1B1C458C530A54FA61B31BF6B04BE8B97AFDE54DD8CBB69275A8A1BE1")
744 );
745 assert_eq!(
746 ec2key.y,
747 decode_hex("FA3A3231DD9DEED9D1897BE5A6228C59501E4BCD12975D3DFF730F01278EA61C")
748 );
749 } else {
750 panic!("Wrong key type!");
751 }
752
753 let serialized = serde_cbor::to_vec(&key).expect("Failed to serialize key");
754 assert_eq!(key_data, serialized);
755 }
756
757 #[test]
758 #[allow(non_snake_case)]
759 fn test_shared_secret() {
760 let EC_PRIV =
762 decode_hex("7452E599FEE739D8A653F6A507343D12D382249108A651402520B72F24FE7684");
763 let EC_PUB_X =
764 decode_hex("44D78D7989B97E62EA993496C9EF6E8FD58B8B00715F9A89153DDD9C4657E47F");
765 let EC_PUB_Y =
766 decode_hex("EC802EE7D22BD4E100F12E48537EB4E7E96ED3A47A0A3BD5F5EEAB65001664F9");
767 let DEV_PUB_X =
768 decode_hex("0501D5BC78DA9252560A26CB08FCC60CBE0B6D3B8E1D1FCEE514FAC0AF675168");
769 let DEV_PUB_Y =
770 decode_hex("D551B3ED46F665731F95B4532939C25D91DB7EB844BD96D4ABD4083785F8DF47");
771 let SHARED = decode_hex("c42a039d548100dfba521e487debcbbb8b66bb7496f8b1862a7a395ed83e1a1c");
772 let TOKEN_ENC = decode_hex("7A9F98E31B77BE90F9C64D12E9635040");
773 let TOKEN = decode_hex("aff12c6dcfbf9df52f7a09211e8865cd");
774 let PIN_HASH_ENC = decode_hex("afe8327ce416da8ee3d057589c2ce1a9");
775
776 let my_pub_key_data = parse_key(ECDSACurve::SECP256R1, &EC_PUB_X, &EC_PUB_Y).unwrap();
778
779 let peer_key = COSEEC2Key {
780 curve: ECDSACurve::SECP256R1,
781 x: DEV_PUB_X,
782 y: DEV_PUB_Y,
783 };
784
785 let shared_secret =
796 test_encapsulate(&peer_key, COSEAlgorithm::ES256, &my_pub_key_data, &EC_PRIV).unwrap();
797 assert_eq!(shared_secret.shared_secret, SHARED);
798
799 let token_enc = encrypt(&shared_secret.shared_secret(), &TOKEN).unwrap();
800 assert_eq!(token_enc, TOKEN_ENC);
801
802 let token = decrypt(&shared_secret.shared_secret(), &TOKEN_ENC).unwrap();
803 assert_eq!(token, TOKEN);
804
805 let pin = Pin::new("1234");
806 let pin_hash_enc =
807 encrypt(&shared_secret.shared_secret(), pin.for_pin_token().as_ref()).unwrap();
808 assert_eq!(pin_hash_enc, PIN_HASH_ENC);
809 }
810
811 #[test]
812 fn test_authenticate() {
813 let key = "key";
814 let message = "The quick brown fox jumps over the lazy dog";
815 let expected =
816 decode_hex("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8");
817
818 let result =
819 authenticate(key.as_bytes(), message.as_bytes()).expect("Failed to authenticate");
820 assert_eq!(result, expected);
821
822 let key = "The quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dog";
823 let message = "message";
824 let expected =
825 decode_hex("5597b93a2843078cbb0c920ae41dfe20f1685e10c67e423c11ab91adfc319d12");
826
827 let result =
828 authenticate(key.as_bytes(), message.as_bytes()).expect("Failed to authenticate");
829 assert_eq!(result, expected);
830 }
831
832 #[test]
833 fn test_pin_encryption_and_hashing() {
834 let pin = "1234";
835
836 let shared_secret = vec![
837 0x82, 0xE3, 0xD8, 0x41, 0xE2, 0x5C, 0x5C, 0x13, 0x46, 0x2C, 0x12, 0x3C, 0xC3, 0xD3,
838 0x98, 0x78, 0x65, 0xBA, 0x3D, 0x20, 0x46, 0x74, 0xFB, 0xED, 0xD4, 0x7E, 0xF5, 0xAB,
839 0xAB, 0x8D, 0x13, 0x72,
840 ];
841 let expected_new_pin_enc = vec![
842 0x70, 0x66, 0x4B, 0xB5, 0x81, 0xE2, 0x57, 0x45, 0x1A, 0x3A, 0xB9, 0x1B, 0xF1, 0xAA,
843 0xD8, 0xE4, 0x5F, 0x6C, 0xE9, 0xB5, 0xC3, 0xB0, 0xF3, 0x2B, 0x5E, 0xCD, 0x62, 0xD0,
844 0xBA, 0x3B, 0x60, 0x5F, 0xD9, 0x18, 0x31, 0x66, 0xF6, 0xC5, 0xFA, 0xF3, 0xE4, 0xDA,
845 0x24, 0x81, 0x50, 0x2C, 0xD0, 0xCE, 0xE0, 0x15, 0x8B, 0x35, 0x1F, 0xC3, 0x92, 0x08,
846 0xA7, 0x7C, 0xB2, 0x74, 0x4B, 0xD4, 0x3C, 0xF9,
847 ];
848 let expected_pin_auth = vec![
849 0x8E, 0x7F, 0x01, 0x69, 0x97, 0xF3, 0xB0, 0xA2, 0x7B, 0xA4, 0x34, 0x7A, 0x0E, 0x49,
850 0xFD, 0xF5,
851 ];
852
853 let input: Vec<u8> = pin
855 .as_bytes()
856 .iter()
857 .chain(std::iter::repeat(&0x00))
858 .take(64)
859 .cloned()
860 .collect();
861
862 let new_pin_enc = encrypt(&shared_secret, &input).expect("Failed to encrypt pin");
863 assert_eq!(new_pin_enc, expected_new_pin_enc);
864
865 let pin_auth = authenticate(&shared_secret, &new_pin_enc).expect("Failed to authenticate");
866 assert_eq!(pin_auth[0..16], expected_pin_auth);
867 }
868}