tests.rs (231588B)
1 use super::{ 2 super::{ 3 AKP, ALG, AuthenticatorAttachment, EC2, EDDSA, ES256, ES384, Ed25519PubKey, KTY, MLDSA44, 4 MLDSA65, MLDSA87, MlDsa44PubKey, MlDsa65PubKey, MlDsa87PubKey, OKP, RSA, Registration, 5 RsaPubKey, UncompressedP256PubKey, UncompressedP384PubKey, cbor, 6 }, 7 CoseAlgorithmIdentifier, 8 spki::SubjectPublicKeyInfo as _, 9 }; 10 use ed25519_dalek::{VerifyingKey, pkcs8::EncodePublicKey as _}; 11 use ml_dsa::{MlDsa44, MlDsa65, MlDsa87, VerifyingKey as MlDsaVerKey}; 12 use p256::{ 13 PublicKey as P256PubKey, Sec1Point as P256Pt, SecretKey as P256Key, 14 elliptic_curve::sec1::{FromSec1Point as _, ToSec1Point as _}, 15 }; 16 use p384::{PublicKey as P384PubKey, Sec1Point as P384Pt, SecretKey as P384Key}; 17 use rsa::{ 18 BoxedUint, RsaPrivateKey, 19 sha2::{Digest as _, Sha256}, 20 traits::PublicKeyParts as _, 21 }; 22 use serde::de::{Error as _, Unexpected}; 23 use serde_json::Error; 24 #[expect(clippy::unwrap_used, reason = "OK in tests")] 25 #[test] 26 fn mldsa87_spki() { 27 assert!( 28 MlDsa87PubKey::from_der( 29 MlDsaVerKey::<MlDsa87>::decode(&[1; 2592].into()) 30 .to_public_key_der() 31 .unwrap() 32 .as_bytes() 33 ) 34 .is_ok_and(|k| k.0 == [1; 2592]) 35 ); 36 } 37 #[expect(clippy::unwrap_used, reason = "OK in tests")] 38 #[test] 39 fn mldsa65_spki() { 40 assert!( 41 MlDsa65PubKey::from_der( 42 MlDsaVerKey::<MlDsa65>::decode(&[1; 1952].into()) 43 .to_public_key_der() 44 .unwrap() 45 .as_bytes() 46 ) 47 .is_ok_and(|k| k.0 == [1; 1952]) 48 ); 49 } 50 #[expect(clippy::unwrap_used, reason = "OK in tests")] 51 #[test] 52 fn mldsa44_spki() { 53 assert!( 54 MlDsa44PubKey::from_der( 55 MlDsaVerKey::<MlDsa44>::decode(&[1; 1312].into()) 56 .to_public_key_der() 57 .unwrap() 58 .as_bytes() 59 ) 60 .is_ok_and(|k| k.0 == [1; 1312]) 61 ); 62 } 63 #[expect(clippy::unwrap_used, reason = "OK in tests")] 64 #[test] 65 fn ed25519_spki() { 66 assert!( 67 Ed25519PubKey::from_der( 68 VerifyingKey::from_bytes(&[1; 32]) 69 .unwrap() 70 .to_public_key_der() 71 .unwrap() 72 .as_bytes() 73 ) 74 .is_ok_and(|k| k.0 == [1; 32]) 75 ); 76 } 77 #[expect(clippy::unwrap_used, reason = "OK in tests")] 78 #[test] 79 fn p256_spki() { 80 let key = P256Key::from_bytes( 81 &[ 82 137, 133, 36, 206, 163, 47, 255, 5, 76, 144, 163, 141, 40, 109, 108, 240, 246, 115, 83 178, 237, 169, 68, 6, 129, 92, 21, 238, 127, 55, 158, 207, 95, 84 ] 85 .into(), 86 ) 87 .unwrap() 88 .public_key(); 89 let enc_key = key.to_sec1_point(false); 90 assert!( 91 UncompressedP256PubKey::from_der(key.to_public_key_der().unwrap().as_bytes()) 92 .is_ok_and(|k| *k.0 == **enc_key.x().unwrap() && *k.1 == **enc_key.y().unwrap()) 93 ); 94 } 95 #[expect(clippy::unwrap_used, reason = "OK in tests")] 96 #[test] 97 fn p384_spki() { 98 let key = P384Key::from_bytes( 99 &[ 100 158, 99, 156, 49, 190, 211, 85, 167, 28, 2, 80, 57, 31, 22, 17, 38, 85, 78, 232, 42, 101 45, 199, 154, 243, 136, 251, 84, 34, 5, 120, 208, 91, 61, 248, 64, 144, 87, 1, 32, 86, 102 220, 68, 182, 11, 105, 223, 75, 70, 103 ] 104 .into(), 105 ) 106 .unwrap() 107 .public_key(); 108 let enc_key = key.to_sec1_point(false); 109 assert!( 110 UncompressedP384PubKey::from_der(key.to_public_key_der().unwrap().as_bytes()) 111 .is_ok_and(|k| *k.0 == **enc_key.x().unwrap() && *k.1 == **enc_key.y().unwrap()) 112 ); 113 } 114 #[expect(clippy::unwrap_used, reason = "OK in tests")] 115 #[test] 116 fn rsa_spki() { 117 let n = [ 118 111, 183, 124, 133, 38, 167, 70, 148, 44, 50, 30, 60, 121, 14, 38, 37, 96, 114, 107, 195, 119 248, 64, 79, 36, 237, 140, 43, 27, 94, 74, 102, 152, 135, 102, 184, 150, 186, 206, 185, 19, 120 165, 209, 48, 98, 98, 9, 3, 205, 208, 82, 250, 105, 132, 201, 73, 62, 60, 165, 100, 128, 121 153, 9, 41, 118, 66, 95, 236, 214, 73, 135, 197, 68, 184, 10, 27, 116, 204, 145, 50, 174, 122 58, 42, 183, 181, 119, 232, 126, 252, 217, 96, 162, 190, 103, 122, 64, 87, 145, 45, 32, 123 207, 17, 239, 223, 3, 35, 14, 112, 119, 124, 141, 123, 208, 239, 105, 81, 217, 151, 162, 124 190, 17, 88, 182, 176, 158, 81, 200, 42, 166, 133, 48, 23, 236, 55, 117, 248, 233, 151, 125 203, 122, 155, 231, 46, 177, 20, 20, 151, 64, 222, 239, 226, 7, 21, 254, 81, 202, 64, 232, 126 161, 235, 22, 51, 246, 207, 213, 0, 229, 138, 46, 222, 205, 157, 108, 139, 253, 230, 80, 127 50, 2, 122, 212, 163, 100, 180, 114, 12, 113, 52, 56, 99, 188, 42, 198, 212, 23, 182, 222, 128 56, 221, 200, 79, 96, 239, 221, 135, 10, 17, 106, 183, 56, 104, 68, 94, 198, 196, 35, 200, 129 83, 204, 26, 185, 204, 212, 31, 183, 19, 111, 233, 13, 72, 93, 53, 65, 111, 59, 242, 122, 130 160, 244, 162, 126, 38, 235, 156, 47, 88, 39, 132, 153, 79, 0, 133, 78, 7, 218, 165, 241, 131 ]; 132 let e = 0x0001_0001u32; 133 let d = [ 134 145, 79, 21, 97, 233, 3, 192, 194, 177, 68, 181, 80, 120, 197, 23, 44, 185, 74, 144, 0, 135 132, 149, 139, 11, 16, 224, 4, 112, 236, 94, 238, 97, 121, 124, 213, 145, 24, 253, 168, 35, 136 190, 205, 132, 115, 33, 201, 38, 253, 246, 180, 66, 155, 165, 46, 3, 254, 68, 108, 154, 137 247, 246, 45, 187, 0, 204, 96, 185, 157, 249, 174, 158, 38, 62, 244, 183, 76, 102, 6, 219, 138 92, 212, 138, 59, 147, 163, 219, 111, 39, 105, 21, 236, 196, 38, 255, 114, 247, 82, 104, 139 113, 204, 29, 152, 209, 219, 48, 239, 74, 129, 19, 247, 33, 239, 119, 166, 216, 152, 94, 140 138, 238, 164, 242, 129, 50, 150, 57, 20, 53, 224, 56, 241, 138, 97, 111, 215, 107, 212, 141 195, 146, 108, 143, 0, 229, 181, 171, 73, 152, 105, 146, 25, 243, 242, 140, 252, 248, 162, 142 247, 63, 168, 180, 20, 153, 120, 10, 248, 211, 1, 71, 127, 212, 249, 237, 203, 202, 48, 26, 143 216, 226, 228, 186, 13, 204, 70, 255, 240, 89, 255, 59, 83, 31, 253, 55, 43, 158, 90, 248, 144 83, 32, 159, 105, 57, 134, 34, 96, 18, 255, 245, 153, 162, 60, 91, 99, 220, 51, 44, 85, 145 114, 67, 125, 202, 65, 217, 245, 40, 8, 81, 165, 142, 24, 245, 127, 122, 247, 152, 212, 75, 146 45, 59, 90, 184, 234, 31, 147, 36, 8, 212, 45, 50, 23, 3, 25, 253, 87, 227, 79, 119, 161, 147 ]; 148 let p = BoxedUint::from_le_slice_vartime( 149 [ 150 215, 166, 5, 21, 11, 179, 41, 77, 198, 92, 165, 48, 77, 162, 42, 41, 206, 141, 60, 69, 151 47, 164, 19, 92, 46, 72, 100, 238, 100, 53, 214, 197, 163, 185, 6, 140, 229, 250, 195, 152 77, 8, 12, 5, 236, 178, 173, 86, 201, 43, 213, 165, 51, 108, 101, 161, 99, 76, 240, 14, 153 234, 76, 197, 137, 53, 198, 168, 135, 205, 212, 198, 120, 29, 16, 82, 98, 233, 236, 154 177, 12, 171, 141, 100, 107, 146, 33, 176, 125, 202, 172, 79, 147, 179, 30, 62, 247, 155 206, 169, 19, 168, 114, 26, 73, 108, 178, 105, 84, 89, 191, 168, 253, 228, 214, 54, 16, 156 212, 199, 111, 72, 3, 41, 247, 227, 165, 244, 32, 188, 24, 247, 157 ] 158 .as_slice(), 159 ); 160 let p_2 = BoxedUint::from_le_slice_vartime( 161 [ 162 41, 25, 198, 240, 134, 206, 121, 57, 11, 5, 134, 192, 212, 77, 229, 197, 14, 78, 85, 163 212, 190, 114, 179, 188, 21, 171, 174, 12, 104, 74, 15, 164, 136, 173, 62, 177, 141, 164 213, 93, 102, 147, 83, 59, 124, 146, 59, 175, 213, 55, 27, 25, 248, 154, 29, 39, 85, 165 50, 235, 134, 60, 203, 106, 186, 195, 190, 185, 71, 169, 142, 236, 92, 11, 250, 187, 166 198, 8, 201, 184, 120, 178, 227, 87, 63, 243, 89, 227, 234, 184, 28, 252, 112, 211, 167 193, 69, 23, 92, 5, 72, 93, 53, 69, 159, 73, 160, 105, 244, 249, 94, 214, 173, 9, 236, 168 4, 255, 129, 11, 224, 140, 252, 168, 57, 143, 176, 241, 60, 219, 90, 250, 169 ] 170 .as_slice(), 171 ); 172 let key = RsaPrivateKey::from_components( 173 BoxedUint::from_le_slice_vartime(n.as_slice()), 174 e.into(), 175 BoxedUint::from_le_slice_vartime(d.as_slice()), 176 vec![p, p_2], 177 ) 178 .unwrap() 179 .to_public_key(); 180 assert!( 181 RsaPubKey::from_der(key.to_public_key_der().unwrap().as_bytes()) 182 .is_ok_and(|k| *k.0 == *key.n().to_be_bytes() && BoxedUint::from(k.1) == *key.e()) 183 ); 184 } 185 #[expect(clippy::unwrap_used, reason = "OK in tests")] 186 #[expect(clippy::indexing_slicing, reason = "comments justify correctness")] 187 #[expect( 188 clippy::cognitive_complexity, 189 clippy::too_many_lines, 190 reason = "a lot to test" 191 )] 192 #[test] 193 fn eddsa_registration_deserialize_data_mismatch() { 194 let c_data_json = serde_json::json!({}).to_string(); 195 let att_obj: [u8; 143] = [ 196 cbor::MAP_3, 197 cbor::TEXT_3, 198 b'f', 199 b'm', 200 b't', 201 cbor::TEXT_4, 202 b'n', 203 b'o', 204 b'n', 205 b'e', 206 cbor::TEXT_7, 207 b'a', 208 b't', 209 b't', 210 b'S', 211 b't', 212 b'm', 213 b't', 214 cbor::MAP_0, 215 cbor::TEXT_8, 216 b'a', 217 b'u', 218 b't', 219 b'h', 220 b'D', 221 b'a', 222 b't', 223 b'a', 224 cbor::BYTES_INFO_24, 225 115, 226 // `rpIdHash`. 227 0, 228 0, 229 0, 230 0, 231 0, 232 0, 233 0, 234 0, 235 0, 236 0, 237 0, 238 0, 239 0, 240 0, 241 0, 242 0, 243 0, 244 0, 245 0, 246 0, 247 0, 248 0, 249 0, 250 0, 251 0, 252 0, 253 0, 254 0, 255 0, 256 0, 257 0, 258 0, 259 // `flags`. 260 0b0100_0101, 261 // `signCount`. 262 0, 263 0, 264 0, 265 0, 266 // `aaguid`. 267 0, 268 0, 269 0, 270 0, 271 0, 272 0, 273 0, 274 0, 275 0, 276 0, 277 0, 278 0, 279 0, 280 0, 281 0, 282 0, 283 // `credentialIdLength`. 284 0, 285 16, 286 // `credentialId`. 287 0, 288 0, 289 0, 290 0, 291 0, 292 0, 293 0, 294 0, 295 0, 296 0, 297 0, 298 0, 299 0, 300 0, 301 0, 302 0, 303 // Ed25519 COSE key. 304 cbor::MAP_4, 305 KTY, 306 OKP, 307 ALG, 308 EDDSA, 309 // `crv`. 310 cbor::NEG_ONE, 311 // `Ed25519`. 312 cbor::SIX, 313 // `x`. 314 cbor::NEG_TWO, 315 cbor::BYTES_INFO_24, 316 32, 317 // Compressed y-coordinate. 318 1, 319 1, 320 1, 321 1, 322 1, 323 1, 324 1, 325 1, 326 1, 327 1, 328 1, 329 1, 330 1, 331 1, 332 1, 333 1, 334 1, 335 1, 336 1, 337 1, 338 1, 339 1, 340 1, 341 1, 342 1, 343 1, 344 1, 345 1, 346 1, 347 1, 348 1, 349 1, 350 ]; 351 let pub_key = VerifyingKey::from_bytes(&[1; 32]) 352 .unwrap() 353 .to_public_key_der() 354 .unwrap(); 355 let b64_cdata_json = base64url_nopad::encode(c_data_json.as_bytes()); 356 let att_obj_len = att_obj.len(); 357 let auth_data_start = att_obj_len - 113; 358 let b64_adata = base64url_nopad::encode(&att_obj[auth_data_start..]); 359 let b64_key = base64url_nopad::encode(pub_key.as_bytes()); 360 let b64_aobj = base64url_nopad::encode(att_obj.as_slice()); 361 // Base case is valid. 362 assert!( 363 serde_json::from_str::<Registration>( 364 serde_json::json!({ 365 "id": "AAAAAAAAAAAAAAAAAAAAAA", 366 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 367 "response": { 368 "clientDataJSON": b64_cdata_json, 369 "authenticatorData": b64_adata, 370 "transports": ["ble", "usb", "hybrid", "internal", "nfc", "smart-card"], 371 "publicKey": b64_key, 372 "publicKeyAlgorithm": -8i8, 373 "attestationObject": b64_aobj, 374 }, 375 "authenticatorAttachment": "cross-platform", 376 "clientExtensionResults": {}, 377 "type": "public-key" 378 }) 379 .to_string() 380 .as_str() 381 ) 382 .is_ok_and( 383 |reg| reg.response.client_data_json == c_data_json.as_bytes() 384 && reg.response.attestation_object_and_c_data_hash[..att_obj_len] == att_obj 385 && reg.response.attestation_object_and_c_data_hash[att_obj_len..] 386 == *Sha256::digest(c_data_json.as_bytes()) 387 && reg.response.transports.count() == 6 388 && matches!( 389 reg.authenticator_attachment, 390 AuthenticatorAttachment::CrossPlatform 391 ) 392 && reg.client_extension_results.cred_props.is_none() 393 && reg.client_extension_results.prf.is_none() 394 ) 395 ); 396 // `id` and `rawId` mismatch. 397 let mut err = Error::invalid_value( 398 Unexpected::Bytes( 399 base64url_nopad::decode(b"ABABABABABABABABABABAA") 400 .unwrap() 401 .as_slice(), 402 ), 403 &format!("id and rawId to match: CredentialId({:?})", [0u8; 16]).as_str(), 404 ) 405 .to_string() 406 .into_bytes(); 407 assert_eq!( 408 serde_json::from_str::<Registration>( 409 serde_json::json!({ 410 "id": "AAAAAAAAAAAAAAAAAAAAAA", 411 "rawId": "ABABABABABABABABABABAA", 412 "response": { 413 "clientDataJSON": b64_cdata_json, 414 "authenticatorData": b64_adata, 415 "transports": [], 416 "publicKey": b64_key, 417 "publicKeyAlgorithm": -8i8, 418 "attestationObject": b64_aobj, 419 }, 420 "clientExtensionResults": {}, 421 "type": "public-key" 422 }) 423 .to_string() 424 .as_str() 425 ) 426 .unwrap_err() 427 .to_string() 428 .into_bytes() 429 .get(..err.len()), 430 Some(err.as_slice()) 431 ); 432 // missing `id`. 433 err = Error::missing_field("id").to_string().into_bytes(); 434 assert_eq!( 435 serde_json::from_str::<Registration>( 436 serde_json::json!({ 437 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 438 "response": { 439 "clientDataJSON": b64_cdata_json, 440 "authenticatorData": b64_adata, 441 "transports": [], 442 "publicKey": b64_key, 443 "publicKeyAlgorithm": -8i8, 444 "attestationObject": b64_aobj, 445 }, 446 "clientExtensionResults": {}, 447 "type": "public-key" 448 }) 449 .to_string() 450 .as_str() 451 ) 452 .unwrap_err() 453 .to_string() 454 .into_bytes() 455 .get(..err.len()), 456 Some(err.as_slice()) 457 ); 458 // `null` `id`. 459 err = Error::invalid_type(Unexpected::Other("null"), &"CredentialId") 460 .to_string() 461 .into_bytes(); 462 assert_eq!( 463 serde_json::from_str::<Registration>( 464 serde_json::json!({ 465 "id": null, 466 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 467 "response": { 468 "clientDataJSON": b64_cdata_json, 469 "authenticatorData": b64_adata, 470 "transports": [], 471 "publicKey": b64_key, 472 "publicKeyAlgorithm": -8i8, 473 "attestationObject": b64_aobj, 474 }, 475 "clientExtensionResults": {}, 476 "type": "public-key" 477 }) 478 .to_string() 479 .as_str() 480 ) 481 .unwrap_err() 482 .to_string() 483 .into_bytes() 484 .get(..err.len()), 485 Some(err.as_slice()) 486 ); 487 // missing `rawId`. 488 err = Error::missing_field("rawId").to_string().into_bytes(); 489 assert_eq!( 490 serde_json::from_str::<Registration>( 491 serde_json::json!({ 492 "id": "AAAAAAAAAAAAAAAAAAAAAA", 493 "response": { 494 "clientDataJSON": b64_cdata_json, 495 "authenticatorData": b64_adata, 496 "transports": [], 497 "publicKey": b64_key, 498 "publicKeyAlgorithm": -8i8, 499 "attestationObject": b64_aobj, 500 }, 501 "clientExtensionResults": {}, 502 "type": "public-key" 503 }) 504 .to_string() 505 .as_str() 506 ) 507 .unwrap_err() 508 .to_string() 509 .into_bytes() 510 .get(..err.len()), 511 Some(err.as_slice()) 512 ); 513 // `null` `rawId`. 514 err = Error::invalid_type(Unexpected::Other("null"), &"CredentialId") 515 .to_string() 516 .into_bytes(); 517 assert_eq!( 518 serde_json::from_str::<Registration>( 519 serde_json::json!({ 520 "id": "AAAAAAAAAAAAAAAAAAAAAA", 521 "rawId": null, 522 "response": { 523 "clientDataJSON": b64_cdata_json, 524 "authenticatorData": b64_adata, 525 "transports": [], 526 "publicKey": b64_key, 527 "publicKeyAlgorithm": -8i8, 528 "attestationObject": b64_aobj, 529 }, 530 "clientExtensionResults": {}, 531 "type": "public-key" 532 }) 533 .to_string() 534 .as_str() 535 ) 536 .unwrap_err() 537 .to_string() 538 .into_bytes() 539 .get(..err.len()), 540 Some(err.as_slice()) 541 ); 542 // `id` and the credential id in authenticator data mismatch. 543 err = Error::invalid_value( 544 Unexpected::Bytes( 545 base64url_nopad::decode(b"ABABABABABABABABABABAA") 546 .unwrap() 547 .as_slice(), 548 ), 549 &format!( 550 "id, rawId, and the credential id in the attested credential data to all match: {:?}", 551 [0u8; 16] 552 ) 553 .as_str(), 554 ) 555 .to_string() 556 .into_bytes(); 557 assert_eq!( 558 serde_json::from_str::<Registration>( 559 serde_json::json!({ 560 "id": "ABABABABABABABABABABAA", 561 "rawId": "ABABABABABABABABABABAA", 562 "response": { 563 "clientDataJSON": b64_cdata_json, 564 "authenticatorData": b64_adata, 565 "transports": [], 566 "publicKey": b64_key, 567 "publicKeyAlgorithm": -8i8, 568 "attestationObject": b64_aobj, 569 }, 570 "clientExtensionResults": {}, 571 "type": "public-key" 572 }) 573 .to_string() 574 .as_str() 575 ) 576 .unwrap_err() 577 .to_string() 578 .into_bytes() 579 .get(..err.len()), 580 Some(err.as_slice()) 581 ); 582 // `authenticatorData` mismatches `authData` in attestation object. 583 let mut bad_auth = [0; 113]; 584 bad_auth.copy_from_slice(&att_obj[auth_data_start..]); 585 bad_auth[113 - 32..].copy_from_slice([0; 32].as_slice()); 586 err = Error::invalid_value( 587 Unexpected::Bytes(bad_auth.as_slice()), 588 &format!("authenticator data to match the authenticator data portion of attestation object: {:?}", &att_obj[att_obj_len - bad_auth.len()..]).as_str(), 589 ) 590 .to_string().into_bytes(); 591 assert_eq!( 592 serde_json::from_str::<Registration>( 593 serde_json::json!({ 594 "id": "AAAAAAAAAAAAAAAAAAAAAA", 595 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 596 "response": { 597 "clientDataJSON": b64_cdata_json, 598 "authenticatorData": base64url_nopad::encode(bad_auth.as_slice()), 599 "transports": [], 600 "publicKey": b64_key, 601 "publicKeyAlgorithm": -8i8, 602 "attestationObject": b64_aobj, 603 }, 604 "clientExtensionResults": {}, 605 "type": "public-key" 606 }) 607 .to_string() 608 .as_str() 609 ) 610 .unwrap_err() 611 .to_string() 612 .into_bytes() 613 .get(..err.len()), 614 Some(err.as_slice()) 615 ); 616 // Missing `authenticatorData`. 617 err = Error::missing_field("authenticatorData") 618 .to_string() 619 .into_bytes(); 620 assert_eq!( 621 serde_json::from_str::<Registration>( 622 serde_json::json!({ 623 "id": "AAAAAAAAAAAAAAAAAAAAAA", 624 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 625 "response": { 626 "clientDataJSON": b64_cdata_json, 627 "transports": [], 628 "publicKey": b64_key, 629 "publicKeyAlgorithm": -8i8, 630 "attestationObject": b64_aobj, 631 }, 632 "clientExtensionResults": {}, 633 "type": "public-key" 634 }) 635 .to_string() 636 .as_str() 637 ) 638 .unwrap_err() 639 .to_string() 640 .into_bytes() 641 .get(..err.len()), 642 Some(err.as_slice()) 643 ); 644 // `null` `authenticatorData`. 645 err = Error::invalid_type(Unexpected::Other("null"), &"authenticatorData") 646 .to_string() 647 .into_bytes(); 648 assert_eq!( 649 serde_json::from_str::<Registration>( 650 serde_json::json!({ 651 "id": "AAAAAAAAAAAAAAAAAAAAAA", 652 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 653 "response": { 654 "clientDataJSON": b64_cdata_json, 655 "transports": [], 656 "authenticatorData": null, 657 "publicKey": b64_key, 658 "publicKeyAlgorithm": -8i8, 659 "attestationObject": b64_aobj, 660 }, 661 "clientExtensionResults": {}, 662 "type": "public-key" 663 }) 664 .to_string() 665 .as_str() 666 ) 667 .unwrap_err() 668 .to_string() 669 .into_bytes() 670 .get(..err.len()), 671 Some(err.as_slice()) 672 ); 673 // `publicKeyAlgorithm` mismatch. 674 err = Error::invalid_value( 675 Unexpected::Other(format!("{:?}", CoseAlgorithmIdentifier::Es256).as_str()), 676 &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {:?}", CoseAlgorithmIdentifier::Eddsa).as_str() 677 ) 678 .to_string().into_bytes(); 679 assert_eq!( 680 serde_json::from_str::<Registration>( 681 serde_json::json!({ 682 "id": "AAAAAAAAAAAAAAAAAAAAAA", 683 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 684 "response": { 685 "clientDataJSON": b64_cdata_json, 686 "authenticatorData": b64_adata, 687 "transports": [], 688 "publicKey": b64_key, 689 "publicKeyAlgorithm": -7i8, 690 "attestationObject": b64_aobj, 691 }, 692 "clientExtensionResults": {}, 693 "type": "public-key" 694 }) 695 .to_string() 696 .as_str() 697 ) 698 .unwrap_err() 699 .to_string() 700 .into_bytes() 701 .get(..err.len()), 702 Some(err.as_slice()) 703 ); 704 // Missing `publicKeyAlgorithm`. 705 err = Error::missing_field("publicKeyAlgorithm") 706 .to_string() 707 .into_bytes(); 708 assert_eq!( 709 serde_json::from_str::<Registration>( 710 serde_json::json!({ 711 "id": "AAAAAAAAAAAAAAAAAAAAAA", 712 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 713 "response": { 714 "clientDataJSON": b64_cdata_json, 715 "authenticatorData": b64_adata, 716 "transports": [], 717 "publicKey": b64_key, 718 "attestationObject": b64_aobj, 719 }, 720 "clientExtensionResults": {}, 721 "type": "public-key" 722 }) 723 .to_string() 724 .as_str() 725 ) 726 .unwrap_err() 727 .to_string() 728 .into_bytes() 729 .get(..err.len()), 730 Some(err.as_slice()) 731 ); 732 // `null` `publicKeyAlgorithm`. 733 err = Error::invalid_type(Unexpected::Other("null"), &"publicKeyAlgorithm") 734 .to_string() 735 .into_bytes(); 736 assert_eq!( 737 serde_json::from_str::<Registration>( 738 serde_json::json!({ 739 "id": "AAAAAAAAAAAAAAAAAAAAAA", 740 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 741 "response": { 742 "clientDataJSON": b64_cdata_json, 743 "authenticatorData": b64_adata, 744 "transports": [], 745 "publicKey": b64_key, 746 "publicKeyAlgorithm": null, 747 "attestationObject": b64_aobj, 748 }, 749 "clientExtensionResults": {}, 750 "type": "public-key" 751 }) 752 .to_string() 753 .as_str() 754 ) 755 .unwrap_err() 756 .to_string() 757 .into_bytes() 758 .get(..err.len()), 759 Some(err.as_slice()) 760 ); 761 // `publicKey` mismatch. 762 err = Error::invalid_value( 763 Unexpected::Bytes([0; 32].as_slice()), 764 &format!( 765 "DER-encoded public key to match the public key within the attestation object: Ed25519(Ed25519PubKey({:?}))", 766 &att_obj[att_obj.len() - 32..], 767 ) 768 .as_str(), 769 ) 770 .to_string().into_bytes(); 771 assert_eq!(serde_json::from_str::<Registration>( 772 serde_json::json!({ 773 "id": "AAAAAAAAAAAAAAAAAAAAAA", 774 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 775 "response": { 776 "clientDataJSON": b64_cdata_json, 777 "authenticatorData": b64_adata, 778 "transports": [], 779 "publicKey": base64url_nopad::encode(VerifyingKey::from_bytes(&[0; 32]).unwrap().to_public_key_der().unwrap().as_bytes()), 780 "publicKeyAlgorithm": -8i8, 781 "attestationObject": b64_aobj, 782 }, 783 "clientExtensionResults": {}, 784 "type": "public-key" 785 }) 786 .to_string() 787 .as_str() 788 ) 789 .unwrap_err().to_string().into_bytes().get(..err.len()), 790 Some(err.as_slice()) 791 ); 792 // Missing `publicKey` when using EdDSA, ES256, or RS256. 793 err = Error::missing_field("publicKey").to_string().into_bytes(); 794 assert_eq!( 795 serde_json::from_str::<Registration>( 796 serde_json::json!({ 797 "id": "AAAAAAAAAAAAAAAAAAAAAA", 798 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 799 "response": { 800 "clientDataJSON": b64_cdata_json, 801 "authenticatorData": b64_adata, 802 "transports": [], 803 "publicKeyAlgorithm": -8i8, 804 "attestationObject": b64_aobj, 805 }, 806 "clientExtensionResults": {}, 807 "type": "public-key" 808 }) 809 .to_string() 810 .as_str() 811 ) 812 .unwrap_err() 813 .to_string() 814 .into_bytes() 815 .get(..err.len()), 816 Some(err.as_slice()) 817 ); 818 // `null` `publicKey` when using EdDSA, ES256, or RS256. 819 err = Error::invalid_type(Unexpected::Other("null"), &"publicKey") 820 .to_string() 821 .into_bytes(); 822 assert_eq!( 823 serde_json::from_str::<Registration>( 824 serde_json::json!({ 825 "id": "AAAAAAAAAAAAAAAAAAAAAA", 826 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 827 "response": { 828 "clientDataJSON": b64_cdata_json, 829 "authenticatorData": b64_adata, 830 "transports": [], 831 "publicKey": null, 832 "publicKeyAlgorithm": -8i8, 833 "attestationObject": b64_aobj, 834 }, 835 "clientExtensionResults": {}, 836 "type": "public-key" 837 }) 838 .to_string() 839 .as_str() 840 ) 841 .unwrap_err() 842 .to_string() 843 .into_bytes() 844 .get(..err.len()), 845 Some(err.as_slice()) 846 ); 847 // Missing `transports`. 848 err = Error::missing_field("transports").to_string().into_bytes(); 849 assert_eq!( 850 serde_json::from_str::<Registration>( 851 serde_json::json!({ 852 "id": "AAAAAAAAAAAAAAAAAAAAAA", 853 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 854 "response": { 855 "clientDataJSON": b64_cdata_json, 856 "authenticatorData": b64_adata, 857 "publicKey": b64_key, 858 "publicKeyAlgorithm": -8i8, 859 "attestationObject": b64_aobj, 860 }, 861 "clientExtensionResults": {}, 862 "type": "public-key" 863 }) 864 .to_string() 865 .as_str() 866 ) 867 .unwrap_err() 868 .to_string() 869 .into_bytes() 870 .get(..err.len()), 871 Some(err.as_slice()) 872 ); 873 // Duplicate `transports` are allowed. 874 assert!( 875 serde_json::from_str::<Registration>( 876 serde_json::json!({ 877 "id": "AAAAAAAAAAAAAAAAAAAAAA", 878 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 879 "response": { 880 "clientDataJSON": b64_cdata_json, 881 "authenticatorData": b64_adata, 882 "transports": ["usb", "usb"], 883 "publicKey": b64_key, 884 "publicKeyAlgorithm": -8i8, 885 "attestationObject": b64_aobj, 886 }, 887 "clientExtensionResults": {}, 888 "type": "public-key" 889 }) 890 .to_string() 891 .as_str() 892 ) 893 .is_ok_and(|reg| reg.response.transports.count() == 1) 894 ); 895 // `null` `transports`. 896 err = Error::invalid_type(Unexpected::Other("null"), &"transports") 897 .to_string() 898 .into_bytes(); 899 assert_eq!( 900 serde_json::from_str::<Registration>( 901 serde_json::json!({ 902 "id": "AAAAAAAAAAAAAAAAAAAAAA", 903 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 904 "response": { 905 "clientDataJSON": b64_cdata_json, 906 "authenticatorData": b64_adata, 907 "transports": null, 908 "publicKey": b64_key, 909 "publicKeyAlgorithm": -8i8, 910 "attestationObject": b64_aobj, 911 }, 912 "clientExtensionResults": {}, 913 "type": "public-key" 914 }) 915 .to_string() 916 .as_str() 917 ) 918 .unwrap_err() 919 .to_string() 920 .into_bytes() 921 .get(..err.len()), 922 Some(err.as_slice()) 923 ); 924 // Unknown `transports`. 925 err = Error::invalid_value( 926 Unexpected::Str("Usb"), 927 &"'ble', 'cable', 'hybrid', 'internal', 'nfc', 'smart-card', or 'usb'", 928 ) 929 .to_string() 930 .into_bytes(); 931 assert_eq!( 932 serde_json::from_str::<Registration>( 933 serde_json::json!({ 934 "id": "AAAAAAAAAAAAAAAAAAAAAA", 935 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 936 "response": { 937 "clientDataJSON": b64_cdata_json, 938 "authenticatorData": b64_adata, 939 "transports": ["Usb"], 940 "publicKey": b64_key, 941 "publicKeyAlgorithm": -8i8, 942 "attestationObject": b64_aobj, 943 }, 944 "clientExtensionResults": {}, 945 "type": "public-key" 946 }) 947 .to_string() 948 .as_str() 949 ) 950 .unwrap_err() 951 .to_string() 952 .into_bytes() 953 .get(..err.len()), 954 Some(err.as_slice()) 955 ); 956 // `null` `authenticatorAttachment`. 957 assert!( 958 serde_json::from_str::<Registration>( 959 serde_json::json!({ 960 "id": "AAAAAAAAAAAAAAAAAAAAAA", 961 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 962 "response": { 963 "clientDataJSON": b64_cdata_json, 964 "authenticatorData": b64_adata, 965 "transports": [], 966 "publicKey": b64_key, 967 "publicKeyAlgorithm": -8i8, 968 "attestationObject": b64_aobj, 969 }, 970 "authenticatorAttachment": null, 971 "clientExtensionResults": {}, 972 "type": "public-key" 973 }) 974 .to_string() 975 .as_str() 976 ) 977 .is_ok_and(|reg| matches!(reg.authenticator_attachment, AuthenticatorAttachment::None)) 978 ); 979 // Unknown `authenticatorAttachment`. 980 err = Error::invalid_value( 981 Unexpected::Str("Platform"), 982 &"'platform' or 'cross-platform'", 983 ) 984 .to_string() 985 .into_bytes(); 986 assert_eq!( 987 serde_json::from_str::<Registration>( 988 serde_json::json!({ 989 "id": "AAAAAAAAAAAAAAAAAAAAAA", 990 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 991 "response": { 992 "clientDataJSON": b64_cdata_json, 993 "authenticatorData": b64_adata, 994 "transports": [], 995 "publicKey": b64_key, 996 "publicKeyAlgorithm": -8i8, 997 "attestationObject": b64_aobj, 998 }, 999 "authenticatorAttachment": "Platform", 1000 "clientExtensionResults": {}, 1001 "type": "public-key" 1002 }) 1003 .to_string() 1004 .as_str() 1005 ) 1006 .unwrap_err() 1007 .to_string() 1008 .into_bytes() 1009 .get(..err.len()), 1010 Some(err.as_slice()) 1011 ); 1012 // Missing `clientDataJSON`. 1013 err = Error::missing_field("clientDataJSON") 1014 .to_string() 1015 .into_bytes(); 1016 assert_eq!( 1017 serde_json::from_str::<Registration>( 1018 serde_json::json!({ 1019 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1020 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1021 "response": { 1022 "authenticatorData": b64_adata, 1023 "transports": [], 1024 "publicKey": b64_key, 1025 "publicKeyAlgorithm": -8i8, 1026 "attestationObject": b64_aobj, 1027 }, 1028 "clientExtensionResults": {}, 1029 "type": "public-key" 1030 }) 1031 .to_string() 1032 .as_str() 1033 ) 1034 .unwrap_err() 1035 .to_string() 1036 .into_bytes() 1037 .get(..err.len()), 1038 Some(err.as_slice()) 1039 ); 1040 // `null` `clientDataJSON`. 1041 err = Error::invalid_type(Unexpected::Other("null"), &"base64url-encoded data") 1042 .to_string() 1043 .into_bytes(); 1044 assert_eq!( 1045 serde_json::from_str::<Registration>( 1046 serde_json::json!({ 1047 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1048 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1049 "response": { 1050 "clientDataJSON": null, 1051 "authenticatorData": b64_adata, 1052 "transports": [], 1053 "publicKey": b64_key, 1054 "publicKeyAlgorithm": -8i8, 1055 "attestationObject": b64_aobj, 1056 }, 1057 "clientExtensionResults": {}, 1058 "type": "public-key" 1059 }) 1060 .to_string() 1061 .as_str() 1062 ) 1063 .unwrap_err() 1064 .to_string() 1065 .into_bytes() 1066 .get(..err.len()), 1067 Some(err.as_slice()) 1068 ); 1069 // Missing `attestationObject`. 1070 err = Error::missing_field("attestationObject") 1071 .to_string() 1072 .into_bytes(); 1073 assert_eq!( 1074 serde_json::from_str::<Registration>( 1075 serde_json::json!({ 1076 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1077 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1078 "response": { 1079 "clientDataJSON": b64_cdata_json, 1080 "authenticatorData": b64_adata, 1081 "transports": [], 1082 "publicKey": b64_key, 1083 "publicKeyAlgorithm": -8i8, 1084 }, 1085 "clientExtensionResults": {}, 1086 "type": "public-key" 1087 }) 1088 .to_string() 1089 .as_str() 1090 ) 1091 .unwrap_err() 1092 .to_string() 1093 .into_bytes() 1094 .get(..err.len()), 1095 Some(err.as_slice()) 1096 ); 1097 // `null` `attestationObject`. 1098 err = Error::invalid_type( 1099 Unexpected::Other("null"), 1100 &"base64url-encoded attestation object", 1101 ) 1102 .to_string() 1103 .into_bytes(); 1104 assert_eq!( 1105 serde_json::from_str::<Registration>( 1106 serde_json::json!({ 1107 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1108 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1109 "response": { 1110 "clientDataJSON": b64_cdata_json, 1111 "authenticatorData": b64_adata, 1112 "transports": [], 1113 "publicKey": b64_key, 1114 "publicKeyAlgorithm": -8i8, 1115 "attestationObject": null, 1116 }, 1117 "clientExtensionResults": {}, 1118 "type": "public-key" 1119 }) 1120 .to_string() 1121 .as_str() 1122 ) 1123 .unwrap_err() 1124 .to_string() 1125 .into_bytes() 1126 .get(..err.len()), 1127 Some(err.as_slice()) 1128 ); 1129 // Missing `response`. 1130 err = Error::missing_field("response").to_string().into_bytes(); 1131 assert_eq!( 1132 serde_json::from_str::<Registration>( 1133 serde_json::json!({ 1134 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1135 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1136 "clientExtensionResults": {}, 1137 "type": "public-key" 1138 }) 1139 .to_string() 1140 .as_str() 1141 ) 1142 .unwrap_err() 1143 .to_string() 1144 .into_bytes() 1145 .get(..err.len()), 1146 Some(err.as_slice()) 1147 ); 1148 // `null` `response`. 1149 err = Error::invalid_type(Unexpected::Other("null"), &"AuthenticatorAttestation") 1150 .to_string() 1151 .into_bytes(); 1152 assert_eq!( 1153 serde_json::from_str::<Registration>( 1154 serde_json::json!({ 1155 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1156 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1157 "response": null, 1158 "clientExtensionResults": {}, 1159 "type": "public-key" 1160 }) 1161 .to_string() 1162 .as_str() 1163 ) 1164 .unwrap_err() 1165 .to_string() 1166 .into_bytes() 1167 .get(..err.len()), 1168 Some(err.as_slice()) 1169 ); 1170 // Empty `response`. 1171 err = Error::missing_field("clientDataJSON") 1172 .to_string() 1173 .into_bytes(); 1174 assert_eq!( 1175 serde_json::from_str::<Registration>( 1176 serde_json::json!({ 1177 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1178 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1179 "response": {}, 1180 "clientExtensionResults": {}, 1181 "type": "public-key" 1182 }) 1183 .to_string() 1184 .as_str() 1185 ) 1186 .unwrap_err() 1187 .to_string() 1188 .into_bytes() 1189 .get(..err.len()), 1190 Some(err.as_slice()) 1191 ); 1192 // Missing `clientExtensionResults`. 1193 err = Error::missing_field("clientExtensionResults") 1194 .to_string() 1195 .into_bytes(); 1196 assert_eq!( 1197 serde_json::from_str::<Registration>( 1198 serde_json::json!({ 1199 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1200 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1201 "response": { 1202 "clientDataJSON": b64_cdata_json, 1203 "authenticatorData": b64_adata, 1204 "transports": [], 1205 "publicKey": b64_key, 1206 "publicKeyAlgorithm": -8i8, 1207 "attestationObject": b64_aobj, 1208 }, 1209 "type": "public-key" 1210 }) 1211 .to_string() 1212 .as_str() 1213 ) 1214 .unwrap_err() 1215 .to_string() 1216 .into_bytes() 1217 .get(..err.len()), 1218 Some(err.as_slice()) 1219 ); 1220 // `null` `clientExtensionResults`. 1221 err = Error::invalid_type( 1222 Unexpected::Other("null"), 1223 &"clientExtensionResults to be a map of allowed client extensions", 1224 ) 1225 .to_string() 1226 .into_bytes(); 1227 assert_eq!( 1228 serde_json::from_str::<Registration>( 1229 serde_json::json!({ 1230 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1231 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1232 "response": { 1233 "clientDataJSON": b64_cdata_json, 1234 "authenticatorData": b64_adata, 1235 "transports": [], 1236 "publicKey": b64_key, 1237 "publicKeyAlgorithm": -8i8, 1238 "attestationObject": b64_aobj, 1239 }, 1240 "clientExtensionResults": null, 1241 "type": "public-key" 1242 }) 1243 .to_string() 1244 .as_str() 1245 ) 1246 .unwrap_err() 1247 .to_string() 1248 .into_bytes() 1249 .get(..err.len()), 1250 Some(err.as_slice()) 1251 ); 1252 // Missing `type`. 1253 err = Error::missing_field("type").to_string().into_bytes(); 1254 assert_eq!( 1255 serde_json::from_str::<Registration>( 1256 serde_json::json!({ 1257 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1258 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1259 "response": { 1260 "clientDataJSON": b64_cdata_json, 1261 "authenticatorData": b64_adata, 1262 "transports": [], 1263 "publicKey": b64_key, 1264 "publicKeyAlgorithm": -8i8, 1265 "attestationObject": b64_aobj, 1266 }, 1267 "clientExtensionResults": {}, 1268 }) 1269 .to_string() 1270 .as_str() 1271 ) 1272 .unwrap_err() 1273 .to_string() 1274 .into_bytes() 1275 .get(..err.len()), 1276 Some(err.as_slice()) 1277 ); 1278 // `null` `type`. 1279 err = Error::invalid_type(Unexpected::Other("null"), &"public-key") 1280 .to_string() 1281 .into_bytes(); 1282 assert_eq!( 1283 serde_json::from_str::<Registration>( 1284 serde_json::json!({ 1285 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1286 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1287 "response": { 1288 "clientDataJSON": b64_cdata_json, 1289 "authenticatorData": b64_adata, 1290 "transports": [], 1291 "publicKey": b64_key, 1292 "publicKeyAlgorithm": -8i8, 1293 "attestationObject": b64_aobj, 1294 }, 1295 "clientExtensionResults": {}, 1296 "type": null 1297 }) 1298 .to_string() 1299 .as_str() 1300 ) 1301 .unwrap_err() 1302 .to_string() 1303 .into_bytes() 1304 .get(..err.len()), 1305 Some(err.as_slice()) 1306 ); 1307 // Not exactly `public-type` `type`. 1308 err = Error::invalid_value(Unexpected::Str("Public-key"), &"public-key") 1309 .to_string() 1310 .into_bytes(); 1311 assert_eq!( 1312 serde_json::from_str::<Registration>( 1313 serde_json::json!({ 1314 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1315 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1316 "response": { 1317 "clientDataJSON": b64_cdata_json, 1318 "authenticatorData": b64_adata, 1319 "transports": [], 1320 "publicKey": b64_key, 1321 "publicKeyAlgorithm": -8i8, 1322 "attestationObject": b64_aobj, 1323 }, 1324 "clientExtensionResults": {}, 1325 "type": "Public-key" 1326 }) 1327 .to_string() 1328 .as_str() 1329 ) 1330 .unwrap_err() 1331 .to_string() 1332 .into_bytes() 1333 .get(..err.len()), 1334 Some(err.as_slice()) 1335 ); 1336 // `null`. 1337 err = Error::invalid_type(Unexpected::Other("null"), &"PublicKeyCredential") 1338 .to_string() 1339 .into_bytes(); 1340 assert_eq!( 1341 serde_json::from_str::<Registration>(serde_json::json!(null).to_string().as_str()) 1342 .unwrap_err() 1343 .to_string() 1344 .into_bytes() 1345 .get(..err.len()), 1346 Some(err.as_slice()) 1347 ); 1348 // Empty. 1349 err = Error::missing_field("response").to_string().into_bytes(); 1350 assert_eq!( 1351 serde_json::from_str::<Registration>(serde_json::json!({}).to_string().as_str()) 1352 .unwrap_err() 1353 .to_string() 1354 .into_bytes() 1355 .get(..err.len()), 1356 Some(err.as_slice()) 1357 ); 1358 // Unknown field in `response`. 1359 err = Error::unknown_field( 1360 "foo", 1361 [ 1362 "clientDataJSON", 1363 "attestationObject", 1364 "authenticatorData", 1365 "transports", 1366 "publicKey", 1367 "publicKeyAlgorithm", 1368 ] 1369 .as_slice(), 1370 ) 1371 .to_string() 1372 .into_bytes(); 1373 assert_eq!( 1374 serde_json::from_str::<Registration>( 1375 serde_json::json!({ 1376 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1377 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1378 "response": { 1379 "clientDataJSON": b64_cdata_json, 1380 "authenticatorData": b64_adata, 1381 "transports": [], 1382 "publicKey": b64_key, 1383 "publicKeyAlgorithm": -8i8, 1384 "attestationObject": b64_aobj, 1385 "foo": true, 1386 }, 1387 "clientExtensionResults": {}, 1388 "type": "public-key" 1389 }) 1390 .to_string() 1391 .as_str() 1392 ) 1393 .unwrap_err() 1394 .to_string() 1395 .into_bytes() 1396 .get(..err.len()), 1397 Some(err.as_slice()) 1398 ); 1399 // Duplicate field in `response`. 1400 err = Error::duplicate_field("transports") 1401 .to_string() 1402 .into_bytes(); 1403 assert_eq!( 1404 serde_json::from_str::<Registration>( 1405 format!( 1406 "{{ 1407 \"id\": \"AAAAAAAAAAAAAAAAAAAAAA\", 1408 \"rawId\": \"AAAAAAAAAAAAAAAAAAAAAA\", 1409 \"response\": {{ 1410 \"clientDataJSON\": \"{b64_cdata_json}\", 1411 \"authenticatorData\": \"{b64_adata}\", 1412 \"transports\": [], 1413 \"publicKey\": \"{b64_key}\", 1414 \"publicKeyAlgorithm\": -8, 1415 \"attestationObject\": \"{b64_aobj}\", 1416 \"transports\": [] 1417 }}, 1418 \"clientExtensionResults\": {{}}, 1419 \"type\": \"public-key\" 1420 1421 }}" 1422 ) 1423 .as_str() 1424 ) 1425 .unwrap_err() 1426 .to_string() 1427 .into_bytes() 1428 .get(..err.len()), 1429 Some(err.as_slice()) 1430 ); 1431 // Unknown field in `PublicKeyCredential`. 1432 err = Error::unknown_field( 1433 "foo", 1434 [ 1435 "id", 1436 "type", 1437 "rawId", 1438 "response", 1439 "authenticatorAttachment", 1440 "clientExtensionResults", 1441 ] 1442 .as_slice(), 1443 ) 1444 .to_string() 1445 .into_bytes(); 1446 assert_eq!( 1447 serde_json::from_str::<Registration>( 1448 serde_json::json!({ 1449 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1450 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1451 "response": { 1452 "clientDataJSON": b64_cdata_json, 1453 "authenticatorData": b64_adata, 1454 "transports": [], 1455 "publicKey": b64_key, 1456 "publicKeyAlgorithm": -8i8, 1457 "attestationObject": b64_aobj 1458 }, 1459 "clientExtensionResults": {}, 1460 "type": "public-key", 1461 "foo": true, 1462 }) 1463 .to_string() 1464 .as_str() 1465 ) 1466 .unwrap_err() 1467 .to_string() 1468 .into_bytes() 1469 .get(..err.len()), 1470 Some(err.as_slice()) 1471 ); 1472 // Duplicate field in `PublicKeyCredential`. 1473 err = Error::duplicate_field("id").to_string().into_bytes(); 1474 assert_eq!( 1475 serde_json::from_str::<Registration>( 1476 format!( 1477 "{{ 1478 \"id\": \"AAAAAAAAAAAAAAAAAAAAAA\", 1479 \"id\": \"AAAAAAAAAAAAAAAAAAAAAA\", 1480 \"rawId\": \"AAAAAAAAAAAAAAAAAAAAAA\", 1481 \"response\": {{ 1482 \"clientDataJSON\": \"{b64_cdata_json}\", 1483 \"authenticatorData\": \"{b64_adata}\", 1484 \"transports\": [], 1485 \"publicKey\": \"{b64_key}\", 1486 \"publicKeyAlgorithm\": -8, 1487 \"attestationObject\": \"{b64_aobj}\" 1488 }}, 1489 \"clientExtensionResults\": {{}}, 1490 \"type\": \"public-key\" 1491 1492 }}" 1493 ) 1494 .as_str() 1495 ) 1496 .unwrap_err() 1497 .to_string() 1498 .into_bytes() 1499 .get(..err.len()), 1500 Some(err.as_slice()) 1501 ); 1502 } 1503 #[expect(clippy::unwrap_used, reason = "OK in tests")] 1504 #[expect(clippy::indexing_slicing, reason = "comments justify correctness")] 1505 #[expect( 1506 clippy::cognitive_complexity, 1507 clippy::too_many_lines, 1508 reason = "a lot to test" 1509 )] 1510 #[test] 1511 fn client_extensions() { 1512 let c_data_json = serde_json::json!({}).to_string(); 1513 let att_obj: [u8; 143] = [ 1514 cbor::MAP_3, 1515 cbor::TEXT_3, 1516 b'f', 1517 b'm', 1518 b't', 1519 cbor::TEXT_4, 1520 b'n', 1521 b'o', 1522 b'n', 1523 b'e', 1524 cbor::TEXT_7, 1525 b'a', 1526 b't', 1527 b't', 1528 b'S', 1529 b't', 1530 b'm', 1531 b't', 1532 cbor::MAP_0, 1533 cbor::TEXT_8, 1534 b'a', 1535 b'u', 1536 b't', 1537 b'h', 1538 b'D', 1539 b'a', 1540 b't', 1541 b'a', 1542 cbor::BYTES_INFO_24, 1543 113, 1544 // `rpIdHash`. 1545 0, 1546 0, 1547 0, 1548 0, 1549 0, 1550 0, 1551 0, 1552 0, 1553 0, 1554 0, 1555 0, 1556 0, 1557 0, 1558 0, 1559 0, 1560 0, 1561 0, 1562 0, 1563 0, 1564 0, 1565 0, 1566 0, 1567 0, 1568 0, 1569 0, 1570 0, 1571 0, 1572 0, 1573 0, 1574 0, 1575 0, 1576 0, 1577 // `flags`. 1578 0b0100_0101, 1579 // `signCount`. 1580 0, 1581 0, 1582 0, 1583 0, 1584 // `aaguid`. 1585 0, 1586 0, 1587 0, 1588 0, 1589 0, 1590 0, 1591 0, 1592 0, 1593 0, 1594 0, 1595 0, 1596 0, 1597 0, 1598 0, 1599 0, 1600 0, 1601 // `credentialIdLength`. 1602 0, 1603 16, 1604 // `credentialId`. 1605 0, 1606 0, 1607 0, 1608 0, 1609 0, 1610 0, 1611 0, 1612 0, 1613 0, 1614 0, 1615 0, 1616 0, 1617 0, 1618 0, 1619 0, 1620 0, 1621 // Ed25519 COSE key. 1622 cbor::MAP_4, 1623 KTY, 1624 OKP, 1625 ALG, 1626 EDDSA, 1627 // `crv`. 1628 cbor::NEG_ONE, 1629 // `Ed25519`. 1630 cbor::SIX, 1631 // `x`. 1632 cbor::NEG_TWO, 1633 cbor::BYTES_INFO_24, 1634 32, 1635 // Compressed y-coordinate. 1636 1, 1637 1, 1638 1, 1639 1, 1640 1, 1641 1, 1642 1, 1643 1, 1644 1, 1645 1, 1646 1, 1647 1, 1648 1, 1649 1, 1650 1, 1651 1, 1652 1, 1653 1, 1654 1, 1655 1, 1656 1, 1657 1, 1658 1, 1659 1, 1660 1, 1661 1, 1662 1, 1663 1, 1664 1, 1665 1, 1666 1, 1667 1, 1668 ]; 1669 let pub_key = VerifyingKey::from_bytes(&[1; 32]) 1670 .unwrap() 1671 .to_public_key_der() 1672 .unwrap(); 1673 let b64_cdata_json = base64url_nopad::encode(c_data_json.as_bytes()); 1674 let b64_adata = base64url_nopad::encode(&att_obj[att_obj.len() - 113..]); 1675 let b64_key = base64url_nopad::encode(pub_key.as_bytes()); 1676 let b64_aobj = base64url_nopad::encode(att_obj.as_slice()); 1677 // Base case is valid. 1678 assert!( 1679 serde_json::from_str::<Registration>( 1680 serde_json::json!({ 1681 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1682 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1683 "response": { 1684 "clientDataJSON": b64_cdata_json, 1685 "authenticatorData": b64_adata, 1686 "transports": [], 1687 "publicKey": b64_key, 1688 "publicKeyAlgorithm": -8i8, 1689 "attestationObject": b64_aobj, 1690 }, 1691 "clientExtensionResults": {}, 1692 "type": "public-key" 1693 }) 1694 .to_string() 1695 .as_str() 1696 ) 1697 .is_ok_and( 1698 |reg| reg.response.client_data_json == c_data_json.as_bytes() 1699 && reg.response.attestation_object_and_c_data_hash[..att_obj.len()] == att_obj 1700 && reg.response.attestation_object_and_c_data_hash[att_obj.len()..] 1701 == *Sha256::digest(c_data_json.as_bytes()) 1702 && reg.response.transports.is_empty() 1703 && matches!(reg.authenticator_attachment, AuthenticatorAttachment::None) 1704 && reg.client_extension_results.cred_props.is_none() 1705 && reg.client_extension_results.prf.is_none() 1706 ) 1707 ); 1708 // `null` `credProps`. 1709 assert!( 1710 serde_json::from_str::<Registration>( 1711 serde_json::json!({ 1712 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1713 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1714 "response": { 1715 "clientDataJSON": b64_cdata_json, 1716 "authenticatorData": b64_adata, 1717 "transports": [], 1718 "publicKey": b64_key, 1719 "publicKeyAlgorithm": -8i8, 1720 "attestationObject": b64_aobj, 1721 }, 1722 "clientExtensionResults": { 1723 "credProps": null 1724 }, 1725 "type": "public-key" 1726 }) 1727 .to_string() 1728 .as_str() 1729 ) 1730 .is_ok_and(|reg| reg.client_extension_results.cred_props.is_none() 1731 && reg.client_extension_results.prf.is_none()) 1732 ); 1733 // `null` `prf`. 1734 assert!( 1735 serde_json::from_str::<Registration>( 1736 serde_json::json!({ 1737 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1738 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1739 "response": { 1740 "clientDataJSON": b64_cdata_json, 1741 "authenticatorData": b64_adata, 1742 "transports": [], 1743 "publicKey": b64_key, 1744 "publicKeyAlgorithm": -8i8, 1745 "attestationObject": b64_aobj, 1746 }, 1747 "clientExtensionResults": { 1748 "prf": null 1749 }, 1750 "type": "public-key" 1751 }) 1752 .to_string() 1753 .as_str() 1754 ) 1755 .is_ok_and(|reg| reg.client_extension_results.cred_props.is_none() 1756 && reg.client_extension_results.prf.is_none()) 1757 ); 1758 // Unknown `clientExtensionResults`. 1759 let mut err = Error::unknown_field("CredProps", ["credProps", "prf"].as_slice()) 1760 .to_string() 1761 .into_bytes(); 1762 assert_eq!( 1763 serde_json::from_str::<Registration>( 1764 serde_json::json!({ 1765 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1766 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1767 "response": { 1768 "clientDataJSON": b64_cdata_json, 1769 "authenticatorData": b64_adata, 1770 "transports": [], 1771 "publicKey": b64_key, 1772 "publicKeyAlgorithm": -8i8, 1773 "attestationObject": b64_aobj, 1774 }, 1775 "clientExtensionResults": { 1776 "CredProps": { 1777 "rk": true 1778 } 1779 }, 1780 "type": "public-key" 1781 }) 1782 .to_string() 1783 .as_str() 1784 ) 1785 .unwrap_err() 1786 .to_string() 1787 .into_bytes() 1788 .get(..err.len()), 1789 Some(err.as_slice()) 1790 ); 1791 // Duplicate field. 1792 err = Error::duplicate_field("credProps").to_string().into_bytes(); 1793 assert_eq!( 1794 serde_json::from_str::<Registration>( 1795 format!( 1796 "{{ 1797 \"id\": \"AAAAAAAAAAAAAAAAAAAAAA\", 1798 \"rawId\": \"AAAAAAAAAAAAAAAAAAAAAA\", 1799 \"response\": {{ 1800 \"clientDataJSON\": \"{b64_cdata_json}\", 1801 \"authenticatorData\": \"{b64_adata}\", 1802 \"transports\": [], 1803 \"publicKey\": \"{b64_key}\", 1804 \"publicKeyAlgorithm\": -8, 1805 \"attestationObject\": \"{b64_aobj}\" 1806 }}, 1807 \"clientExtensionResults\": {{ 1808 \"credProps\": null, 1809 \"credProps\": null 1810 }}, 1811 \"type\": \"public-key\" 1812 }}" 1813 ) 1814 .as_str() 1815 ) 1816 .unwrap_err() 1817 .to_string() 1818 .into_bytes() 1819 .get(..err.len()), 1820 Some(err.as_slice()) 1821 ); 1822 // `null` `rk`. 1823 assert!( 1824 serde_json::from_str::<Registration>( 1825 serde_json::json!({ 1826 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1827 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1828 "response": { 1829 "clientDataJSON": b64_cdata_json, 1830 "authenticatorData": b64_adata, 1831 "transports": [], 1832 "publicKey": b64_key, 1833 "publicKeyAlgorithm": -8i8, 1834 "attestationObject": b64_aobj, 1835 }, 1836 "clientExtensionResults": { 1837 "credProps": { 1838 "rk": null 1839 } 1840 }, 1841 "type": "public-key" 1842 }) 1843 .to_string() 1844 .as_str() 1845 ) 1846 .is_ok_and(|reg| reg 1847 .client_extension_results 1848 .cred_props 1849 .is_some_and(|props| props.rk.is_none()) 1850 && reg.client_extension_results.prf.is_none()) 1851 ); 1852 // Missing `rk`. 1853 assert!( 1854 serde_json::from_str::<Registration>( 1855 serde_json::json!({ 1856 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1857 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1858 "response": { 1859 "clientDataJSON": b64_cdata_json, 1860 "authenticatorData": b64_adata, 1861 "transports": [], 1862 "publicKey": b64_key, 1863 "publicKeyAlgorithm": -8i8, 1864 "attestationObject": b64_aobj, 1865 }, 1866 "clientExtensionResults": { 1867 "credProps": {} 1868 }, 1869 "type": "public-key" 1870 }) 1871 .to_string() 1872 .as_str() 1873 ) 1874 .is_ok_and(|reg| reg 1875 .client_extension_results 1876 .cred_props 1877 .is_some_and(|props| props.rk.is_none()) 1878 && reg.client_extension_results.prf.is_none()) 1879 ); 1880 // `true` rk`. 1881 assert!( 1882 serde_json::from_str::<Registration>( 1883 serde_json::json!({ 1884 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1885 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1886 "response": { 1887 "clientDataJSON": b64_cdata_json, 1888 "authenticatorData": b64_adata, 1889 "transports": [], 1890 "publicKey": b64_key, 1891 "publicKeyAlgorithm": -8i8, 1892 "attestationObject": b64_aobj, 1893 }, 1894 "clientExtensionResults": { 1895 "credProps": { 1896 "rk": true 1897 } 1898 }, 1899 "type": "public-key" 1900 }) 1901 .to_string() 1902 .as_str() 1903 ) 1904 .is_ok_and(|reg| reg 1905 .client_extension_results 1906 .cred_props 1907 .is_some_and(|props| props.rk.unwrap_or_default()) 1908 && reg.client_extension_results.prf.is_none()) 1909 ); 1910 // `false` rk`. 1911 assert!( 1912 serde_json::from_str::<Registration>( 1913 serde_json::json!({ 1914 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1915 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1916 "response": { 1917 "clientDataJSON": b64_cdata_json, 1918 "authenticatorData": b64_adata, 1919 "transports": [], 1920 "publicKey": b64_key, 1921 "publicKeyAlgorithm": -8i8, 1922 "attestationObject": b64_aobj, 1923 }, 1924 "clientExtensionResults": { 1925 "credProps": { 1926 "rk": false 1927 } 1928 }, 1929 "type": "public-key" 1930 }) 1931 .to_string() 1932 .as_str() 1933 ) 1934 .is_ok_and(|reg| reg 1935 .client_extension_results 1936 .cred_props 1937 .is_some_and(|props| props.rk.is_some_and(|rk| !rk)) 1938 && reg.client_extension_results.prf.is_none()) 1939 ); 1940 // Invalid `rk`. 1941 err = Error::invalid_type(Unexpected::Unsigned(3), &"a boolean") 1942 .to_string() 1943 .into_bytes(); 1944 assert_eq!( 1945 serde_json::from_str::<Registration>( 1946 serde_json::json!({ 1947 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1948 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1949 "response": { 1950 "clientDataJSON": b64_cdata_json, 1951 "authenticatorData": b64_adata, 1952 "transports": [], 1953 "publicKey": b64_key, 1954 "publicKeyAlgorithm": -8i8, 1955 "attestationObject": b64_aobj, 1956 }, 1957 "clientExtensionResults": { 1958 "credProps": { 1959 "rk": 3u8 1960 } 1961 }, 1962 "type": "public-key" 1963 }) 1964 .to_string() 1965 .as_str() 1966 ) 1967 .unwrap_err() 1968 .to_string() 1969 .into_bytes() 1970 .get(..err.len()), 1971 Some(err.as_slice()) 1972 ); 1973 // Unknown `credProps` field. 1974 err = Error::unknown_field("Rk", ["rk"].as_slice()) 1975 .to_string() 1976 .into_bytes(); 1977 assert_eq!( 1978 serde_json::from_str::<Registration>( 1979 serde_json::json!({ 1980 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1981 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1982 "response": { 1983 "clientDataJSON": b64_cdata_json, 1984 "authenticatorData": b64_adata, 1985 "transports": [], 1986 "publicKey": b64_key, 1987 "publicKeyAlgorithm": -8i8, 1988 "attestationObject": b64_aobj, 1989 }, 1990 "clientExtensionResults": { 1991 "credProps": { 1992 "Rk": true, 1993 } 1994 }, 1995 "type": "public-key" 1996 }) 1997 .to_string() 1998 .as_str() 1999 ) 2000 .unwrap_err() 2001 .to_string() 2002 .into_bytes() 2003 .get(..err.len()), 2004 Some(err.as_slice()) 2005 ); 2006 // Duplicate field in `credProps`. 2007 err = Error::duplicate_field("rk").to_string().into_bytes(); 2008 assert_eq!( 2009 serde_json::from_str::<Registration>( 2010 format!( 2011 "{{ 2012 \"id\": \"AAAAAAAAAAAAAAAAAAAAAA\", 2013 \"rawId\": \"AAAAAAAAAAAAAAAAAAAAAA\", 2014 \"response\": {{ 2015 \"clientDataJSON\": \"{b64_cdata_json}\", 2016 \"authenticatorData\": \"{b64_adata}\", 2017 \"transports\": [], 2018 \"publicKey\": \"{b64_key}\", 2019 \"publicKeyAlgorithm\": -8, 2020 \"attestationObject\": \"{b64_aobj}\" 2021 }}, 2022 \"clientExtensionResults\": {{ 2023 \"credProps\": {{ 2024 \"rk\": true, 2025 \"rk\": true 2026 }} 2027 }}, 2028 \"type\": \"public-key\" 2029 }}" 2030 ) 2031 .as_str() 2032 ) 2033 .unwrap_err() 2034 .to_string() 2035 .into_bytes() 2036 .get(..err.len()), 2037 Some(err.as_slice()) 2038 ); 2039 // `null` `enabled`. 2040 err = Error::invalid_type(Unexpected::Other("null"), &"a boolean") 2041 .to_string() 2042 .into_bytes(); 2043 assert_eq!( 2044 serde_json::from_str::<Registration>( 2045 serde_json::json!({ 2046 "id": "AAAAAAAAAAAAAAAAAAAAAA", 2047 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 2048 "response": { 2049 "clientDataJSON": b64_cdata_json, 2050 "authenticatorData": b64_adata, 2051 "transports": [], 2052 "publicKey": b64_key, 2053 "publicKeyAlgorithm": -8i8, 2054 "attestationObject": b64_aobj, 2055 }, 2056 "clientExtensionResults": { 2057 "prf": { 2058 "enabled": null 2059 } 2060 }, 2061 "type": "public-key" 2062 }) 2063 .to_string() 2064 .as_str() 2065 ) 2066 .unwrap_err() 2067 .to_string() 2068 .into_bytes() 2069 .get(..err.len()), 2070 Some(err.as_slice()) 2071 ); 2072 // Missing `enabled`. 2073 err = Error::missing_field("enabled").to_string().into_bytes(); 2074 assert_eq!( 2075 serde_json::from_str::<Registration>( 2076 serde_json::json!({ 2077 "id": "AAAAAAAAAAAAAAAAAAAAAA", 2078 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 2079 "response": { 2080 "clientDataJSON": b64_cdata_json, 2081 "authenticatorData": b64_adata, 2082 "transports": [], 2083 "publicKey": b64_key, 2084 "publicKeyAlgorithm": -8i8, 2085 "attestationObject": b64_aobj, 2086 }, 2087 "clientExtensionResults": { 2088 "prf": {} 2089 }, 2090 "type": "public-key" 2091 }) 2092 .to_string() 2093 .as_str() 2094 ) 2095 .unwrap_err() 2096 .to_string() 2097 .into_bytes() 2098 .get(..err.len()), 2099 Some(err.as_slice()) 2100 ); 2101 // `true` `enabled`. 2102 assert!( 2103 serde_json::from_str::<Registration>( 2104 serde_json::json!({ 2105 "id": "AAAAAAAAAAAAAAAAAAAAAA", 2106 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 2107 "response": { 2108 "clientDataJSON": b64_cdata_json, 2109 "authenticatorData": b64_adata, 2110 "transports": [], 2111 "publicKey": b64_key, 2112 "publicKeyAlgorithm": -8i8, 2113 "attestationObject": b64_aobj, 2114 }, 2115 "clientExtensionResults": { 2116 "prf": { 2117 "enabled": true 2118 } 2119 }, 2120 "type": "public-key" 2121 }) 2122 .to_string() 2123 .as_str() 2124 ) 2125 .is_ok_and(|reg| reg.client_extension_results.cred_props.is_none() 2126 && reg 2127 .client_extension_results 2128 .prf 2129 .is_some_and(|prf| prf.enabled)) 2130 ); 2131 // `false` `enabled`. 2132 assert!( 2133 serde_json::from_str::<Registration>( 2134 serde_json::json!({ 2135 "id": "AAAAAAAAAAAAAAAAAAAAAA", 2136 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 2137 "response": { 2138 "clientDataJSON": b64_cdata_json, 2139 "authenticatorData": b64_adata, 2140 "transports": [], 2141 "publicKey": b64_key, 2142 "publicKeyAlgorithm": -8i8, 2143 "attestationObject": b64_aobj, 2144 }, 2145 "clientExtensionResults": { 2146 "prf": { 2147 "enabled": false, 2148 } 2149 }, 2150 "type": "public-key" 2151 }) 2152 .to_string() 2153 .as_str() 2154 ) 2155 .is_ok_and(|reg| reg.client_extension_results.cred_props.is_none() 2156 && reg 2157 .client_extension_results 2158 .prf 2159 .is_some_and(|prf| !prf.enabled)) 2160 ); 2161 // Invalid `enabled`. 2162 err = Error::invalid_type(Unexpected::Unsigned(3), &"a boolean") 2163 .to_string() 2164 .into_bytes(); 2165 assert_eq!( 2166 serde_json::from_str::<Registration>( 2167 serde_json::json!({ 2168 "id": "AAAAAAAAAAAAAAAAAAAAAA", 2169 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 2170 "response": { 2171 "clientDataJSON": b64_cdata_json, 2172 "authenticatorData": b64_adata, 2173 "transports": [], 2174 "publicKey": b64_key, 2175 "publicKeyAlgorithm": -8i8, 2176 "attestationObject": b64_aobj, 2177 }, 2178 "clientExtensionResults": { 2179 "prf": { 2180 "enabled": 3u8 2181 } 2182 }, 2183 "type": "public-key" 2184 }) 2185 .to_string() 2186 .as_str() 2187 ) 2188 .unwrap_err() 2189 .to_string() 2190 .into_bytes() 2191 .get(..err.len()), 2192 Some(err.as_slice()) 2193 ); 2194 // `null` `results` with `enabled` `true`. 2195 assert!( 2196 serde_json::from_str::<Registration>( 2197 serde_json::json!({ 2198 "id": "AAAAAAAAAAAAAAAAAAAAAA", 2199 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 2200 "response": { 2201 "clientDataJSON": b64_cdata_json, 2202 "authenticatorData": b64_adata, 2203 "transports": [], 2204 "publicKey": b64_key, 2205 "publicKeyAlgorithm": -8i8, 2206 "attestationObject": b64_aobj, 2207 }, 2208 "clientExtensionResults": { 2209 "prf": { 2210 "enabled": true, 2211 "results": null, 2212 } 2213 }, 2214 "type": "public-key" 2215 }) 2216 .to_string() 2217 .as_str() 2218 ) 2219 .is_ok_and(|reg| reg.client_extension_results.cred_props.is_none() 2220 && reg 2221 .client_extension_results 2222 .prf 2223 .is_some_and(|prf| prf.enabled)) 2224 ); 2225 // `null` `results` with `enabled` `false`. 2226 err = Error::custom( 2227 "prf must not have 'results', including a null 'results', if 'enabled' is false", 2228 ) 2229 .to_string() 2230 .into_bytes(); 2231 assert_eq!( 2232 serde_json::from_str::<Registration>( 2233 serde_json::json!({ 2234 "id": "AAAAAAAAAAAAAAAAAAAAAA", 2235 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 2236 "response": { 2237 "clientDataJSON": b64_cdata_json, 2238 "authenticatorData": b64_adata, 2239 "transports": [], 2240 "publicKey": b64_key, 2241 "publicKeyAlgorithm": -8i8, 2242 "attestationObject": b64_aobj, 2243 }, 2244 "clientExtensionResults": { 2245 "prf": { 2246 "enabled": false, 2247 "results": null 2248 } 2249 }, 2250 "type": "public-key" 2251 }) 2252 .to_string() 2253 .as_str() 2254 ) 2255 .unwrap_err() 2256 .to_string() 2257 .into_bytes() 2258 .get(..err.len()), 2259 Some(err.as_slice()) 2260 ); 2261 // Duplicate field in `prf`. 2262 err = Error::duplicate_field("enabled").to_string().into_bytes(); 2263 assert_eq!( 2264 serde_json::from_str::<Registration>( 2265 format!( 2266 "{{ 2267 \"id\": \"AAAAAAAAAAAAAAAAAAAAAA\", 2268 \"rawId\": \"AAAAAAAAAAAAAAAAAAAAAA\", 2269 \"response\": {{ 2270 \"clientDataJSON\": \"{b64_cdata_json}\", 2271 \"authenticatorData\": \"{b64_adata}\", 2272 \"transports\": [], 2273 \"publicKey\": \"{b64_key}\", 2274 \"publicKeyAlgorithm\": -8, 2275 \"attestationObject\": \"{b64_aobj}\" 2276 }}, 2277 \"clientExtensionResults\": {{ 2278 \"prf\": {{ 2279 \"enabled\": true, 2280 \"enabled\": true 2281 }} 2282 }}, 2283 \"type\": \"public-key\" 2284 }}" 2285 ) 2286 .as_str() 2287 ) 2288 .unwrap_err() 2289 .to_string() 2290 .into_bytes() 2291 .get(..err.len()), 2292 Some(err.as_slice()) 2293 ); 2294 // Missing `first`. 2295 err = Error::missing_field("first").to_string().into_bytes(); 2296 assert_eq!( 2297 serde_json::from_str::<Registration>( 2298 serde_json::json!({ 2299 "id": "AAAAAAAAAAAAAAAAAAAAAA", 2300 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 2301 "response": { 2302 "clientDataJSON": b64_cdata_json, 2303 "authenticatorData": b64_adata, 2304 "transports": [], 2305 "publicKey": b64_key, 2306 "publicKeyAlgorithm": -8i8, 2307 "attestationObject": b64_aobj, 2308 }, 2309 "clientExtensionResults": { 2310 "prf": { 2311 "enabled": true, 2312 "results": {}, 2313 } 2314 }, 2315 "type": "public-key" 2316 }) 2317 .to_string() 2318 .as_str() 2319 ) 2320 .unwrap_err() 2321 .to_string() 2322 .into_bytes() 2323 .get(..err.len()), 2324 Some(err.as_slice()) 2325 ); 2326 // `null` `first`. 2327 assert!( 2328 serde_json::from_str::<Registration>( 2329 serde_json::json!({ 2330 "id": "AAAAAAAAAAAAAAAAAAAAAA", 2331 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 2332 "response": { 2333 "clientDataJSON": b64_cdata_json, 2334 "authenticatorData": b64_adata, 2335 "transports": [], 2336 "publicKey": b64_key, 2337 "publicKeyAlgorithm": -8i8, 2338 "attestationObject": b64_aobj, 2339 }, 2340 "clientExtensionResults": { 2341 "prf": { 2342 "enabled": true, 2343 "results": { 2344 "first": null 2345 }, 2346 } 2347 }, 2348 "type": "public-key" 2349 }) 2350 .to_string() 2351 .as_str() 2352 ) 2353 .is_ok_and(|reg| reg.client_extension_results.cred_props.is_none() 2354 && reg 2355 .client_extension_results 2356 .prf 2357 .is_some_and(|prf| prf.enabled)) 2358 ); 2359 // `null` `second`. 2360 assert!( 2361 serde_json::from_str::<Registration>( 2362 serde_json::json!({ 2363 "id": "AAAAAAAAAAAAAAAAAAAAAA", 2364 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 2365 "response": { 2366 "clientDataJSON": b64_cdata_json, 2367 "authenticatorData": b64_adata, 2368 "transports": [], 2369 "publicKey": b64_key, 2370 "publicKeyAlgorithm": -8i8, 2371 "attestationObject": b64_aobj, 2372 }, 2373 "clientExtensionResults": { 2374 "prf": { 2375 "enabled": true, 2376 "results": { 2377 "first": null, 2378 "second": null 2379 }, 2380 } 2381 }, 2382 "type": "public-key" 2383 }) 2384 .to_string() 2385 .as_str() 2386 ) 2387 .is_ok_and(|reg| reg.client_extension_results.cred_props.is_none() 2388 && reg 2389 .client_extension_results 2390 .prf 2391 .is_some_and(|prf| prf.enabled)) 2392 ); 2393 // Non-`null` `first`. 2394 err = Error::invalid_type(Unexpected::Option, &"null") 2395 .to_string() 2396 .into_bytes(); 2397 assert_eq!( 2398 serde_json::from_str::<Registration>( 2399 serde_json::json!({ 2400 "id": "AAAAAAAAAAAAAAAAAAAAAA", 2401 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 2402 "response": { 2403 "clientDataJSON": b64_cdata_json, 2404 "authenticatorData": b64_adata, 2405 "transports": [], 2406 "publicKey": b64_key, 2407 "publicKeyAlgorithm": -8i8, 2408 "attestationObject": b64_aobj, 2409 }, 2410 "clientExtensionResults": { 2411 "prf": { 2412 "enabled": true, 2413 "results": { 2414 "first": "" 2415 }, 2416 } 2417 }, 2418 "type": "public-key" 2419 }) 2420 .to_string() 2421 .as_str() 2422 ) 2423 .unwrap_err() 2424 .to_string() 2425 .into_bytes() 2426 .get(..err.len()), 2427 Some(err.as_slice()) 2428 ); 2429 // Non-`null` `second`. 2430 err = Error::invalid_type(Unexpected::Option, &"null") 2431 .to_string() 2432 .into_bytes(); 2433 assert_eq!( 2434 serde_json::from_str::<Registration>( 2435 serde_json::json!({ 2436 "id": "AAAAAAAAAAAAAAAAAAAAAA", 2437 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 2438 "response": { 2439 "clientDataJSON": b64_cdata_json, 2440 "authenticatorData": b64_adata, 2441 "transports": [], 2442 "publicKey": b64_key, 2443 "publicKeyAlgorithm": -8i8, 2444 "attestationObject": b64_aobj, 2445 }, 2446 "clientExtensionResults": { 2447 "prf": { 2448 "enabled": true, 2449 "results": { 2450 "first": null, 2451 "second": "" 2452 }, 2453 } 2454 }, 2455 "type": "public-key" 2456 }) 2457 .to_string() 2458 .as_str() 2459 ) 2460 .unwrap_err() 2461 .to_string() 2462 .into_bytes() 2463 .get(..err.len()), 2464 Some(err.as_slice()) 2465 ); 2466 // Unknown `prf` field. 2467 err = Error::unknown_field("Results", ["enabled", "results"].as_slice()) 2468 .to_string() 2469 .into_bytes(); 2470 assert_eq!( 2471 serde_json::from_str::<Registration>( 2472 serde_json::json!({ 2473 "id": "AAAAAAAAAAAAAAAAAAAAAA", 2474 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 2475 "response": { 2476 "clientDataJSON": b64_cdata_json, 2477 "authenticatorData": b64_adata, 2478 "transports": [], 2479 "publicKey": b64_key, 2480 "publicKeyAlgorithm": -8i8, 2481 "attestationObject": b64_aobj, 2482 }, 2483 "clientExtensionResults": { 2484 "prf": { 2485 "enabled": true, 2486 "Results": null 2487 } 2488 }, 2489 "type": "public-key" 2490 }) 2491 .to_string() 2492 .as_str() 2493 ) 2494 .unwrap_err() 2495 .to_string() 2496 .into_bytes() 2497 .get(..err.len()), 2498 Some(err.as_slice()) 2499 ); 2500 // Unknown `results` field. 2501 err = Error::unknown_field("Second", ["first", "second"].as_slice()) 2502 .to_string() 2503 .into_bytes(); 2504 assert_eq!( 2505 serde_json::from_str::<Registration>( 2506 serde_json::json!({ 2507 "id": "AAAAAAAAAAAAAAAAAAAAAA", 2508 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 2509 "response": { 2510 "clientDataJSON": b64_cdata_json, 2511 "authenticatorData": b64_adata, 2512 "transports": [], 2513 "publicKey": b64_key, 2514 "publicKeyAlgorithm": -8i8, 2515 "attestationObject": b64_aobj, 2516 }, 2517 "clientExtensionResults": { 2518 "prf": { 2519 "enabled": true, 2520 "results": { 2521 "first": null, 2522 "Second": null 2523 } 2524 } 2525 }, 2526 "type": "public-key" 2527 }) 2528 .to_string() 2529 .as_str() 2530 ) 2531 .unwrap_err() 2532 .to_string() 2533 .into_bytes() 2534 .get(..err.len()), 2535 Some(err.as_slice()) 2536 ); 2537 // Duplicate field in `results`. 2538 err = Error::duplicate_field("first").to_string().into_bytes(); 2539 assert_eq!( 2540 serde_json::from_str::<Registration>( 2541 format!( 2542 "{{ 2543 \"id\": \"AAAAAAAAAAAAAAAAAAAAAA\", 2544 \"rawId\": \"AAAAAAAAAAAAAAAAAAAAAA\", 2545 \"response\": {{ 2546 \"clientDataJSON\": \"{b64_cdata_json}\", 2547 \"authenticatorData\": \"{b64_adata}\", 2548 \"transports\": [], 2549 \"publicKey\": \"{b64_key}\", 2550 \"publicKeyAlgorithm\": -8, 2551 \"attestationObject\": \"{b64_aobj}\" 2552 }}, 2553 \"clientExtensionResults\": {{ 2554 \"prf\": {{ 2555 \"enabled\": true, 2556 \"results\": {{ 2557 \"first\": null, 2558 \"first\": null 2559 }} 2560 }} 2561 }}, 2562 \"type\": \"public-key\" 2563 }}" 2564 ) 2565 .as_str() 2566 ) 2567 .unwrap_err() 2568 .to_string() 2569 .into_bytes() 2570 .get(..err.len()), 2571 Some(err.as_slice()) 2572 ); 2573 } 2574 #[expect( 2575 clippy::assertions_on_result_states, 2576 clippy::unwrap_used, 2577 reason = "OK in tests" 2578 )] 2579 #[expect(clippy::indexing_slicing, reason = "comments justify correctness")] 2580 #[expect(clippy::too_many_lines, reason = "a lot to test")] 2581 #[test] 2582 fn mldsa87_registration_deserialize_data_mismatch() { 2583 let c_data_json = serde_json::json!({}).to_string(); 2584 let att_obj: [u8; 2704] = [ 2585 cbor::MAP_3, 2586 cbor::TEXT_3, 2587 b'f', 2588 b'm', 2589 b't', 2590 cbor::TEXT_4, 2591 b'n', 2592 b'o', 2593 b'n', 2594 b'e', 2595 cbor::TEXT_7, 2596 b'a', 2597 b't', 2598 b't', 2599 b'S', 2600 b't', 2601 b'm', 2602 b't', 2603 cbor::MAP_0, 2604 cbor::TEXT_8, 2605 b'a', 2606 b'u', 2607 b't', 2608 b'h', 2609 b'D', 2610 b'a', 2611 b't', 2612 b'a', 2613 cbor::BYTES_INFO_25, 2614 10, 2615 113, 2616 // `rpIdHash`. 2617 0, 2618 0, 2619 0, 2620 0, 2621 0, 2622 0, 2623 0, 2624 0, 2625 0, 2626 0, 2627 0, 2628 0, 2629 0, 2630 0, 2631 0, 2632 0, 2633 0, 2634 0, 2635 0, 2636 0, 2637 0, 2638 0, 2639 0, 2640 0, 2641 0, 2642 0, 2643 0, 2644 0, 2645 0, 2646 0, 2647 0, 2648 0, 2649 // `flags`. 2650 0b0100_0101, 2651 // `signCount`. 2652 0, 2653 0, 2654 0, 2655 0, 2656 // `aaguid`. 2657 0, 2658 0, 2659 0, 2660 0, 2661 0, 2662 0, 2663 0, 2664 0, 2665 0, 2666 0, 2667 0, 2668 0, 2669 0, 2670 0, 2671 0, 2672 0, 2673 // `credentialIdLength`. 2674 0, 2675 16, 2676 // `credentialId`. 2677 0, 2678 0, 2679 0, 2680 0, 2681 0, 2682 0, 2683 0, 2684 0, 2685 0, 2686 0, 2687 0, 2688 0, 2689 0, 2690 0, 2691 0, 2692 0, 2693 // ML-DSA-87 COSE key. 2694 cbor::MAP_3, 2695 KTY, 2696 AKP, 2697 ALG, 2698 cbor::NEG_INFO_24, 2699 MLDSA87, 2700 // `pub`. 2701 cbor::NEG_ONE, 2702 cbor::BYTES_INFO_25, 2703 10, 2704 32, 2705 // Encoded key. 2706 1, 2707 1, 2708 1, 2709 1, 2710 1, 2711 1, 2712 1, 2713 1, 2714 1, 2715 1, 2716 1, 2717 1, 2718 1, 2719 1, 2720 1, 2721 1, 2722 1, 2723 1, 2724 1, 2725 1, 2726 1, 2727 1, 2728 1, 2729 1, 2730 1, 2731 1, 2732 1, 2733 1, 2734 1, 2735 1, 2736 1, 2737 1, 2738 1, 2739 1, 2740 1, 2741 1, 2742 1, 2743 1, 2744 1, 2745 1, 2746 1, 2747 1, 2748 1, 2749 1, 2750 1, 2751 1, 2752 1, 2753 1, 2754 1, 2755 1, 2756 1, 2757 1, 2758 1, 2759 1, 2760 1, 2761 1, 2762 1, 2763 1, 2764 1, 2765 1, 2766 1, 2767 1, 2768 1, 2769 1, 2770 1, 2771 1, 2772 1, 2773 1, 2774 1, 2775 1, 2776 1, 2777 1, 2778 1, 2779 1, 2780 1, 2781 1, 2782 1, 2783 1, 2784 1, 2785 1, 2786 1, 2787 1, 2788 1, 2789 1, 2790 1, 2791 1, 2792 1, 2793 1, 2794 1, 2795 1, 2796 1, 2797 1, 2798 1, 2799 1, 2800 1, 2801 1, 2802 1, 2803 1, 2804 1, 2805 1, 2806 1, 2807 1, 2808 1, 2809 1, 2810 1, 2811 1, 2812 1, 2813 1, 2814 1, 2815 1, 2816 1, 2817 1, 2818 1, 2819 1, 2820 1, 2821 1, 2822 1, 2823 1, 2824 1, 2825 1, 2826 1, 2827 1, 2828 1, 2829 1, 2830 1, 2831 1, 2832 1, 2833 1, 2834 1, 2835 1, 2836 1, 2837 1, 2838 1, 2839 1, 2840 1, 2841 1, 2842 1, 2843 1, 2844 1, 2845 1, 2846 1, 2847 1, 2848 1, 2849 1, 2850 1, 2851 1, 2852 1, 2853 1, 2854 1, 2855 1, 2856 1, 2857 1, 2858 1, 2859 1, 2860 1, 2861 1, 2862 1, 2863 1, 2864 1, 2865 1, 2866 1, 2867 1, 2868 1, 2869 1, 2870 1, 2871 1, 2872 1, 2873 1, 2874 1, 2875 1, 2876 1, 2877 1, 2878 1, 2879 1, 2880 1, 2881 1, 2882 1, 2883 1, 2884 1, 2885 1, 2886 1, 2887 1, 2888 1, 2889 1, 2890 1, 2891 1, 2892 1, 2893 1, 2894 1, 2895 1, 2896 1, 2897 1, 2898 1, 2899 1, 2900 1, 2901 1, 2902 1, 2903 1, 2904 1, 2905 1, 2906 1, 2907 1, 2908 1, 2909 1, 2910 1, 2911 1, 2912 1, 2913 1, 2914 1, 2915 1, 2916 1, 2917 1, 2918 1, 2919 1, 2920 1, 2921 1, 2922 1, 2923 1, 2924 1, 2925 1, 2926 1, 2927 1, 2928 1, 2929 1, 2930 1, 2931 1, 2932 1, 2933 1, 2934 1, 2935 1, 2936 1, 2937 1, 2938 1, 2939 1, 2940 1, 2941 1, 2942 1, 2943 1, 2944 1, 2945 1, 2946 1, 2947 1, 2948 1, 2949 1, 2950 1, 2951 1, 2952 1, 2953 1, 2954 1, 2955 1, 2956 1, 2957 1, 2958 1, 2959 1, 2960 1, 2961 1, 2962 1, 2963 1, 2964 1, 2965 1, 2966 1, 2967 1, 2968 1, 2969 1, 2970 1, 2971 1, 2972 1, 2973 1, 2974 1, 2975 1, 2976 1, 2977 1, 2978 1, 2979 1, 2980 1, 2981 1, 2982 1, 2983 1, 2984 1, 2985 1, 2986 1, 2987 1, 2988 1, 2989 1, 2990 1, 2991 1, 2992 1, 2993 1, 2994 1, 2995 1, 2996 1, 2997 1, 2998 1, 2999 1, 3000 1, 3001 1, 3002 1, 3003 1, 3004 1, 3005 1, 3006 1, 3007 1, 3008 1, 3009 1, 3010 1, 3011 1, 3012 1, 3013 1, 3014 1, 3015 1, 3016 1, 3017 1, 3018 1, 3019 1, 3020 1, 3021 1, 3022 1, 3023 1, 3024 1, 3025 1, 3026 1, 3027 1, 3028 1, 3029 1, 3030 1, 3031 1, 3032 1, 3033 1, 3034 1, 3035 1, 3036 1, 3037 1, 3038 1, 3039 1, 3040 1, 3041 1, 3042 1, 3043 1, 3044 1, 3045 1, 3046 1, 3047 1, 3048 1, 3049 1, 3050 1, 3051 1, 3052 1, 3053 1, 3054 1, 3055 1, 3056 1, 3057 1, 3058 1, 3059 1, 3060 1, 3061 1, 3062 1, 3063 1, 3064 1, 3065 1, 3066 1, 3067 1, 3068 1, 3069 1, 3070 1, 3071 1, 3072 1, 3073 1, 3074 1, 3075 1, 3076 1, 3077 1, 3078 1, 3079 1, 3080 1, 3081 1, 3082 1, 3083 1, 3084 1, 3085 1, 3086 1, 3087 1, 3088 1, 3089 1, 3090 1, 3091 1, 3092 1, 3093 1, 3094 1, 3095 1, 3096 1, 3097 1, 3098 1, 3099 1, 3100 1, 3101 1, 3102 1, 3103 1, 3104 1, 3105 1, 3106 1, 3107 1, 3108 1, 3109 1, 3110 1, 3111 1, 3112 1, 3113 1, 3114 1, 3115 1, 3116 1, 3117 1, 3118 1, 3119 1, 3120 1, 3121 1, 3122 1, 3123 1, 3124 1, 3125 1, 3126 1, 3127 1, 3128 1, 3129 1, 3130 1, 3131 1, 3132 1, 3133 1, 3134 1, 3135 1, 3136 1, 3137 1, 3138 1, 3139 1, 3140 1, 3141 1, 3142 1, 3143 1, 3144 1, 3145 1, 3146 1, 3147 1, 3148 1, 3149 1, 3150 1, 3151 1, 3152 1, 3153 1, 3154 1, 3155 1, 3156 1, 3157 1, 3158 1, 3159 1, 3160 1, 3161 1, 3162 1, 3163 1, 3164 1, 3165 1, 3166 1, 3167 1, 3168 1, 3169 1, 3170 1, 3171 1, 3172 1, 3173 1, 3174 1, 3175 1, 3176 1, 3177 1, 3178 1, 3179 1, 3180 1, 3181 1, 3182 1, 3183 1, 3184 1, 3185 1, 3186 1, 3187 1, 3188 1, 3189 1, 3190 1, 3191 1, 3192 1, 3193 1, 3194 1, 3195 1, 3196 1, 3197 1, 3198 1, 3199 1, 3200 1, 3201 1, 3202 1, 3203 1, 3204 1, 3205 1, 3206 1, 3207 1, 3208 1, 3209 1, 3210 1, 3211 1, 3212 1, 3213 1, 3214 1, 3215 1, 3216 1, 3217 1, 3218 1, 3219 1, 3220 1, 3221 1, 3222 1, 3223 1, 3224 1, 3225 1, 3226 1, 3227 1, 3228 1, 3229 1, 3230 1, 3231 1, 3232 1, 3233 1, 3234 1, 3235 1, 3236 1, 3237 1, 3238 1, 3239 1, 3240 1, 3241 1, 3242 1, 3243 1, 3244 1, 3245 1, 3246 1, 3247 1, 3248 1, 3249 1, 3250 1, 3251 1, 3252 1, 3253 1, 3254 1, 3255 1, 3256 1, 3257 1, 3258 1, 3259 1, 3260 1, 3261 1, 3262 1, 3263 1, 3264 1, 3265 1, 3266 1, 3267 1, 3268 1, 3269 1, 3270 1, 3271 1, 3272 1, 3273 1, 3274 1, 3275 1, 3276 1, 3277 1, 3278 1, 3279 1, 3280 1, 3281 1, 3282 1, 3283 1, 3284 1, 3285 1, 3286 1, 3287 1, 3288 1, 3289 1, 3290 1, 3291 1, 3292 1, 3293 1, 3294 1, 3295 1, 3296 1, 3297 1, 3298 1, 3299 1, 3300 1, 3301 1, 3302 1, 3303 1, 3304 1, 3305 1, 3306 1, 3307 1, 3308 1, 3309 1, 3310 1, 3311 1, 3312 1, 3313 1, 3314 1, 3315 1, 3316 1, 3317 1, 3318 1, 3319 1, 3320 1, 3321 1, 3322 1, 3323 1, 3324 1, 3325 1, 3326 1, 3327 1, 3328 1, 3329 1, 3330 1, 3331 1, 3332 1, 3333 1, 3334 1, 3335 1, 3336 1, 3337 1, 3338 1, 3339 1, 3340 1, 3341 1, 3342 1, 3343 1, 3344 1, 3345 1, 3346 1, 3347 1, 3348 1, 3349 1, 3350 1, 3351 1, 3352 1, 3353 1, 3354 1, 3355 1, 3356 1, 3357 1, 3358 1, 3359 1, 3360 1, 3361 1, 3362 1, 3363 1, 3364 1, 3365 1, 3366 1, 3367 1, 3368 1, 3369 1, 3370 1, 3371 1, 3372 1, 3373 1, 3374 1, 3375 1, 3376 1, 3377 1, 3378 1, 3379 1, 3380 1, 3381 1, 3382 1, 3383 1, 3384 1, 3385 1, 3386 1, 3387 1, 3388 1, 3389 1, 3390 1, 3391 1, 3392 1, 3393 1, 3394 1, 3395 1, 3396 1, 3397 1, 3398 1, 3399 1, 3400 1, 3401 1, 3402 1, 3403 1, 3404 1, 3405 1, 3406 1, 3407 1, 3408 1, 3409 1, 3410 1, 3411 1, 3412 1, 3413 1, 3414 1, 3415 1, 3416 1, 3417 1, 3418 1, 3419 1, 3420 1, 3421 1, 3422 1, 3423 1, 3424 1, 3425 1, 3426 1, 3427 1, 3428 1, 3429 1, 3430 1, 3431 1, 3432 1, 3433 1, 3434 1, 3435 1, 3436 1, 3437 1, 3438 1, 3439 1, 3440 1, 3441 1, 3442 1, 3443 1, 3444 1, 3445 1, 3446 1, 3447 1, 3448 1, 3449 1, 3450 1, 3451 1, 3452 1, 3453 1, 3454 1, 3455 1, 3456 1, 3457 1, 3458 1, 3459 1, 3460 1, 3461 1, 3462 1, 3463 1, 3464 1, 3465 1, 3466 1, 3467 1, 3468 1, 3469 1, 3470 1, 3471 1, 3472 1, 3473 1, 3474 1, 3475 1, 3476 1, 3477 1, 3478 1, 3479 1, 3480 1, 3481 1, 3482 1, 3483 1, 3484 1, 3485 1, 3486 1, 3487 1, 3488 1, 3489 1, 3490 1, 3491 1, 3492 1, 3493 1, 3494 1, 3495 1, 3496 1, 3497 1, 3498 1, 3499 1, 3500 1, 3501 1, 3502 1, 3503 1, 3504 1, 3505 1, 3506 1, 3507 1, 3508 1, 3509 1, 3510 1, 3511 1, 3512 1, 3513 1, 3514 1, 3515 1, 3516 1, 3517 1, 3518 1, 3519 1, 3520 1, 3521 1, 3522 1, 3523 1, 3524 1, 3525 1, 3526 1, 3527 1, 3528 1, 3529 1, 3530 1, 3531 1, 3532 1, 3533 1, 3534 1, 3535 1, 3536 1, 3537 1, 3538 1, 3539 1, 3540 1, 3541 1, 3542 1, 3543 1, 3544 1, 3545 1, 3546 1, 3547 1, 3548 1, 3549 1, 3550 1, 3551 1, 3552 1, 3553 1, 3554 1, 3555 1, 3556 1, 3557 1, 3558 1, 3559 1, 3560 1, 3561 1, 3562 1, 3563 1, 3564 1, 3565 1, 3566 1, 3567 1, 3568 1, 3569 1, 3570 1, 3571 1, 3572 1, 3573 1, 3574 1, 3575 1, 3576 1, 3577 1, 3578 1, 3579 1, 3580 1, 3581 1, 3582 1, 3583 1, 3584 1, 3585 1, 3586 1, 3587 1, 3588 1, 3589 1, 3590 1, 3591 1, 3592 1, 3593 1, 3594 1, 3595 1, 3596 1, 3597 1, 3598 1, 3599 1, 3600 1, 3601 1, 3602 1, 3603 1, 3604 1, 3605 1, 3606 1, 3607 1, 3608 1, 3609 1, 3610 1, 3611 1, 3612 1, 3613 1, 3614 1, 3615 1, 3616 1, 3617 1, 3618 1, 3619 1, 3620 1, 3621 1, 3622 1, 3623 1, 3624 1, 3625 1, 3626 1, 3627 1, 3628 1, 3629 1, 3630 1, 3631 1, 3632 1, 3633 1, 3634 1, 3635 1, 3636 1, 3637 1, 3638 1, 3639 1, 3640 1, 3641 1, 3642 1, 3643 1, 3644 1, 3645 1, 3646 1, 3647 1, 3648 1, 3649 1, 3650 1, 3651 1, 3652 1, 3653 1, 3654 1, 3655 1, 3656 1, 3657 1, 3658 1, 3659 1, 3660 1, 3661 1, 3662 1, 3663 1, 3664 1, 3665 1, 3666 1, 3667 1, 3668 1, 3669 1, 3670 1, 3671 1, 3672 1, 3673 1, 3674 1, 3675 1, 3676 1, 3677 1, 3678 1, 3679 1, 3680 1, 3681 1, 3682 1, 3683 1, 3684 1, 3685 1, 3686 1, 3687 1, 3688 1, 3689 1, 3690 1, 3691 1, 3692 1, 3693 1, 3694 1, 3695 1, 3696 1, 3697 1, 3698 1, 3699 1, 3700 1, 3701 1, 3702 1, 3703 1, 3704 1, 3705 1, 3706 1, 3707 1, 3708 1, 3709 1, 3710 1, 3711 1, 3712 1, 3713 1, 3714 1, 3715 1, 3716 1, 3717 1, 3718 1, 3719 1, 3720 1, 3721 1, 3722 1, 3723 1, 3724 1, 3725 1, 3726 1, 3727 1, 3728 1, 3729 1, 3730 1, 3731 1, 3732 1, 3733 1, 3734 1, 3735 1, 3736 1, 3737 1, 3738 1, 3739 1, 3740 1, 3741 1, 3742 1, 3743 1, 3744 1, 3745 1, 3746 1, 3747 1, 3748 1, 3749 1, 3750 1, 3751 1, 3752 1, 3753 1, 3754 1, 3755 1, 3756 1, 3757 1, 3758 1, 3759 1, 3760 1, 3761 1, 3762 1, 3763 1, 3764 1, 3765 1, 3766 1, 3767 1, 3768 1, 3769 1, 3770 1, 3771 1, 3772 1, 3773 1, 3774 1, 3775 1, 3776 1, 3777 1, 3778 1, 3779 1, 3780 1, 3781 1, 3782 1, 3783 1, 3784 1, 3785 1, 3786 1, 3787 1, 3788 1, 3789 1, 3790 1, 3791 1, 3792 1, 3793 1, 3794 1, 3795 1, 3796 1, 3797 1, 3798 1, 3799 1, 3800 1, 3801 1, 3802 1, 3803 1, 3804 1, 3805 1, 3806 1, 3807 1, 3808 1, 3809 1, 3810 1, 3811 1, 3812 1, 3813 1, 3814 1, 3815 1, 3816 1, 3817 1, 3818 1, 3819 1, 3820 1, 3821 1, 3822 1, 3823 1, 3824 1, 3825 1, 3826 1, 3827 1, 3828 1, 3829 1, 3830 1, 3831 1, 3832 1, 3833 1, 3834 1, 3835 1, 3836 1, 3837 1, 3838 1, 3839 1, 3840 1, 3841 1, 3842 1, 3843 1, 3844 1, 3845 1, 3846 1, 3847 1, 3848 1, 3849 1, 3850 1, 3851 1, 3852 1, 3853 1, 3854 1, 3855 1, 3856 1, 3857 1, 3858 1, 3859 1, 3860 1, 3861 1, 3862 1, 3863 1, 3864 1, 3865 1, 3866 1, 3867 1, 3868 1, 3869 1, 3870 1, 3871 1, 3872 1, 3873 1, 3874 1, 3875 1, 3876 1, 3877 1, 3878 1, 3879 1, 3880 1, 3881 1, 3882 1, 3883 1, 3884 1, 3885 1, 3886 1, 3887 1, 3888 1, 3889 1, 3890 1, 3891 1, 3892 1, 3893 1, 3894 1, 3895 1, 3896 1, 3897 1, 3898 1, 3899 1, 3900 1, 3901 1, 3902 1, 3903 1, 3904 1, 3905 1, 3906 1, 3907 1, 3908 1, 3909 1, 3910 1, 3911 1, 3912 1, 3913 1, 3914 1, 3915 1, 3916 1, 3917 1, 3918 1, 3919 1, 3920 1, 3921 1, 3922 1, 3923 1, 3924 1, 3925 1, 3926 1, 3927 1, 3928 1, 3929 1, 3930 1, 3931 1, 3932 1, 3933 1, 3934 1, 3935 1, 3936 1, 3937 1, 3938 1, 3939 1, 3940 1, 3941 1, 3942 1, 3943 1, 3944 1, 3945 1, 3946 1, 3947 1, 3948 1, 3949 1, 3950 1, 3951 1, 3952 1, 3953 1, 3954 1, 3955 1, 3956 1, 3957 1, 3958 1, 3959 1, 3960 1, 3961 1, 3962 1, 3963 1, 3964 1, 3965 1, 3966 1, 3967 1, 3968 1, 3969 1, 3970 1, 3971 1, 3972 1, 3973 1, 3974 1, 3975 1, 3976 1, 3977 1, 3978 1, 3979 1, 3980 1, 3981 1, 3982 1, 3983 1, 3984 1, 3985 1, 3986 1, 3987 1, 3988 1, 3989 1, 3990 1, 3991 1, 3992 1, 3993 1, 3994 1, 3995 1, 3996 1, 3997 1, 3998 1, 3999 1, 4000 1, 4001 1, 4002 1, 4003 1, 4004 1, 4005 1, 4006 1, 4007 1, 4008 1, 4009 1, 4010 1, 4011 1, 4012 1, 4013 1, 4014 1, 4015 1, 4016 1, 4017 1, 4018 1, 4019 1, 4020 1, 4021 1, 4022 1, 4023 1, 4024 1, 4025 1, 4026 1, 4027 1, 4028 1, 4029 1, 4030 1, 4031 1, 4032 1, 4033 1, 4034 1, 4035 1, 4036 1, 4037 1, 4038 1, 4039 1, 4040 1, 4041 1, 4042 1, 4043 1, 4044 1, 4045 1, 4046 1, 4047 1, 4048 1, 4049 1, 4050 1, 4051 1, 4052 1, 4053 1, 4054 1, 4055 1, 4056 1, 4057 1, 4058 1, 4059 1, 4060 1, 4061 1, 4062 1, 4063 1, 4064 1, 4065 1, 4066 1, 4067 1, 4068 1, 4069 1, 4070 1, 4071 1, 4072 1, 4073 1, 4074 1, 4075 1, 4076 1, 4077 1, 4078 1, 4079 1, 4080 1, 4081 1, 4082 1, 4083 1, 4084 1, 4085 1, 4086 1, 4087 1, 4088 1, 4089 1, 4090 1, 4091 1, 4092 1, 4093 1, 4094 1, 4095 1, 4096 1, 4097 1, 4098 1, 4099 1, 4100 1, 4101 1, 4102 1, 4103 1, 4104 1, 4105 1, 4106 1, 4107 1, 4108 1, 4109 1, 4110 1, 4111 1, 4112 1, 4113 1, 4114 1, 4115 1, 4116 1, 4117 1, 4118 1, 4119 1, 4120 1, 4121 1, 4122 1, 4123 1, 4124 1, 4125 1, 4126 1, 4127 1, 4128 1, 4129 1, 4130 1, 4131 1, 4132 1, 4133 1, 4134 1, 4135 1, 4136 1, 4137 1, 4138 1, 4139 1, 4140 1, 4141 1, 4142 1, 4143 1, 4144 1, 4145 1, 4146 1, 4147 1, 4148 1, 4149 1, 4150 1, 4151 1, 4152 1, 4153 1, 4154 1, 4155 1, 4156 1, 4157 1, 4158 1, 4159 1, 4160 1, 4161 1, 4162 1, 4163 1, 4164 1, 4165 1, 4166 1, 4167 1, 4168 1, 4169 1, 4170 1, 4171 1, 4172 1, 4173 1, 4174 1, 4175 1, 4176 1, 4177 1, 4178 1, 4179 1, 4180 1, 4181 1, 4182 1, 4183 1, 4184 1, 4185 1, 4186 1, 4187 1, 4188 1, 4189 1, 4190 1, 4191 1, 4192 1, 4193 1, 4194 1, 4195 1, 4196 1, 4197 1, 4198 1, 4199 1, 4200 1, 4201 1, 4202 1, 4203 1, 4204 1, 4205 1, 4206 1, 4207 1, 4208 1, 4209 1, 4210 1, 4211 1, 4212 1, 4213 1, 4214 1, 4215 1, 4216 1, 4217 1, 4218 1, 4219 1, 4220 1, 4221 1, 4222 1, 4223 1, 4224 1, 4225 1, 4226 1, 4227 1, 4228 1, 4229 1, 4230 1, 4231 1, 4232 1, 4233 1, 4234 1, 4235 1, 4236 1, 4237 1, 4238 1, 4239 1, 4240 1, 4241 1, 4242 1, 4243 1, 4244 1, 4245 1, 4246 1, 4247 1, 4248 1, 4249 1, 4250 1, 4251 1, 4252 1, 4253 1, 4254 1, 4255 1, 4256 1, 4257 1, 4258 1, 4259 1, 4260 1, 4261 1, 4262 1, 4263 1, 4264 1, 4265 1, 4266 1, 4267 1, 4268 1, 4269 1, 4270 1, 4271 1, 4272 1, 4273 1, 4274 1, 4275 1, 4276 1, 4277 1, 4278 1, 4279 1, 4280 1, 4281 1, 4282 1, 4283 1, 4284 1, 4285 1, 4286 1, 4287 1, 4288 1, 4289 1, 4290 1, 4291 1, 4292 1, 4293 1, 4294 1, 4295 1, 4296 1, 4297 1, 4298 1, 4299 1, 4300 1, 4301 1, 4302 1, 4303 1, 4304 1, 4305 1, 4306 1, 4307 1, 4308 1, 4309 1, 4310 1, 4311 1, 4312 1, 4313 1, 4314 1, 4315 1, 4316 1, 4317 1, 4318 1, 4319 1, 4320 1, 4321 1, 4322 1, 4323 1, 4324 1, 4325 1, 4326 1, 4327 1, 4328 1, 4329 1, 4330 1, 4331 1, 4332 1, 4333 1, 4334 1, 4335 1, 4336 1, 4337 1, 4338 1, 4339 1, 4340 1, 4341 1, 4342 1, 4343 1, 4344 1, 4345 1, 4346 1, 4347 1, 4348 1, 4349 1, 4350 1, 4351 1, 4352 1, 4353 1, 4354 1, 4355 1, 4356 1, 4357 1, 4358 1, 4359 1, 4360 1, 4361 1, 4362 1, 4363 1, 4364 1, 4365 1, 4366 1, 4367 1, 4368 1, 4369 1, 4370 1, 4371 1, 4372 1, 4373 1, 4374 1, 4375 1, 4376 1, 4377 1, 4378 1, 4379 1, 4380 1, 4381 1, 4382 1, 4383 1, 4384 1, 4385 1, 4386 1, 4387 1, 4388 1, 4389 1, 4390 1, 4391 1, 4392 1, 4393 1, 4394 1, 4395 1, 4396 1, 4397 1, 4398 1, 4399 1, 4400 1, 4401 1, 4402 1, 4403 1, 4404 1, 4405 1, 4406 1, 4407 1, 4408 1, 4409 1, 4410 1, 4411 1, 4412 1, 4413 1, 4414 1, 4415 1, 4416 1, 4417 1, 4418 1, 4419 1, 4420 1, 4421 1, 4422 1, 4423 1, 4424 1, 4425 1, 4426 1, 4427 1, 4428 1, 4429 1, 4430 1, 4431 1, 4432 1, 4433 1, 4434 1, 4435 1, 4436 1, 4437 1, 4438 1, 4439 1, 4440 1, 4441 1, 4442 1, 4443 1, 4444 1, 4445 1, 4446 1, 4447 1, 4448 1, 4449 1, 4450 1, 4451 1, 4452 1, 4453 1, 4454 1, 4455 1, 4456 1, 4457 1, 4458 1, 4459 1, 4460 1, 4461 1, 4462 1, 4463 1, 4464 1, 4465 1, 4466 1, 4467 1, 4468 1, 4469 1, 4470 1, 4471 1, 4472 1, 4473 1, 4474 1, 4475 1, 4476 1, 4477 1, 4478 1, 4479 1, 4480 1, 4481 1, 4482 1, 4483 1, 4484 1, 4485 1, 4486 1, 4487 1, 4488 1, 4489 1, 4490 1, 4491 1, 4492 1, 4493 1, 4494 1, 4495 1, 4496 1, 4497 1, 4498 1, 4499 1, 4500 1, 4501 1, 4502 1, 4503 1, 4504 1, 4505 1, 4506 1, 4507 1, 4508 1, 4509 1, 4510 1, 4511 1, 4512 1, 4513 1, 4514 1, 4515 1, 4516 1, 4517 1, 4518 1, 4519 1, 4520 1, 4521 1, 4522 1, 4523 1, 4524 1, 4525 1, 4526 1, 4527 1, 4528 1, 4529 1, 4530 1, 4531 1, 4532 1, 4533 1, 4534 1, 4535 1, 4536 1, 4537 1, 4538 1, 4539 1, 4540 1, 4541 1, 4542 1, 4543 1, 4544 1, 4545 1, 4546 1, 4547 1, 4548 1, 4549 1, 4550 1, 4551 1, 4552 1, 4553 1, 4554 1, 4555 1, 4556 1, 4557 1, 4558 1, 4559 1, 4560 1, 4561 1, 4562 1, 4563 1, 4564 1, 4565 1, 4566 1, 4567 1, 4568 1, 4569 1, 4570 1, 4571 1, 4572 1, 4573 1, 4574 1, 4575 1, 4576 1, 4577 1, 4578 1, 4579 1, 4580 1, 4581 1, 4582 1, 4583 1, 4584 1, 4585 1, 4586 1, 4587 1, 4588 1, 4589 1, 4590 1, 4591 1, 4592 1, 4593 1, 4594 1, 4595 1, 4596 1, 4597 1, 4598 1, 4599 1, 4600 1, 4601 1, 4602 1, 4603 1, 4604 1, 4605 1, 4606 1, 4607 1, 4608 1, 4609 1, 4610 1, 4611 1, 4612 1, 4613 1, 4614 1, 4615 1, 4616 1, 4617 1, 4618 1, 4619 1, 4620 1, 4621 1, 4622 1, 4623 1, 4624 1, 4625 1, 4626 1, 4627 1, 4628 1, 4629 1, 4630 1, 4631 1, 4632 1, 4633 1, 4634 1, 4635 1, 4636 1, 4637 1, 4638 1, 4639 1, 4640 1, 4641 1, 4642 1, 4643 1, 4644 1, 4645 1, 4646 1, 4647 1, 4648 1, 4649 1, 4650 1, 4651 1, 4652 1, 4653 1, 4654 1, 4655 1, 4656 1, 4657 1, 4658 1, 4659 1, 4660 1, 4661 1, 4662 1, 4663 1, 4664 1, 4665 1, 4666 1, 4667 1, 4668 1, 4669 1, 4670 1, 4671 1, 4672 1, 4673 1, 4674 1, 4675 1, 4676 1, 4677 1, 4678 1, 4679 1, 4680 1, 4681 1, 4682 1, 4683 1, 4684 1, 4685 1, 4686 1, 4687 1, 4688 1, 4689 1, 4690 1, 4691 1, 4692 1, 4693 1, 4694 1, 4695 1, 4696 1, 4697 1, 4698 1, 4699 1, 4700 1, 4701 1, 4702 1, 4703 1, 4704 1, 4705 1, 4706 1, 4707 1, 4708 1, 4709 1, 4710 1, 4711 1, 4712 1, 4713 1, 4714 1, 4715 1, 4716 1, 4717 1, 4718 1, 4719 1, 4720 1, 4721 1, 4722 1, 4723 1, 4724 1, 4725 1, 4726 1, 4727 1, 4728 1, 4729 1, 4730 1, 4731 1, 4732 1, 4733 1, 4734 1, 4735 1, 4736 1, 4737 1, 4738 1, 4739 1, 4740 1, 4741 1, 4742 1, 4743 1, 4744 1, 4745 1, 4746 1, 4747 1, 4748 1, 4749 1, 4750 1, 4751 1, 4752 1, 4753 1, 4754 1, 4755 1, 4756 1, 4757 1, 4758 1, 4759 1, 4760 1, 4761 1, 4762 1, 4763 1, 4764 1, 4765 1, 4766 1, 4767 1, 4768 1, 4769 1, 4770 1, 4771 1, 4772 1, 4773 1, 4774 1, 4775 1, 4776 1, 4777 1, 4778 1, 4779 1, 4780 1, 4781 1, 4782 1, 4783 1, 4784 1, 4785 1, 4786 1, 4787 1, 4788 1, 4789 1, 4790 1, 4791 1, 4792 1, 4793 1, 4794 1, 4795 1, 4796 1, 4797 1, 4798 1, 4799 1, 4800 1, 4801 1, 4802 1, 4803 1, 4804 1, 4805 1, 4806 1, 4807 1, 4808 1, 4809 1, 4810 1, 4811 1, 4812 1, 4813 1, 4814 1, 4815 1, 4816 1, 4817 1, 4818 1, 4819 1, 4820 1, 4821 1, 4822 1, 4823 1, 4824 1, 4825 1, 4826 1, 4827 1, 4828 1, 4829 1, 4830 1, 4831 1, 4832 1, 4833 1, 4834 1, 4835 1, 4836 1, 4837 1, 4838 1, 4839 1, 4840 1, 4841 1, 4842 1, 4843 1, 4844 1, 4845 1, 4846 1, 4847 1, 4848 1, 4849 1, 4850 1, 4851 1, 4852 1, 4853 1, 4854 1, 4855 1, 4856 1, 4857 1, 4858 1, 4859 1, 4860 1, 4861 1, 4862 1, 4863 1, 4864 1, 4865 1, 4866 1, 4867 1, 4868 1, 4869 1, 4870 1, 4871 1, 4872 1, 4873 1, 4874 1, 4875 1, 4876 1, 4877 1, 4878 1, 4879 1, 4880 1, 4881 1, 4882 1, 4883 1, 4884 1, 4885 1, 4886 1, 4887 1, 4888 1, 4889 1, 4890 1, 4891 1, 4892 1, 4893 1, 4894 1, 4895 1, 4896 1, 4897 1, 4898 1, 4899 1, 4900 1, 4901 1, 4902 1, 4903 1, 4904 1, 4905 1, 4906 1, 4907 1, 4908 1, 4909 1, 4910 1, 4911 1, 4912 1, 4913 1, 4914 1, 4915 1, 4916 1, 4917 1, 4918 1, 4919 1, 4920 1, 4921 1, 4922 1, 4923 1, 4924 1, 4925 1, 4926 1, 4927 1, 4928 1, 4929 1, 4930 1, 4931 1, 4932 1, 4933 1, 4934 1, 4935 1, 4936 1, 4937 1, 4938 1, 4939 1, 4940 1, 4941 1, 4942 1, 4943 1, 4944 1, 4945 1, 4946 1, 4947 1, 4948 1, 4949 1, 4950 1, 4951 1, 4952 1, 4953 1, 4954 1, 4955 1, 4956 1, 4957 1, 4958 1, 4959 1, 4960 1, 4961 1, 4962 1, 4963 1, 4964 1, 4965 1, 4966 1, 4967 1, 4968 1, 4969 1, 4970 1, 4971 1, 4972 1, 4973 1, 4974 1, 4975 1, 4976 1, 4977 1, 4978 1, 4979 1, 4980 1, 4981 1, 4982 1, 4983 1, 4984 1, 4985 1, 4986 1, 4987 1, 4988 1, 4989 1, 4990 1, 4991 1, 4992 1, 4993 1, 4994 1, 4995 1, 4996 1, 4997 1, 4998 1, 4999 1, 5000 1, 5001 1, 5002 1, 5003 1, 5004 1, 5005 1, 5006 1, 5007 1, 5008 1, 5009 1, 5010 1, 5011 1, 5012 1, 5013 1, 5014 1, 5015 1, 5016 1, 5017 1, 5018 1, 5019 1, 5020 1, 5021 1, 5022 1, 5023 1, 5024 1, 5025 1, 5026 1, 5027 1, 5028 1, 5029 1, 5030 1, 5031 1, 5032 1, 5033 1, 5034 1, 5035 1, 5036 1, 5037 1, 5038 1, 5039 1, 5040 1, 5041 1, 5042 1, 5043 1, 5044 1, 5045 1, 5046 1, 5047 1, 5048 1, 5049 1, 5050 1, 5051 1, 5052 1, 5053 1, 5054 1, 5055 1, 5056 1, 5057 1, 5058 1, 5059 1, 5060 1, 5061 1, 5062 1, 5063 1, 5064 1, 5065 1, 5066 1, 5067 1, 5068 1, 5069 1, 5070 1, 5071 1, 5072 1, 5073 1, 5074 1, 5075 1, 5076 1, 5077 1, 5078 1, 5079 1, 5080 1, 5081 1, 5082 1, 5083 1, 5084 1, 5085 1, 5086 1, 5087 1, 5088 1, 5089 1, 5090 1, 5091 1, 5092 1, 5093 1, 5094 1, 5095 1, 5096 1, 5097 1, 5098 1, 5099 1, 5100 1, 5101 1, 5102 1, 5103 1, 5104 1, 5105 1, 5106 1, 5107 1, 5108 1, 5109 1, 5110 1, 5111 1, 5112 1, 5113 1, 5114 1, 5115 1, 5116 1, 5117 1, 5118 1, 5119 1, 5120 1, 5121 1, 5122 1, 5123 1, 5124 1, 5125 1, 5126 1, 5127 1, 5128 1, 5129 1, 5130 1, 5131 1, 5132 1, 5133 1, 5134 1, 5135 1, 5136 1, 5137 1, 5138 1, 5139 1, 5140 1, 5141 1, 5142 1, 5143 1, 5144 1, 5145 1, 5146 1, 5147 1, 5148 1, 5149 1, 5150 1, 5151 1, 5152 1, 5153 1, 5154 1, 5155 1, 5156 1, 5157 1, 5158 1, 5159 1, 5160 1, 5161 1, 5162 1, 5163 1, 5164 1, 5165 1, 5166 1, 5167 1, 5168 1, 5169 1, 5170 1, 5171 1, 5172 1, 5173 1, 5174 1, 5175 1, 5176 1, 5177 1, 5178 1, 5179 1, 5180 1, 5181 1, 5182 1, 5183 1, 5184 1, 5185 1, 5186 1, 5187 1, 5188 1, 5189 1, 5190 1, 5191 1, 5192 1, 5193 1, 5194 1, 5195 1, 5196 1, 5197 1, 5198 1, 5199 1, 5200 1, 5201 1, 5202 1, 5203 1, 5204 1, 5205 1, 5206 1, 5207 1, 5208 1, 5209 1, 5210 1, 5211 1, 5212 1, 5213 1, 5214 1, 5215 1, 5216 1, 5217 1, 5218 1, 5219 1, 5220 1, 5221 1, 5222 1, 5223 1, 5224 1, 5225 1, 5226 1, 5227 1, 5228 1, 5229 1, 5230 1, 5231 1, 5232 1, 5233 1, 5234 1, 5235 1, 5236 1, 5237 1, 5238 1, 5239 1, 5240 1, 5241 1, 5242 1, 5243 1, 5244 1, 5245 1, 5246 1, 5247 1, 5248 1, 5249 1, 5250 1, 5251 1, 5252 1, 5253 1, 5254 1, 5255 1, 5256 1, 5257 1, 5258 1, 5259 1, 5260 1, 5261 1, 5262 1, 5263 1, 5264 1, 5265 1, 5266 1, 5267 1, 5268 1, 5269 1, 5270 1, 5271 1, 5272 1, 5273 1, 5274 1, 5275 1, 5276 1, 5277 1, 5278 1, 5279 1, 5280 1, 5281 1, 5282 1, 5283 1, 5284 1, 5285 1, 5286 1, 5287 1, 5288 1, 5289 1, 5290 1, 5291 1, 5292 1, 5293 1, 5294 1, 5295 1, 5296 1, 5297 1, 5298 ]; 5299 let pub_key = MlDsaVerKey::<MlDsa87>::decode(&[1u8; 2592].into()) 5300 .to_public_key_der() 5301 .unwrap(); 5302 let att_obj_len = att_obj.len(); 5303 let b64_cdata_json = base64url_nopad::encode(c_data_json.as_bytes()); 5304 let b64_adata = base64url_nopad::encode(&att_obj[att_obj_len - 2673..]); 5305 let b64_key = base64url_nopad::encode(pub_key.as_bytes()); 5306 let b64_aobj = base64url_nopad::encode(att_obj.as_slice()); 5307 // Base case is valid. 5308 assert!( 5309 serde_json::from_str::<Registration>( 5310 serde_json::json!({ 5311 "id": "AAAAAAAAAAAAAAAAAAAAAA", 5312 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 5313 "response": { 5314 "clientDataJSON": b64_cdata_json, 5315 "authenticatorData": b64_adata, 5316 "transports": [], 5317 "publicKey": b64_key, 5318 "publicKeyAlgorithm": -50i8, 5319 "attestationObject": b64_aobj, 5320 }, 5321 "clientExtensionResults": {}, 5322 "type": "public-key" 5323 }) 5324 .to_string() 5325 .as_str() 5326 ) 5327 .is_ok_and( 5328 |reg| reg.response.client_data_json == c_data_json.as_bytes() 5329 && reg.response.attestation_object_and_c_data_hash[..att_obj_len] == att_obj 5330 && reg.response.attestation_object_and_c_data_hash[att_obj_len..] 5331 == *Sha256::digest(c_data_json.as_bytes()) 5332 && reg.response.transports.is_empty() 5333 && matches!(reg.authenticator_attachment, AuthenticatorAttachment::None) 5334 && reg.client_extension_results.cred_props.is_none() 5335 && reg.client_extension_results.prf.is_none() 5336 ) 5337 ); 5338 // `publicKeyAlgorithm` mismatch. 5339 let mut err = Error::invalid_value( 5340 Unexpected::Other(format!("{:?}", CoseAlgorithmIdentifier::Eddsa).as_str()), 5341 &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {:?}", CoseAlgorithmIdentifier::Mldsa87).as_str() 5342 ) 5343 .to_string().into_bytes(); 5344 assert_eq!( 5345 serde_json::from_str::<Registration>( 5346 serde_json::json!({ 5347 "id": "AAAAAAAAAAAAAAAAAAAAAA", 5348 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 5349 "response": { 5350 "clientDataJSON": b64_cdata_json, 5351 "authenticatorData": b64_adata, 5352 "transports": [], 5353 "publicKey": b64_key, 5354 "publicKeyAlgorithm": -8i8, 5355 "attestationObject": b64_aobj, 5356 }, 5357 "clientExtensionResults": {}, 5358 "type": "public-key" 5359 }) 5360 .to_string() 5361 .as_str() 5362 ) 5363 .unwrap_err() 5364 .to_string() 5365 .into_bytes() 5366 .get(..err.len()), 5367 Some(err.as_slice()) 5368 ); 5369 // Missing `publicKeyAlgorithm`. 5370 err = Error::missing_field("publicKeyAlgorithm") 5371 .to_string() 5372 .into_bytes(); 5373 assert_eq!( 5374 serde_json::from_str::<Registration>( 5375 serde_json::json!({ 5376 "id": "AAAAAAAAAAAAAAAAAAAAAA", 5377 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 5378 "response": { 5379 "clientDataJSON": b64_cdata_json, 5380 "authenticatorData": b64_adata, 5381 "transports": [], 5382 "publicKey": b64_key, 5383 "attestationObject": b64_aobj, 5384 }, 5385 "clientExtensionResults": {}, 5386 "type": "public-key" 5387 }) 5388 .to_string() 5389 .as_str() 5390 ) 5391 .unwrap_err() 5392 .to_string() 5393 .into_bytes() 5394 .get(..err.len()), 5395 Some(err.as_slice()) 5396 ); 5397 // `null` `publicKeyAlgorithm`. 5398 err = Error::invalid_type(Unexpected::Other("null"), &"publicKeyAlgorithm") 5399 .to_string() 5400 .into_bytes(); 5401 assert_eq!( 5402 serde_json::from_str::<Registration>( 5403 serde_json::json!({ 5404 "id": "AAAAAAAAAAAAAAAAAAAAAA", 5405 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 5406 "response": { 5407 "clientDataJSON": b64_cdata_json, 5408 "authenticatorData": b64_adata, 5409 "transports": [], 5410 "publicKey": b64_key, 5411 "publicKeyAlgorithm": null, 5412 "attestationObject": b64_aobj, 5413 }, 5414 "clientExtensionResults": {}, 5415 "type": "public-key" 5416 }) 5417 .to_string() 5418 .as_str() 5419 ) 5420 .unwrap_err() 5421 .to_string() 5422 .into_bytes() 5423 .get(..err.len()), 5424 Some(err.as_slice()) 5425 ); 5426 // `publicKey` mismatch. 5427 let bad_pub_key = MlDsaVerKey::<MlDsa87>::decode(&[2; 2592].into()); 5428 err = Error::invalid_value( 5429 Unexpected::Bytes([0; 32].as_slice()), 5430 &format!( 5431 "DER-encoded public key to match the public key within the attestation object: MlDsa87(MlDsa87PubKey({:?}))", 5432 &[1u8; 2592] 5433 ) 5434 .as_str(), 5435 ) 5436 .to_string().into_bytes(); 5437 assert_eq!(serde_json::from_str::<Registration>( 5438 serde_json::json!({ 5439 "id": "AAAAAAAAAAAAAAAAAAAAAA", 5440 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 5441 "response": { 5442 "clientDataJSON": b64_cdata_json, 5443 "authenticatorData": b64_adata, 5444 "transports": [], 5445 "publicKey": base64url_nopad::encode(bad_pub_key.to_public_key_der().unwrap().as_bytes()), 5446 "publicKeyAlgorithm": -50i8, 5447 "attestationObject": b64_aobj, 5448 }, 5449 "clientExtensionResults": {}, 5450 "type": "public-key" 5451 }) 5452 .to_string() 5453 .as_str() 5454 ) 5455 .unwrap_err().to_string().into_bytes().get(..err.len()), 5456 Some(err.as_slice()) 5457 ); 5458 // Missing `publicKey` is allowed when not using EdDSA, ES256, or RS256. 5459 assert!( 5460 serde_json::from_str::<Registration>( 5461 serde_json::json!({ 5462 "id": "AAAAAAAAAAAAAAAAAAAAAA", 5463 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 5464 "response": { 5465 "clientDataJSON": b64_cdata_json, 5466 "authenticatorData": b64_adata, 5467 "transports": [], 5468 "publicKeyAlgorithm": -50i8, 5469 "attestationObject": b64_aobj, 5470 }, 5471 "clientExtensionResults": {}, 5472 "type": "public-key" 5473 }) 5474 .to_string() 5475 .as_str() 5476 ) 5477 .is_ok() 5478 ); 5479 // `publicKeyAlgorithm` mismatch when `publicKey` does not exist. 5480 err = Error::invalid_value( 5481 Unexpected::Other(format!("{:?}", CoseAlgorithmIdentifier::Es256).as_str()), 5482 &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {:?}", CoseAlgorithmIdentifier::Mldsa87).as_str() 5483 ) 5484 .to_string().into_bytes(); 5485 assert_eq!( 5486 serde_json::from_str::<Registration>( 5487 serde_json::json!({ 5488 "id": "AAAAAAAAAAAAAAAAAAAAAA", 5489 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 5490 "response": { 5491 "clientDataJSON": b64_cdata_json, 5492 "authenticatorData": b64_adata, 5493 "transports": [], 5494 "publicKeyAlgorithm": -7i8, 5495 "attestationObject": b64_aobj, 5496 }, 5497 "clientExtensionResults": {}, 5498 "type": "public-key" 5499 }) 5500 .to_string() 5501 .as_str() 5502 ) 5503 .unwrap_err() 5504 .to_string() 5505 .into_bytes() 5506 .get(..err.len()), 5507 Some(err.as_slice()) 5508 ); 5509 // `null` `publicKey` is allowed when not using EdDSA, ES256, or RS256. 5510 assert!( 5511 serde_json::from_str::<Registration>( 5512 serde_json::json!({ 5513 "id": "AAAAAAAAAAAAAAAAAAAAAA", 5514 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 5515 "response": { 5516 "clientDataJSON": b64_cdata_json, 5517 "authenticatorData": b64_adata, 5518 "transports": [], 5519 "publicKey": null, 5520 "publicKeyAlgorithm": -50i8, 5521 "attestationObject": b64_aobj, 5522 }, 5523 "clientExtensionResults": {}, 5524 "type": "public-key" 5525 }) 5526 .to_string() 5527 .as_str() 5528 ) 5529 .is_ok() 5530 ); 5531 // `publicKeyAlgorithm` mismatch when `publicKey` is null. 5532 err = Error::invalid_value( 5533 Unexpected::Other(format!("{:?}", CoseAlgorithmIdentifier::Es256).as_str()), 5534 &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {:?}", CoseAlgorithmIdentifier::Mldsa87).as_str() 5535 ) 5536 .to_string().into_bytes(); 5537 assert_eq!( 5538 serde_json::from_str::<Registration>( 5539 serde_json::json!({ 5540 "id": "AAAAAAAAAAAAAAAAAAAAAA", 5541 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 5542 "response": { 5543 "clientDataJSON": b64_cdata_json, 5544 "authenticatorData": b64_adata, 5545 "transports": [], 5546 "publicKey": null, 5547 "publicKeyAlgorithm": -7i8, 5548 "attestationObject": b64_aobj, 5549 }, 5550 "clientExtensionResults": {}, 5551 "type": "public-key" 5552 }) 5553 .to_string() 5554 .as_str() 5555 ) 5556 .unwrap_err() 5557 .to_string() 5558 .into_bytes() 5559 .get(..err.len()), 5560 Some(err.as_slice()) 5561 ); 5562 } 5563 #[expect( 5564 clippy::assertions_on_result_states, 5565 clippy::unwrap_used, 5566 reason = "OK in tests" 5567 )] 5568 #[expect(clippy::indexing_slicing, reason = "comments justify correctness")] 5569 #[expect(clippy::too_many_lines, reason = "a lot to test")] 5570 #[test] 5571 fn mldsa65_registration_deserialize_data_mismatch() { 5572 let c_data_json = serde_json::json!({}).to_string(); 5573 let att_obj: [u8; 2064] = [ 5574 cbor::MAP_3, 5575 cbor::TEXT_3, 5576 b'f', 5577 b'm', 5578 b't', 5579 cbor::TEXT_4, 5580 b'n', 5581 b'o', 5582 b'n', 5583 b'e', 5584 cbor::TEXT_7, 5585 b'a', 5586 b't', 5587 b't', 5588 b'S', 5589 b't', 5590 b'm', 5591 b't', 5592 cbor::MAP_0, 5593 cbor::TEXT_8, 5594 b'a', 5595 b'u', 5596 b't', 5597 b'h', 5598 b'D', 5599 b'a', 5600 b't', 5601 b'a', 5602 cbor::BYTES_INFO_25, 5603 7, 5604 241, 5605 // `rpIdHash`. 5606 0, 5607 0, 5608 0, 5609 0, 5610 0, 5611 0, 5612 0, 5613 0, 5614 0, 5615 0, 5616 0, 5617 0, 5618 0, 5619 0, 5620 0, 5621 0, 5622 0, 5623 0, 5624 0, 5625 0, 5626 0, 5627 0, 5628 0, 5629 0, 5630 0, 5631 0, 5632 0, 5633 0, 5634 0, 5635 0, 5636 0, 5637 0, 5638 // `flags`. 5639 0b0100_0101, 5640 // `signCount`. 5641 0, 5642 0, 5643 0, 5644 0, 5645 // `aaguid`. 5646 0, 5647 0, 5648 0, 5649 0, 5650 0, 5651 0, 5652 0, 5653 0, 5654 0, 5655 0, 5656 0, 5657 0, 5658 0, 5659 0, 5660 0, 5661 0, 5662 // `credentialIdLength`. 5663 0, 5664 16, 5665 // `credentialId`. 5666 0, 5667 0, 5668 0, 5669 0, 5670 0, 5671 0, 5672 0, 5673 0, 5674 0, 5675 0, 5676 0, 5677 0, 5678 0, 5679 0, 5680 0, 5681 0, 5682 // ML-DSA-65 COSE key. 5683 cbor::MAP_3, 5684 KTY, 5685 AKP, 5686 ALG, 5687 cbor::NEG_INFO_24, 5688 MLDSA65, 5689 // `pub`. 5690 cbor::NEG_ONE, 5691 cbor::BYTES_INFO_25, 5692 7, 5693 160, 5694 // Encoded key. 5695 1, 5696 1, 5697 1, 5698 1, 5699 1, 5700 1, 5701 1, 5702 1, 5703 1, 5704 1, 5705 1, 5706 1, 5707 1, 5708 1, 5709 1, 5710 1, 5711 1, 5712 1, 5713 1, 5714 1, 5715 1, 5716 1, 5717 1, 5718 1, 5719 1, 5720 1, 5721 1, 5722 1, 5723 1, 5724 1, 5725 1, 5726 1, 5727 1, 5728 1, 5729 1, 5730 1, 5731 1, 5732 1, 5733 1, 5734 1, 5735 1, 5736 1, 5737 1, 5738 1, 5739 1, 5740 1, 5741 1, 5742 1, 5743 1, 5744 1, 5745 1, 5746 1, 5747 1, 5748 1, 5749 1, 5750 1, 5751 1, 5752 1, 5753 1, 5754 1, 5755 1, 5756 1, 5757 1, 5758 1, 5759 1, 5760 1, 5761 1, 5762 1, 5763 1, 5764 1, 5765 1, 5766 1, 5767 1, 5768 1, 5769 1, 5770 1, 5771 1, 5772 1, 5773 1, 5774 1, 5775 1, 5776 1, 5777 1, 5778 1, 5779 1, 5780 1, 5781 1, 5782 1, 5783 1, 5784 1, 5785 1, 5786 1, 5787 1, 5788 1, 5789 1, 5790 1, 5791 1, 5792 1, 5793 1, 5794 1, 5795 1, 5796 1, 5797 1, 5798 1, 5799 1, 5800 1, 5801 1, 5802 1, 5803 1, 5804 1, 5805 1, 5806 1, 5807 1, 5808 1, 5809 1, 5810 1, 5811 1, 5812 1, 5813 1, 5814 1, 5815 1, 5816 1, 5817 1, 5818 1, 5819 1, 5820 1, 5821 1, 5822 1, 5823 1, 5824 1, 5825 1, 5826 1, 5827 1, 5828 1, 5829 1, 5830 1, 5831 1, 5832 1, 5833 1, 5834 1, 5835 1, 5836 1, 5837 1, 5838 1, 5839 1, 5840 1, 5841 1, 5842 1, 5843 1, 5844 1, 5845 1, 5846 1, 5847 1, 5848 1, 5849 1, 5850 1, 5851 1, 5852 1, 5853 1, 5854 1, 5855 1, 5856 1, 5857 1, 5858 1, 5859 1, 5860 1, 5861 1, 5862 1, 5863 1, 5864 1, 5865 1, 5866 1, 5867 1, 5868 1, 5869 1, 5870 1, 5871 1, 5872 1, 5873 1, 5874 1, 5875 1, 5876 1, 5877 1, 5878 1, 5879 1, 5880 1, 5881 1, 5882 1, 5883 1, 5884 1, 5885 1, 5886 1, 5887 1, 5888 1, 5889 1, 5890 1, 5891 1, 5892 1, 5893 1, 5894 1, 5895 1, 5896 1, 5897 1, 5898 1, 5899 1, 5900 1, 5901 1, 5902 1, 5903 1, 5904 1, 5905 1, 5906 1, 5907 1, 5908 1, 5909 1, 5910 1, 5911 1, 5912 1, 5913 1, 5914 1, 5915 1, 5916 1, 5917 1, 5918 1, 5919 1, 5920 1, 5921 1, 5922 1, 5923 1, 5924 1, 5925 1, 5926 1, 5927 1, 5928 1, 5929 1, 5930 1, 5931 1, 5932 1, 5933 1, 5934 1, 5935 1, 5936 1, 5937 1, 5938 1, 5939 1, 5940 1, 5941 1, 5942 1, 5943 1, 5944 1, 5945 1, 5946 1, 5947 1, 5948 1, 5949 1, 5950 1, 5951 1, 5952 1, 5953 1, 5954 1, 5955 1, 5956 1, 5957 1, 5958 1, 5959 1, 5960 1, 5961 1, 5962 1, 5963 1, 5964 1, 5965 1, 5966 1, 5967 1, 5968 1, 5969 1, 5970 1, 5971 1, 5972 1, 5973 1, 5974 1, 5975 1, 5976 1, 5977 1, 5978 1, 5979 1, 5980 1, 5981 1, 5982 1, 5983 1, 5984 1, 5985 1, 5986 1, 5987 1, 5988 1, 5989 1, 5990 1, 5991 1, 5992 1, 5993 1, 5994 1, 5995 1, 5996 1, 5997 1, 5998 1, 5999 1, 6000 1, 6001 1, 6002 1, 6003 1, 6004 1, 6005 1, 6006 1, 6007 1, 6008 1, 6009 1, 6010 1, 6011 1, 6012 1, 6013 1, 6014 1, 6015 1, 6016 1, 6017 1, 6018 1, 6019 1, 6020 1, 6021 1, 6022 1, 6023 1, 6024 1, 6025 1, 6026 1, 6027 1, 6028 1, 6029 1, 6030 1, 6031 1, 6032 1, 6033 1, 6034 1, 6035 1, 6036 1, 6037 1, 6038 1, 6039 1, 6040 1, 6041 1, 6042 1, 6043 1, 6044 1, 6045 1, 6046 1, 6047 1, 6048 1, 6049 1, 6050 1, 6051 1, 6052 1, 6053 1, 6054 1, 6055 1, 6056 1, 6057 1, 6058 1, 6059 1, 6060 1, 6061 1, 6062 1, 6063 1, 6064 1, 6065 1, 6066 1, 6067 1, 6068 1, 6069 1, 6070 1, 6071 1, 6072 1, 6073 1, 6074 1, 6075 1, 6076 1, 6077 1, 6078 1, 6079 1, 6080 1, 6081 1, 6082 1, 6083 1, 6084 1, 6085 1, 6086 1, 6087 1, 6088 1, 6089 1, 6090 1, 6091 1, 6092 1, 6093 1, 6094 1, 6095 1, 6096 1, 6097 1, 6098 1, 6099 1, 6100 1, 6101 1, 6102 1, 6103 1, 6104 1, 6105 1, 6106 1, 6107 1, 6108 1, 6109 1, 6110 1, 6111 1, 6112 1, 6113 1, 6114 1, 6115 1, 6116 1, 6117 1, 6118 1, 6119 1, 6120 1, 6121 1, 6122 1, 6123 1, 6124 1, 6125 1, 6126 1, 6127 1, 6128 1, 6129 1, 6130 1, 6131 1, 6132 1, 6133 1, 6134 1, 6135 1, 6136 1, 6137 1, 6138 1, 6139 1, 6140 1, 6141 1, 6142 1, 6143 1, 6144 1, 6145 1, 6146 1, 6147 1, 6148 1, 6149 1, 6150 1, 6151 1, 6152 1, 6153 1, 6154 1, 6155 1, 6156 1, 6157 1, 6158 1, 6159 1, 6160 1, 6161 1, 6162 1, 6163 1, 6164 1, 6165 1, 6166 1, 6167 1, 6168 1, 6169 1, 6170 1, 6171 1, 6172 1, 6173 1, 6174 1, 6175 1, 6176 1, 6177 1, 6178 1, 6179 1, 6180 1, 6181 1, 6182 1, 6183 1, 6184 1, 6185 1, 6186 1, 6187 1, 6188 1, 6189 1, 6190 1, 6191 1, 6192 1, 6193 1, 6194 1, 6195 1, 6196 1, 6197 1, 6198 1, 6199 1, 6200 1, 6201 1, 6202 1, 6203 1, 6204 1, 6205 1, 6206 1, 6207 1, 6208 1, 6209 1, 6210 1, 6211 1, 6212 1, 6213 1, 6214 1, 6215 1, 6216 1, 6217 1, 6218 1, 6219 1, 6220 1, 6221 1, 6222 1, 6223 1, 6224 1, 6225 1, 6226 1, 6227 1, 6228 1, 6229 1, 6230 1, 6231 1, 6232 1, 6233 1, 6234 1, 6235 1, 6236 1, 6237 1, 6238 1, 6239 1, 6240 1, 6241 1, 6242 1, 6243 1, 6244 1, 6245 1, 6246 1, 6247 1, 6248 1, 6249 1, 6250 1, 6251 1, 6252 1, 6253 1, 6254 1, 6255 1, 6256 1, 6257 1, 6258 1, 6259 1, 6260 1, 6261 1, 6262 1, 6263 1, 6264 1, 6265 1, 6266 1, 6267 1, 6268 1, 6269 1, 6270 1, 6271 1, 6272 1, 6273 1, 6274 1, 6275 1, 6276 1, 6277 1, 6278 1, 6279 1, 6280 1, 6281 1, 6282 1, 6283 1, 6284 1, 6285 1, 6286 1, 6287 1, 6288 1, 6289 1, 6290 1, 6291 1, 6292 1, 6293 1, 6294 1, 6295 1, 6296 1, 6297 1, 6298 1, 6299 1, 6300 1, 6301 1, 6302 1, 6303 1, 6304 1, 6305 1, 6306 1, 6307 1, 6308 1, 6309 1, 6310 1, 6311 1, 6312 1, 6313 1, 6314 1, 6315 1, 6316 1, 6317 1, 6318 1, 6319 1, 6320 1, 6321 1, 6322 1, 6323 1, 6324 1, 6325 1, 6326 1, 6327 1, 6328 1, 6329 1, 6330 1, 6331 1, 6332 1, 6333 1, 6334 1, 6335 1, 6336 1, 6337 1, 6338 1, 6339 1, 6340 1, 6341 1, 6342 1, 6343 1, 6344 1, 6345 1, 6346 1, 6347 1, 6348 1, 6349 1, 6350 1, 6351 1, 6352 1, 6353 1, 6354 1, 6355 1, 6356 1, 6357 1, 6358 1, 6359 1, 6360 1, 6361 1, 6362 1, 6363 1, 6364 1, 6365 1, 6366 1, 6367 1, 6368 1, 6369 1, 6370 1, 6371 1, 6372 1, 6373 1, 6374 1, 6375 1, 6376 1, 6377 1, 6378 1, 6379 1, 6380 1, 6381 1, 6382 1, 6383 1, 6384 1, 6385 1, 6386 1, 6387 1, 6388 1, 6389 1, 6390 1, 6391 1, 6392 1, 6393 1, 6394 1, 6395 1, 6396 1, 6397 1, 6398 1, 6399 1, 6400 1, 6401 1, 6402 1, 6403 1, 6404 1, 6405 1, 6406 1, 6407 1, 6408 1, 6409 1, 6410 1, 6411 1, 6412 1, 6413 1, 6414 1, 6415 1, 6416 1, 6417 1, 6418 1, 6419 1, 6420 1, 6421 1, 6422 1, 6423 1, 6424 1, 6425 1, 6426 1, 6427 1, 6428 1, 6429 1, 6430 1, 6431 1, 6432 1, 6433 1, 6434 1, 6435 1, 6436 1, 6437 1, 6438 1, 6439 1, 6440 1, 6441 1, 6442 1, 6443 1, 6444 1, 6445 1, 6446 1, 6447 1, 6448 1, 6449 1, 6450 1, 6451 1, 6452 1, 6453 1, 6454 1, 6455 1, 6456 1, 6457 1, 6458 1, 6459 1, 6460 1, 6461 1, 6462 1, 6463 1, 6464 1, 6465 1, 6466 1, 6467 1, 6468 1, 6469 1, 6470 1, 6471 1, 6472 1, 6473 1, 6474 1, 6475 1, 6476 1, 6477 1, 6478 1, 6479 1, 6480 1, 6481 1, 6482 1, 6483 1, 6484 1, 6485 1, 6486 1, 6487 1, 6488 1, 6489 1, 6490 1, 6491 1, 6492 1, 6493 1, 6494 1, 6495 1, 6496 1, 6497 1, 6498 1, 6499 1, 6500 1, 6501 1, 6502 1, 6503 1, 6504 1, 6505 1, 6506 1, 6507 1, 6508 1, 6509 1, 6510 1, 6511 1, 6512 1, 6513 1, 6514 1, 6515 1, 6516 1, 6517 1, 6518 1, 6519 1, 6520 1, 6521 1, 6522 1, 6523 1, 6524 1, 6525 1, 6526 1, 6527 1, 6528 1, 6529 1, 6530 1, 6531 1, 6532 1, 6533 1, 6534 1, 6535 1, 6536 1, 6537 1, 6538 1, 6539 1, 6540 1, 6541 1, 6542 1, 6543 1, 6544 1, 6545 1, 6546 1, 6547 1, 6548 1, 6549 1, 6550 1, 6551 1, 6552 1, 6553 1, 6554 1, 6555 1, 6556 1, 6557 1, 6558 1, 6559 1, 6560 1, 6561 1, 6562 1, 6563 1, 6564 1, 6565 1, 6566 1, 6567 1, 6568 1, 6569 1, 6570 1, 6571 1, 6572 1, 6573 1, 6574 1, 6575 1, 6576 1, 6577 1, 6578 1, 6579 1, 6580 1, 6581 1, 6582 1, 6583 1, 6584 1, 6585 1, 6586 1, 6587 1, 6588 1, 6589 1, 6590 1, 6591 1, 6592 1, 6593 1, 6594 1, 6595 1, 6596 1, 6597 1, 6598 1, 6599 1, 6600 1, 6601 1, 6602 1, 6603 1, 6604 1, 6605 1, 6606 1, 6607 1, 6608 1, 6609 1, 6610 1, 6611 1, 6612 1, 6613 1, 6614 1, 6615 1, 6616 1, 6617 1, 6618 1, 6619 1, 6620 1, 6621 1, 6622 1, 6623 1, 6624 1, 6625 1, 6626 1, 6627 1, 6628 1, 6629 1, 6630 1, 6631 1, 6632 1, 6633 1, 6634 1, 6635 1, 6636 1, 6637 1, 6638 1, 6639 1, 6640 1, 6641 1, 6642 1, 6643 1, 6644 1, 6645 1, 6646 1, 6647 1, 6648 1, 6649 1, 6650 1, 6651 1, 6652 1, 6653 1, 6654 1, 6655 1, 6656 1, 6657 1, 6658 1, 6659 1, 6660 1, 6661 1, 6662 1, 6663 1, 6664 1, 6665 1, 6666 1, 6667 1, 6668 1, 6669 1, 6670 1, 6671 1, 6672 1, 6673 1, 6674 1, 6675 1, 6676 1, 6677 1, 6678 1, 6679 1, 6680 1, 6681 1, 6682 1, 6683 1, 6684 1, 6685 1, 6686 1, 6687 1, 6688 1, 6689 1, 6690 1, 6691 1, 6692 1, 6693 1, 6694 1, 6695 1, 6696 1, 6697 1, 6698 1, 6699 1, 6700 1, 6701 1, 6702 1, 6703 1, 6704 1, 6705 1, 6706 1, 6707 1, 6708 1, 6709 1, 6710 1, 6711 1, 6712 1, 6713 1, 6714 1, 6715 1, 6716 1, 6717 1, 6718 1, 6719 1, 6720 1, 6721 1, 6722 1, 6723 1, 6724 1, 6725 1, 6726 1, 6727 1, 6728 1, 6729 1, 6730 1, 6731 1, 6732 1, 6733 1, 6734 1, 6735 1, 6736 1, 6737 1, 6738 1, 6739 1, 6740 1, 6741 1, 6742 1, 6743 1, 6744 1, 6745 1, 6746 1, 6747 1, 6748 1, 6749 1, 6750 1, 6751 1, 6752 1, 6753 1, 6754 1, 6755 1, 6756 1, 6757 1, 6758 1, 6759 1, 6760 1, 6761 1, 6762 1, 6763 1, 6764 1, 6765 1, 6766 1, 6767 1, 6768 1, 6769 1, 6770 1, 6771 1, 6772 1, 6773 1, 6774 1, 6775 1, 6776 1, 6777 1, 6778 1, 6779 1, 6780 1, 6781 1, 6782 1, 6783 1, 6784 1, 6785 1, 6786 1, 6787 1, 6788 1, 6789 1, 6790 1, 6791 1, 6792 1, 6793 1, 6794 1, 6795 1, 6796 1, 6797 1, 6798 1, 6799 1, 6800 1, 6801 1, 6802 1, 6803 1, 6804 1, 6805 1, 6806 1, 6807 1, 6808 1, 6809 1, 6810 1, 6811 1, 6812 1, 6813 1, 6814 1, 6815 1, 6816 1, 6817 1, 6818 1, 6819 1, 6820 1, 6821 1, 6822 1, 6823 1, 6824 1, 6825 1, 6826 1, 6827 1, 6828 1, 6829 1, 6830 1, 6831 1, 6832 1, 6833 1, 6834 1, 6835 1, 6836 1, 6837 1, 6838 1, 6839 1, 6840 1, 6841 1, 6842 1, 6843 1, 6844 1, 6845 1, 6846 1, 6847 1, 6848 1, 6849 1, 6850 1, 6851 1, 6852 1, 6853 1, 6854 1, 6855 1, 6856 1, 6857 1, 6858 1, 6859 1, 6860 1, 6861 1, 6862 1, 6863 1, 6864 1, 6865 1, 6866 1, 6867 1, 6868 1, 6869 1, 6870 1, 6871 1, 6872 1, 6873 1, 6874 1, 6875 1, 6876 1, 6877 1, 6878 1, 6879 1, 6880 1, 6881 1, 6882 1, 6883 1, 6884 1, 6885 1, 6886 1, 6887 1, 6888 1, 6889 1, 6890 1, 6891 1, 6892 1, 6893 1, 6894 1, 6895 1, 6896 1, 6897 1, 6898 1, 6899 1, 6900 1, 6901 1, 6902 1, 6903 1, 6904 1, 6905 1, 6906 1, 6907 1, 6908 1, 6909 1, 6910 1, 6911 1, 6912 1, 6913 1, 6914 1, 6915 1, 6916 1, 6917 1, 6918 1, 6919 1, 6920 1, 6921 1, 6922 1, 6923 1, 6924 1, 6925 1, 6926 1, 6927 1, 6928 1, 6929 1, 6930 1, 6931 1, 6932 1, 6933 1, 6934 1, 6935 1, 6936 1, 6937 1, 6938 1, 6939 1, 6940 1, 6941 1, 6942 1, 6943 1, 6944 1, 6945 1, 6946 1, 6947 1, 6948 1, 6949 1, 6950 1, 6951 1, 6952 1, 6953 1, 6954 1, 6955 1, 6956 1, 6957 1, 6958 1, 6959 1, 6960 1, 6961 1, 6962 1, 6963 1, 6964 1, 6965 1, 6966 1, 6967 1, 6968 1, 6969 1, 6970 1, 6971 1, 6972 1, 6973 1, 6974 1, 6975 1, 6976 1, 6977 1, 6978 1, 6979 1, 6980 1, 6981 1, 6982 1, 6983 1, 6984 1, 6985 1, 6986 1, 6987 1, 6988 1, 6989 1, 6990 1, 6991 1, 6992 1, 6993 1, 6994 1, 6995 1, 6996 1, 6997 1, 6998 1, 6999 1, 7000 1, 7001 1, 7002 1, 7003 1, 7004 1, 7005 1, 7006 1, 7007 1, 7008 1, 7009 1, 7010 1, 7011 1, 7012 1, 7013 1, 7014 1, 7015 1, 7016 1, 7017 1, 7018 1, 7019 1, 7020 1, 7021 1, 7022 1, 7023 1, 7024 1, 7025 1, 7026 1, 7027 1, 7028 1, 7029 1, 7030 1, 7031 1, 7032 1, 7033 1, 7034 1, 7035 1, 7036 1, 7037 1, 7038 1, 7039 1, 7040 1, 7041 1, 7042 1, 7043 1, 7044 1, 7045 1, 7046 1, 7047 1, 7048 1, 7049 1, 7050 1, 7051 1, 7052 1, 7053 1, 7054 1, 7055 1, 7056 1, 7057 1, 7058 1, 7059 1, 7060 1, 7061 1, 7062 1, 7063 1, 7064 1, 7065 1, 7066 1, 7067 1, 7068 1, 7069 1, 7070 1, 7071 1, 7072 1, 7073 1, 7074 1, 7075 1, 7076 1, 7077 1, 7078 1, 7079 1, 7080 1, 7081 1, 7082 1, 7083 1, 7084 1, 7085 1, 7086 1, 7087 1, 7088 1, 7089 1, 7090 1, 7091 1, 7092 1, 7093 1, 7094 1, 7095 1, 7096 1, 7097 1, 7098 1, 7099 1, 7100 1, 7101 1, 7102 1, 7103 1, 7104 1, 7105 1, 7106 1, 7107 1, 7108 1, 7109 1, 7110 1, 7111 1, 7112 1, 7113 1, 7114 1, 7115 1, 7116 1, 7117 1, 7118 1, 7119 1, 7120 1, 7121 1, 7122 1, 7123 1, 7124 1, 7125 1, 7126 1, 7127 1, 7128 1, 7129 1, 7130 1, 7131 1, 7132 1, 7133 1, 7134 1, 7135 1, 7136 1, 7137 1, 7138 1, 7139 1, 7140 1, 7141 1, 7142 1, 7143 1, 7144 1, 7145 1, 7146 1, 7147 1, 7148 1, 7149 1, 7150 1, 7151 1, 7152 1, 7153 1, 7154 1, 7155 1, 7156 1, 7157 1, 7158 1, 7159 1, 7160 1, 7161 1, 7162 1, 7163 1, 7164 1, 7165 1, 7166 1, 7167 1, 7168 1, 7169 1, 7170 1, 7171 1, 7172 1, 7173 1, 7174 1, 7175 1, 7176 1, 7177 1, 7178 1, 7179 1, 7180 1, 7181 1, 7182 1, 7183 1, 7184 1, 7185 1, 7186 1, 7187 1, 7188 1, 7189 1, 7190 1, 7191 1, 7192 1, 7193 1, 7194 1, 7195 1, 7196 1, 7197 1, 7198 1, 7199 1, 7200 1, 7201 1, 7202 1, 7203 1, 7204 1, 7205 1, 7206 1, 7207 1, 7208 1, 7209 1, 7210 1, 7211 1, 7212 1, 7213 1, 7214 1, 7215 1, 7216 1, 7217 1, 7218 1, 7219 1, 7220 1, 7221 1, 7222 1, 7223 1, 7224 1, 7225 1, 7226 1, 7227 1, 7228 1, 7229 1, 7230 1, 7231 1, 7232 1, 7233 1, 7234 1, 7235 1, 7236 1, 7237 1, 7238 1, 7239 1, 7240 1, 7241 1, 7242 1, 7243 1, 7244 1, 7245 1, 7246 1, 7247 1, 7248 1, 7249 1, 7250 1, 7251 1, 7252 1, 7253 1, 7254 1, 7255 1, 7256 1, 7257 1, 7258 1, 7259 1, 7260 1, 7261 1, 7262 1, 7263 1, 7264 1, 7265 1, 7266 1, 7267 1, 7268 1, 7269 1, 7270 1, 7271 1, 7272 1, 7273 1, 7274 1, 7275 1, 7276 1, 7277 1, 7278 1, 7279 1, 7280 1, 7281 1, 7282 1, 7283 1, 7284 1, 7285 1, 7286 1, 7287 1, 7288 1, 7289 1, 7290 1, 7291 1, 7292 1, 7293 1, 7294 1, 7295 1, 7296 1, 7297 1, 7298 1, 7299 1, 7300 1, 7301 1, 7302 1, 7303 1, 7304 1, 7305 1, 7306 1, 7307 1, 7308 1, 7309 1, 7310 1, 7311 1, 7312 1, 7313 1, 7314 1, 7315 1, 7316 1, 7317 1, 7318 1, 7319 1, 7320 1, 7321 1, 7322 1, 7323 1, 7324 1, 7325 1, 7326 1, 7327 1, 7328 1, 7329 1, 7330 1, 7331 1, 7332 1, 7333 1, 7334 1, 7335 1, 7336 1, 7337 1, 7338 1, 7339 1, 7340 1, 7341 1, 7342 1, 7343 1, 7344 1, 7345 1, 7346 1, 7347 1, 7348 1, 7349 1, 7350 1, 7351 1, 7352 1, 7353 1, 7354 1, 7355 1, 7356 1, 7357 1, 7358 1, 7359 1, 7360 1, 7361 1, 7362 1, 7363 1, 7364 1, 7365 1, 7366 1, 7367 1, 7368 1, 7369 1, 7370 1, 7371 1, 7372 1, 7373 1, 7374 1, 7375 1, 7376 1, 7377 1, 7378 1, 7379 1, 7380 1, 7381 1, 7382 1, 7383 1, 7384 1, 7385 1, 7386 1, 7387 1, 7388 1, 7389 1, 7390 1, 7391 1, 7392 1, 7393 1, 7394 1, 7395 1, 7396 1, 7397 1, 7398 1, 7399 1, 7400 1, 7401 1, 7402 1, 7403 1, 7404 1, 7405 1, 7406 1, 7407 1, 7408 1, 7409 1, 7410 1, 7411 1, 7412 1, 7413 1, 7414 1, 7415 1, 7416 1, 7417 1, 7418 1, 7419 1, 7420 1, 7421 1, 7422 1, 7423 1, 7424 1, 7425 1, 7426 1, 7427 1, 7428 1, 7429 1, 7430 1, 7431 1, 7432 1, 7433 1, 7434 1, 7435 1, 7436 1, 7437 1, 7438 1, 7439 1, 7440 1, 7441 1, 7442 1, 7443 1, 7444 1, 7445 1, 7446 1, 7447 1, 7448 1, 7449 1, 7450 1, 7451 1, 7452 1, 7453 1, 7454 1, 7455 1, 7456 1, 7457 1, 7458 1, 7459 1, 7460 1, 7461 1, 7462 1, 7463 1, 7464 1, 7465 1, 7466 1, 7467 1, 7468 1, 7469 1, 7470 1, 7471 1, 7472 1, 7473 1, 7474 1, 7475 1, 7476 1, 7477 1, 7478 1, 7479 1, 7480 1, 7481 1, 7482 1, 7483 1, 7484 1, 7485 1, 7486 1, 7487 1, 7488 1, 7489 1, 7490 1, 7491 1, 7492 1, 7493 1, 7494 1, 7495 1, 7496 1, 7497 1, 7498 1, 7499 1, 7500 1, 7501 1, 7502 1, 7503 1, 7504 1, 7505 1, 7506 1, 7507 1, 7508 1, 7509 1, 7510 1, 7511 1, 7512 1, 7513 1, 7514 1, 7515 1, 7516 1, 7517 1, 7518 1, 7519 1, 7520 1, 7521 1, 7522 1, 7523 1, 7524 1, 7525 1, 7526 1, 7527 1, 7528 1, 7529 1, 7530 1, 7531 1, 7532 1, 7533 1, 7534 1, 7535 1, 7536 1, 7537 1, 7538 1, 7539 1, 7540 1, 7541 1, 7542 1, 7543 1, 7544 1, 7545 1, 7546 1, 7547 1, 7548 1, 7549 1, 7550 1, 7551 1, 7552 1, 7553 1, 7554 1, 7555 1, 7556 1, 7557 1, 7558 1, 7559 1, 7560 1, 7561 1, 7562 1, 7563 1, 7564 1, 7565 1, 7566 1, 7567 1, 7568 1, 7569 1, 7570 1, 7571 1, 7572 1, 7573 1, 7574 1, 7575 1, 7576 1, 7577 1, 7578 1, 7579 1, 7580 1, 7581 1, 7582 1, 7583 1, 7584 1, 7585 1, 7586 1, 7587 1, 7588 1, 7589 1, 7590 1, 7591 1, 7592 1, 7593 1, 7594 1, 7595 1, 7596 1, 7597 1, 7598 1, 7599 1, 7600 1, 7601 1, 7602 1, 7603 1, 7604 1, 7605 1, 7606 1, 7607 1, 7608 1, 7609 1, 7610 1, 7611 1, 7612 1, 7613 1, 7614 1, 7615 1, 7616 1, 7617 1, 7618 1, 7619 1, 7620 1, 7621 1, 7622 1, 7623 1, 7624 1, 7625 1, 7626 1, 7627 1, 7628 1, 7629 1, 7630 1, 7631 1, 7632 1, 7633 1, 7634 1, 7635 1, 7636 1, 7637 1, 7638 1, 7639 1, 7640 1, 7641 1, 7642 1, 7643 1, 7644 1, 7645 1, 7646 1, 7647 ]; 7648 let pub_key = MlDsaVerKey::<MlDsa65>::decode(&[1u8; 1952].into()) 7649 .to_public_key_der() 7650 .unwrap(); 7651 let att_obj_len = att_obj.len(); 7652 let b64_cdata_json = base64url_nopad::encode(c_data_json.as_bytes()); 7653 let b64_adata = base64url_nopad::encode(&att_obj[att_obj_len - 2033..]); 7654 let b64_key = base64url_nopad::encode(pub_key.as_bytes()); 7655 let b64_aobj = base64url_nopad::encode(att_obj.as_slice()); 7656 // Base case is valid. 7657 assert!( 7658 serde_json::from_str::<Registration>( 7659 serde_json::json!({ 7660 "id": "AAAAAAAAAAAAAAAAAAAAAA", 7661 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 7662 "response": { 7663 "clientDataJSON": b64_cdata_json, 7664 "authenticatorData": b64_adata, 7665 "transports": [], 7666 "publicKey": b64_key, 7667 "publicKeyAlgorithm": -49i8, 7668 "attestationObject": b64_aobj, 7669 }, 7670 "clientExtensionResults": {}, 7671 "type": "public-key" 7672 }) 7673 .to_string() 7674 .as_str() 7675 ) 7676 .is_ok_and( 7677 |reg| reg.response.client_data_json == c_data_json.as_bytes() 7678 && reg.response.attestation_object_and_c_data_hash[..att_obj_len] == att_obj 7679 && reg.response.attestation_object_and_c_data_hash[att_obj_len..] 7680 == *Sha256::digest(c_data_json.as_bytes()) 7681 && reg.response.transports.is_empty() 7682 && matches!(reg.authenticator_attachment, AuthenticatorAttachment::None) 7683 && reg.client_extension_results.cred_props.is_none() 7684 && reg.client_extension_results.prf.is_none() 7685 ) 7686 ); 7687 // `publicKeyAlgorithm` mismatch. 7688 let mut err = Error::invalid_value( 7689 Unexpected::Other(format!("{:?}", CoseAlgorithmIdentifier::Eddsa).as_str()), 7690 &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {:?}", CoseAlgorithmIdentifier::Mldsa65).as_str() 7691 ) 7692 .to_string().into_bytes(); 7693 assert_eq!( 7694 serde_json::from_str::<Registration>( 7695 serde_json::json!({ 7696 "id": "AAAAAAAAAAAAAAAAAAAAAA", 7697 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 7698 "response": { 7699 "clientDataJSON": b64_cdata_json, 7700 "authenticatorData": b64_adata, 7701 "transports": [], 7702 "publicKey": b64_key, 7703 "publicKeyAlgorithm": -8i8, 7704 "attestationObject": b64_aobj, 7705 }, 7706 "clientExtensionResults": {}, 7707 "type": "public-key" 7708 }) 7709 .to_string() 7710 .as_str() 7711 ) 7712 .unwrap_err() 7713 .to_string() 7714 .into_bytes() 7715 .get(..err.len()), 7716 Some(err.as_slice()) 7717 ); 7718 // Missing `publicKeyAlgorithm`. 7719 err = Error::missing_field("publicKeyAlgorithm") 7720 .to_string() 7721 .into_bytes(); 7722 assert_eq!( 7723 serde_json::from_str::<Registration>( 7724 serde_json::json!({ 7725 "id": "AAAAAAAAAAAAAAAAAAAAAA", 7726 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 7727 "response": { 7728 "clientDataJSON": b64_cdata_json, 7729 "authenticatorData": b64_adata, 7730 "transports": [], 7731 "publicKey": b64_key, 7732 "attestationObject": b64_aobj, 7733 }, 7734 "clientExtensionResults": {}, 7735 "type": "public-key" 7736 }) 7737 .to_string() 7738 .as_str() 7739 ) 7740 .unwrap_err() 7741 .to_string() 7742 .into_bytes() 7743 .get(..err.len()), 7744 Some(err.as_slice()) 7745 ); 7746 // `null` `publicKeyAlgorithm`. 7747 err = Error::invalid_type(Unexpected::Other("null"), &"publicKeyAlgorithm") 7748 .to_string() 7749 .into_bytes(); 7750 assert_eq!( 7751 serde_json::from_str::<Registration>( 7752 serde_json::json!({ 7753 "id": "AAAAAAAAAAAAAAAAAAAAAA", 7754 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 7755 "response": { 7756 "clientDataJSON": b64_cdata_json, 7757 "authenticatorData": b64_adata, 7758 "transports": [], 7759 "publicKey": b64_key, 7760 "publicKeyAlgorithm": null, 7761 "attestationObject": b64_aobj, 7762 }, 7763 "clientExtensionResults": {}, 7764 "type": "public-key" 7765 }) 7766 .to_string() 7767 .as_str() 7768 ) 7769 .unwrap_err() 7770 .to_string() 7771 .into_bytes() 7772 .get(..err.len()), 7773 Some(err.as_slice()) 7774 ); 7775 // `publicKey` mismatch. 7776 let bad_pub_key = MlDsaVerKey::<MlDsa65>::decode(&[2; 1952].into()); 7777 err = Error::invalid_value( 7778 Unexpected::Bytes([0; 32].as_slice()), 7779 &format!( 7780 "DER-encoded public key to match the public key within the attestation object: MlDsa65(MlDsa65PubKey({:?}))", 7781 &[1u8; 1952] 7782 ) 7783 .as_str(), 7784 ) 7785 .to_string().into_bytes(); 7786 assert_eq!(serde_json::from_str::<Registration>( 7787 serde_json::json!({ 7788 "id": "AAAAAAAAAAAAAAAAAAAAAA", 7789 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 7790 "response": { 7791 "clientDataJSON": b64_cdata_json, 7792 "authenticatorData": b64_adata, 7793 "transports": [], 7794 "publicKey": base64url_nopad::encode(bad_pub_key.to_public_key_der().unwrap().as_bytes()), 7795 "publicKeyAlgorithm": -49i8, 7796 "attestationObject": b64_aobj, 7797 }, 7798 "clientExtensionResults": {}, 7799 "type": "public-key" 7800 }) 7801 .to_string() 7802 .as_str() 7803 ) 7804 .unwrap_err().to_string().into_bytes().get(..err.len()), 7805 Some(err.as_slice()) 7806 ); 7807 // Missing `publicKey` is allowed when not using EdDSA, ES256, or RS256. 7808 assert!( 7809 serde_json::from_str::<Registration>( 7810 serde_json::json!({ 7811 "id": "AAAAAAAAAAAAAAAAAAAAAA", 7812 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 7813 "response": { 7814 "clientDataJSON": b64_cdata_json, 7815 "authenticatorData": b64_adata, 7816 "transports": [], 7817 "publicKeyAlgorithm": -49i8, 7818 "attestationObject": b64_aobj, 7819 }, 7820 "clientExtensionResults": {}, 7821 "type": "public-key" 7822 }) 7823 .to_string() 7824 .as_str() 7825 ) 7826 .is_ok() 7827 ); 7828 // `publicKeyAlgorithm` mismatch when `publicKey` does not exist. 7829 err = Error::invalid_value( 7830 Unexpected::Other(format!("{:?}", CoseAlgorithmIdentifier::Es256).as_str()), 7831 &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {:?}", CoseAlgorithmIdentifier::Mldsa65).as_str() 7832 ) 7833 .to_string().into_bytes(); 7834 assert_eq!( 7835 serde_json::from_str::<Registration>( 7836 serde_json::json!({ 7837 "id": "AAAAAAAAAAAAAAAAAAAAAA", 7838 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 7839 "response": { 7840 "clientDataJSON": b64_cdata_json, 7841 "authenticatorData": b64_adata, 7842 "transports": [], 7843 "publicKeyAlgorithm": -7i8, 7844 "attestationObject": b64_aobj, 7845 }, 7846 "clientExtensionResults": {}, 7847 "type": "public-key" 7848 }) 7849 .to_string() 7850 .as_str() 7851 ) 7852 .unwrap_err() 7853 .to_string() 7854 .into_bytes() 7855 .get(..err.len()), 7856 Some(err.as_slice()) 7857 ); 7858 // `null` `publicKey` is allowed when not using EdDSA, ES256, or RS256. 7859 assert!( 7860 serde_json::from_str::<Registration>( 7861 serde_json::json!({ 7862 "id": "AAAAAAAAAAAAAAAAAAAAAA", 7863 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 7864 "response": { 7865 "clientDataJSON": b64_cdata_json, 7866 "authenticatorData": b64_adata, 7867 "transports": [], 7868 "publicKey": null, 7869 "publicKeyAlgorithm": -49i8, 7870 "attestationObject": b64_aobj, 7871 }, 7872 "clientExtensionResults": {}, 7873 "type": "public-key" 7874 }) 7875 .to_string() 7876 .as_str() 7877 ) 7878 .is_ok() 7879 ); 7880 // `publicKeyAlgorithm` mismatch when `publicKey` is null. 7881 err = Error::invalid_value( 7882 Unexpected::Other(format!("{:?}", CoseAlgorithmIdentifier::Es256).as_str()), 7883 &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {:?}", CoseAlgorithmIdentifier::Mldsa65).as_str() 7884 ) 7885 .to_string().into_bytes(); 7886 assert_eq!( 7887 serde_json::from_str::<Registration>( 7888 serde_json::json!({ 7889 "id": "AAAAAAAAAAAAAAAAAAAAAA", 7890 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 7891 "response": { 7892 "clientDataJSON": b64_cdata_json, 7893 "authenticatorData": b64_adata, 7894 "transports": [], 7895 "publicKey": null, 7896 "publicKeyAlgorithm": -7i8, 7897 "attestationObject": b64_aobj, 7898 }, 7899 "clientExtensionResults": {}, 7900 "type": "public-key" 7901 }) 7902 .to_string() 7903 .as_str() 7904 ) 7905 .unwrap_err() 7906 .to_string() 7907 .into_bytes() 7908 .get(..err.len()), 7909 Some(err.as_slice()) 7910 ); 7911 } 7912 #[expect( 7913 clippy::assertions_on_result_states, 7914 clippy::unwrap_used, 7915 reason = "OK in tests" 7916 )] 7917 #[expect(clippy::indexing_slicing, reason = "comments justify correctness")] 7918 #[expect(clippy::too_many_lines, reason = "a lot to test")] 7919 #[test] 7920 fn mldsa44_registration_deserialize_data_mismatch() { 7921 let c_data_json = serde_json::json!({}).to_string(); 7922 let att_obj: [u8; 1424] = [ 7923 cbor::MAP_3, 7924 cbor::TEXT_3, 7925 b'f', 7926 b'm', 7927 b't', 7928 cbor::TEXT_4, 7929 b'n', 7930 b'o', 7931 b'n', 7932 b'e', 7933 cbor::TEXT_7, 7934 b'a', 7935 b't', 7936 b't', 7937 b'S', 7938 b't', 7939 b'm', 7940 b't', 7941 cbor::MAP_0, 7942 cbor::TEXT_8, 7943 b'a', 7944 b'u', 7945 b't', 7946 b'h', 7947 b'D', 7948 b'a', 7949 b't', 7950 b'a', 7951 cbor::BYTES_INFO_25, 7952 5, 7953 113, 7954 // `rpIdHash`. 7955 0, 7956 0, 7957 0, 7958 0, 7959 0, 7960 0, 7961 0, 7962 0, 7963 0, 7964 0, 7965 0, 7966 0, 7967 0, 7968 0, 7969 0, 7970 0, 7971 0, 7972 0, 7973 0, 7974 0, 7975 0, 7976 0, 7977 0, 7978 0, 7979 0, 7980 0, 7981 0, 7982 0, 7983 0, 7984 0, 7985 0, 7986 0, 7987 // `flags`. 7988 0b0100_0101, 7989 // `signCount`. 7990 0, 7991 0, 7992 0, 7993 0, 7994 // `aaguid`. 7995 0, 7996 0, 7997 0, 7998 0, 7999 0, 8000 0, 8001 0, 8002 0, 8003 0, 8004 0, 8005 0, 8006 0, 8007 0, 8008 0, 8009 0, 8010 0, 8011 // `credentialIdLength`. 8012 0, 8013 16, 8014 // `credentialId`. 8015 0, 8016 0, 8017 0, 8018 0, 8019 0, 8020 0, 8021 0, 8022 0, 8023 0, 8024 0, 8025 0, 8026 0, 8027 0, 8028 0, 8029 0, 8030 0, 8031 // ML-DSA-44 COSE key. 8032 cbor::MAP_3, 8033 KTY, 8034 AKP, 8035 ALG, 8036 cbor::NEG_INFO_24, 8037 MLDSA44, 8038 // `pub`. 8039 cbor::NEG_ONE, 8040 cbor::BYTES_INFO_25, 8041 5, 8042 32, 8043 // Encoded key. 8044 1, 8045 1, 8046 1, 8047 1, 8048 1, 8049 1, 8050 1, 8051 1, 8052 1, 8053 1, 8054 1, 8055 1, 8056 1, 8057 1, 8058 1, 8059 1, 8060 1, 8061 1, 8062 1, 8063 1, 8064 1, 8065 1, 8066 1, 8067 1, 8068 1, 8069 1, 8070 1, 8071 1, 8072 1, 8073 1, 8074 1, 8075 1, 8076 1, 8077 1, 8078 1, 8079 1, 8080 1, 8081 1, 8082 1, 8083 1, 8084 1, 8085 1, 8086 1, 8087 1, 8088 1, 8089 1, 8090 1, 8091 1, 8092 1, 8093 1, 8094 1, 8095 1, 8096 1, 8097 1, 8098 1, 8099 1, 8100 1, 8101 1, 8102 1, 8103 1, 8104 1, 8105 1, 8106 1, 8107 1, 8108 1, 8109 1, 8110 1, 8111 1, 8112 1, 8113 1, 8114 1, 8115 1, 8116 1, 8117 1, 8118 1, 8119 1, 8120 1, 8121 1, 8122 1, 8123 1, 8124 1, 8125 1, 8126 1, 8127 1, 8128 1, 8129 1, 8130 1, 8131 1, 8132 1, 8133 1, 8134 1, 8135 1, 8136 1, 8137 1, 8138 1, 8139 1, 8140 1, 8141 1, 8142 1, 8143 1, 8144 1, 8145 1, 8146 1, 8147 1, 8148 1, 8149 1, 8150 1, 8151 1, 8152 1, 8153 1, 8154 1, 8155 1, 8156 1, 8157 1, 8158 1, 8159 1, 8160 1, 8161 1, 8162 1, 8163 1, 8164 1, 8165 1, 8166 1, 8167 1, 8168 1, 8169 1, 8170 1, 8171 1, 8172 1, 8173 1, 8174 1, 8175 1, 8176 1, 8177 1, 8178 1, 8179 1, 8180 1, 8181 1, 8182 1, 8183 1, 8184 1, 8185 1, 8186 1, 8187 1, 8188 1, 8189 1, 8190 1, 8191 1, 8192 1, 8193 1, 8194 1, 8195 1, 8196 1, 8197 1, 8198 1, 8199 1, 8200 1, 8201 1, 8202 1, 8203 1, 8204 1, 8205 1, 8206 1, 8207 1, 8208 1, 8209 1, 8210 1, 8211 1, 8212 1, 8213 1, 8214 1, 8215 1, 8216 1, 8217 1, 8218 1, 8219 1, 8220 1, 8221 1, 8222 1, 8223 1, 8224 1, 8225 1, 8226 1, 8227 1, 8228 1, 8229 1, 8230 1, 8231 1, 8232 1, 8233 1, 8234 1, 8235 1, 8236 1, 8237 1, 8238 1, 8239 1, 8240 1, 8241 1, 8242 1, 8243 1, 8244 1, 8245 1, 8246 1, 8247 1, 8248 1, 8249 1, 8250 1, 8251 1, 8252 1, 8253 1, 8254 1, 8255 1, 8256 1, 8257 1, 8258 1, 8259 1, 8260 1, 8261 1, 8262 1, 8263 1, 8264 1, 8265 1, 8266 1, 8267 1, 8268 1, 8269 1, 8270 1, 8271 1, 8272 1, 8273 1, 8274 1, 8275 1, 8276 1, 8277 1, 8278 1, 8279 1, 8280 1, 8281 1, 8282 1, 8283 1, 8284 1, 8285 1, 8286 1, 8287 1, 8288 1, 8289 1, 8290 1, 8291 1, 8292 1, 8293 1, 8294 1, 8295 1, 8296 1, 8297 1, 8298 1, 8299 1, 8300 1, 8301 1, 8302 1, 8303 1, 8304 1, 8305 1, 8306 1, 8307 1, 8308 1, 8309 1, 8310 1, 8311 1, 8312 1, 8313 1, 8314 1, 8315 1, 8316 1, 8317 1, 8318 1, 8319 1, 8320 1, 8321 1, 8322 1, 8323 1, 8324 1, 8325 1, 8326 1, 8327 1, 8328 1, 8329 1, 8330 1, 8331 1, 8332 1, 8333 1, 8334 1, 8335 1, 8336 1, 8337 1, 8338 1, 8339 1, 8340 1, 8341 1, 8342 1, 8343 1, 8344 1, 8345 1, 8346 1, 8347 1, 8348 1, 8349 1, 8350 1, 8351 1, 8352 1, 8353 1, 8354 1, 8355 1, 8356 1, 8357 1, 8358 1, 8359 1, 8360 1, 8361 1, 8362 1, 8363 1, 8364 1, 8365 1, 8366 1, 8367 1, 8368 1, 8369 1, 8370 1, 8371 1, 8372 1, 8373 1, 8374 1, 8375 1, 8376 1, 8377 1, 8378 1, 8379 1, 8380 1, 8381 1, 8382 1, 8383 1, 8384 1, 8385 1, 8386 1, 8387 1, 8388 1, 8389 1, 8390 1, 8391 1, 8392 1, 8393 1, 8394 1, 8395 1, 8396 1, 8397 1, 8398 1, 8399 1, 8400 1, 8401 1, 8402 1, 8403 1, 8404 1, 8405 1, 8406 1, 8407 1, 8408 1, 8409 1, 8410 1, 8411 1, 8412 1, 8413 1, 8414 1, 8415 1, 8416 1, 8417 1, 8418 1, 8419 1, 8420 1, 8421 1, 8422 1, 8423 1, 8424 1, 8425 1, 8426 1, 8427 1, 8428 1, 8429 1, 8430 1, 8431 1, 8432 1, 8433 1, 8434 1, 8435 1, 8436 1, 8437 1, 8438 1, 8439 1, 8440 1, 8441 1, 8442 1, 8443 1, 8444 1, 8445 1, 8446 1, 8447 1, 8448 1, 8449 1, 8450 1, 8451 1, 8452 1, 8453 1, 8454 1, 8455 1, 8456 1, 8457 1, 8458 1, 8459 1, 8460 1, 8461 1, 8462 1, 8463 1, 8464 1, 8465 1, 8466 1, 8467 1, 8468 1, 8469 1, 8470 1, 8471 1, 8472 1, 8473 1, 8474 1, 8475 1, 8476 1, 8477 1, 8478 1, 8479 1, 8480 1, 8481 1, 8482 1, 8483 1, 8484 1, 8485 1, 8486 1, 8487 1, 8488 1, 8489 1, 8490 1, 8491 1, 8492 1, 8493 1, 8494 1, 8495 1, 8496 1, 8497 1, 8498 1, 8499 1, 8500 1, 8501 1, 8502 1, 8503 1, 8504 1, 8505 1, 8506 1, 8507 1, 8508 1, 8509 1, 8510 1, 8511 1, 8512 1, 8513 1, 8514 1, 8515 1, 8516 1, 8517 1, 8518 1, 8519 1, 8520 1, 8521 1, 8522 1, 8523 1, 8524 1, 8525 1, 8526 1, 8527 1, 8528 1, 8529 1, 8530 1, 8531 1, 8532 1, 8533 1, 8534 1, 8535 1, 8536 1, 8537 1, 8538 1, 8539 1, 8540 1, 8541 1, 8542 1, 8543 1, 8544 1, 8545 1, 8546 1, 8547 1, 8548 1, 8549 1, 8550 1, 8551 1, 8552 1, 8553 1, 8554 1, 8555 1, 8556 1, 8557 1, 8558 1, 8559 1, 8560 1, 8561 1, 8562 1, 8563 1, 8564 1, 8565 1, 8566 1, 8567 1, 8568 1, 8569 1, 8570 1, 8571 1, 8572 1, 8573 1, 8574 1, 8575 1, 8576 1, 8577 1, 8578 1, 8579 1, 8580 1, 8581 1, 8582 1, 8583 1, 8584 1, 8585 1, 8586 1, 8587 1, 8588 1, 8589 1, 8590 1, 8591 1, 8592 1, 8593 1, 8594 1, 8595 1, 8596 1, 8597 1, 8598 1, 8599 1, 8600 1, 8601 1, 8602 1, 8603 1, 8604 1, 8605 1, 8606 1, 8607 1, 8608 1, 8609 1, 8610 1, 8611 1, 8612 1, 8613 1, 8614 1, 8615 1, 8616 1, 8617 1, 8618 1, 8619 1, 8620 1, 8621 1, 8622 1, 8623 1, 8624 1, 8625 1, 8626 1, 8627 1, 8628 1, 8629 1, 8630 1, 8631 1, 8632 1, 8633 1, 8634 1, 8635 1, 8636 1, 8637 1, 8638 1, 8639 1, 8640 1, 8641 1, 8642 1, 8643 1, 8644 1, 8645 1, 8646 1, 8647 1, 8648 1, 8649 1, 8650 1, 8651 1, 8652 1, 8653 1, 8654 1, 8655 1, 8656 1, 8657 1, 8658 1, 8659 1, 8660 1, 8661 1, 8662 1, 8663 1, 8664 1, 8665 1, 8666 1, 8667 1, 8668 1, 8669 1, 8670 1, 8671 1, 8672 1, 8673 1, 8674 1, 8675 1, 8676 1, 8677 1, 8678 1, 8679 1, 8680 1, 8681 1, 8682 1, 8683 1, 8684 1, 8685 1, 8686 1, 8687 1, 8688 1, 8689 1, 8690 1, 8691 1, 8692 1, 8693 1, 8694 1, 8695 1, 8696 1, 8697 1, 8698 1, 8699 1, 8700 1, 8701 1, 8702 1, 8703 1, 8704 1, 8705 1, 8706 1, 8707 1, 8708 1, 8709 1, 8710 1, 8711 1, 8712 1, 8713 1, 8714 1, 8715 1, 8716 1, 8717 1, 8718 1, 8719 1, 8720 1, 8721 1, 8722 1, 8723 1, 8724 1, 8725 1, 8726 1, 8727 1, 8728 1, 8729 1, 8730 1, 8731 1, 8732 1, 8733 1, 8734 1, 8735 1, 8736 1, 8737 1, 8738 1, 8739 1, 8740 1, 8741 1, 8742 1, 8743 1, 8744 1, 8745 1, 8746 1, 8747 1, 8748 1, 8749 1, 8750 1, 8751 1, 8752 1, 8753 1, 8754 1, 8755 1, 8756 1, 8757 1, 8758 1, 8759 1, 8760 1, 8761 1, 8762 1, 8763 1, 8764 1, 8765 1, 8766 1, 8767 1, 8768 1, 8769 1, 8770 1, 8771 1, 8772 1, 8773 1, 8774 1, 8775 1, 8776 1, 8777 1, 8778 1, 8779 1, 8780 1, 8781 1, 8782 1, 8783 1, 8784 1, 8785 1, 8786 1, 8787 1, 8788 1, 8789 1, 8790 1, 8791 1, 8792 1, 8793 1, 8794 1, 8795 1, 8796 1, 8797 1, 8798 1, 8799 1, 8800 1, 8801 1, 8802 1, 8803 1, 8804 1, 8805 1, 8806 1, 8807 1, 8808 1, 8809 1, 8810 1, 8811 1, 8812 1, 8813 1, 8814 1, 8815 1, 8816 1, 8817 1, 8818 1, 8819 1, 8820 1, 8821 1, 8822 1, 8823 1, 8824 1, 8825 1, 8826 1, 8827 1, 8828 1, 8829 1, 8830 1, 8831 1, 8832 1, 8833 1, 8834 1, 8835 1, 8836 1, 8837 1, 8838 1, 8839 1, 8840 1, 8841 1, 8842 1, 8843 1, 8844 1, 8845 1, 8846 1, 8847 1, 8848 1, 8849 1, 8850 1, 8851 1, 8852 1, 8853 1, 8854 1, 8855 1, 8856 1, 8857 1, 8858 1, 8859 1, 8860 1, 8861 1, 8862 1, 8863 1, 8864 1, 8865 1, 8866 1, 8867 1, 8868 1, 8869 1, 8870 1, 8871 1, 8872 1, 8873 1, 8874 1, 8875 1, 8876 1, 8877 1, 8878 1, 8879 1, 8880 1, 8881 1, 8882 1, 8883 1, 8884 1, 8885 1, 8886 1, 8887 1, 8888 1, 8889 1, 8890 1, 8891 1, 8892 1, 8893 1, 8894 1, 8895 1, 8896 1, 8897 1, 8898 1, 8899 1, 8900 1, 8901 1, 8902 1, 8903 1, 8904 1, 8905 1, 8906 1, 8907 1, 8908 1, 8909 1, 8910 1, 8911 1, 8912 1, 8913 1, 8914 1, 8915 1, 8916 1, 8917 1, 8918 1, 8919 1, 8920 1, 8921 1, 8922 1, 8923 1, 8924 1, 8925 1, 8926 1, 8927 1, 8928 1, 8929 1, 8930 1, 8931 1, 8932 1, 8933 1, 8934 1, 8935 1, 8936 1, 8937 1, 8938 1, 8939 1, 8940 1, 8941 1, 8942 1, 8943 1, 8944 1, 8945 1, 8946 1, 8947 1, 8948 1, 8949 1, 8950 1, 8951 1, 8952 1, 8953 1, 8954 1, 8955 1, 8956 1, 8957 1, 8958 1, 8959 1, 8960 1, 8961 1, 8962 1, 8963 1, 8964 1, 8965 1, 8966 1, 8967 1, 8968 1, 8969 1, 8970 1, 8971 1, 8972 1, 8973 1, 8974 1, 8975 1, 8976 1, 8977 1, 8978 1, 8979 1, 8980 1, 8981 1, 8982 1, 8983 1, 8984 1, 8985 1, 8986 1, 8987 1, 8988 1, 8989 1, 8990 1, 8991 1, 8992 1, 8993 1, 8994 1, 8995 1, 8996 1, 8997 1, 8998 1, 8999 1, 9000 1, 9001 1, 9002 1, 9003 1, 9004 1, 9005 1, 9006 1, 9007 1, 9008 1, 9009 1, 9010 1, 9011 1, 9012 1, 9013 1, 9014 1, 9015 1, 9016 1, 9017 1, 9018 1, 9019 1, 9020 1, 9021 1, 9022 1, 9023 1, 9024 1, 9025 1, 9026 1, 9027 1, 9028 1, 9029 1, 9030 1, 9031 1, 9032 1, 9033 1, 9034 1, 9035 1, 9036 1, 9037 1, 9038 1, 9039 1, 9040 1, 9041 1, 9042 1, 9043 1, 9044 1, 9045 1, 9046 1, 9047 1, 9048 1, 9049 1, 9050 1, 9051 1, 9052 1, 9053 1, 9054 1, 9055 1, 9056 1, 9057 1, 9058 1, 9059 1, 9060 1, 9061 1, 9062 1, 9063 1, 9064 1, 9065 1, 9066 1, 9067 1, 9068 1, 9069 1, 9070 1, 9071 1, 9072 1, 9073 1, 9074 1, 9075 1, 9076 1, 9077 1, 9078 1, 9079 1, 9080 1, 9081 1, 9082 1, 9083 1, 9084 1, 9085 1, 9086 1, 9087 1, 9088 1, 9089 1, 9090 1, 9091 1, 9092 1, 9093 1, 9094 1, 9095 1, 9096 1, 9097 1, 9098 1, 9099 1, 9100 1, 9101 1, 9102 1, 9103 1, 9104 1, 9105 1, 9106 1, 9107 1, 9108 1, 9109 1, 9110 1, 9111 1, 9112 1, 9113 1, 9114 1, 9115 1, 9116 1, 9117 1, 9118 1, 9119 1, 9120 1, 9121 1, 9122 1, 9123 1, 9124 1, 9125 1, 9126 1, 9127 1, 9128 1, 9129 1, 9130 1, 9131 1, 9132 1, 9133 1, 9134 1, 9135 1, 9136 1, 9137 1, 9138 1, 9139 1, 9140 1, 9141 1, 9142 1, 9143 1, 9144 1, 9145 1, 9146 1, 9147 1, 9148 1, 9149 1, 9150 1, 9151 1, 9152 1, 9153 1, 9154 1, 9155 1, 9156 1, 9157 1, 9158 1, 9159 1, 9160 1, 9161 1, 9162 1, 9163 1, 9164 1, 9165 1, 9166 1, 9167 1, 9168 1, 9169 1, 9170 1, 9171 1, 9172 1, 9173 1, 9174 1, 9175 1, 9176 1, 9177 1, 9178 1, 9179 1, 9180 1, 9181 1, 9182 1, 9183 1, 9184 1, 9185 1, 9186 1, 9187 1, 9188 1, 9189 1, 9190 1, 9191 1, 9192 1, 9193 1, 9194 1, 9195 1, 9196 1, 9197 1, 9198 1, 9199 1, 9200 1, 9201 1, 9202 1, 9203 1, 9204 1, 9205 1, 9206 1, 9207 1, 9208 1, 9209 1, 9210 1, 9211 1, 9212 1, 9213 1, 9214 1, 9215 1, 9216 1, 9217 1, 9218 1, 9219 1, 9220 1, 9221 1, 9222 1, 9223 1, 9224 1, 9225 1, 9226 1, 9227 1, 9228 1, 9229 1, 9230 1, 9231 1, 9232 1, 9233 1, 9234 1, 9235 1, 9236 1, 9237 1, 9238 1, 9239 1, 9240 1, 9241 1, 9242 1, 9243 1, 9244 1, 9245 1, 9246 1, 9247 1, 9248 1, 9249 1, 9250 1, 9251 1, 9252 1, 9253 1, 9254 1, 9255 1, 9256 1, 9257 1, 9258 1, 9259 1, 9260 1, 9261 1, 9262 1, 9263 1, 9264 1, 9265 1, 9266 1, 9267 1, 9268 1, 9269 1, 9270 1, 9271 1, 9272 1, 9273 1, 9274 1, 9275 1, 9276 1, 9277 1, 9278 1, 9279 1, 9280 1, 9281 1, 9282 1, 9283 1, 9284 1, 9285 1, 9286 1, 9287 1, 9288 1, 9289 1, 9290 1, 9291 1, 9292 1, 9293 1, 9294 1, 9295 1, 9296 1, 9297 1, 9298 1, 9299 1, 9300 1, 9301 1, 9302 1, 9303 1, 9304 1, 9305 1, 9306 1, 9307 1, 9308 1, 9309 1, 9310 1, 9311 1, 9312 1, 9313 1, 9314 1, 9315 1, 9316 1, 9317 1, 9318 1, 9319 1, 9320 1, 9321 1, 9322 1, 9323 1, 9324 1, 9325 1, 9326 1, 9327 1, 9328 1, 9329 1, 9330 1, 9331 1, 9332 1, 9333 1, 9334 1, 9335 1, 9336 1, 9337 1, 9338 1, 9339 1, 9340 1, 9341 1, 9342 1, 9343 1, 9344 1, 9345 1, 9346 1, 9347 1, 9348 1, 9349 1, 9350 1, 9351 1, 9352 1, 9353 1, 9354 1, 9355 1, 9356 ]; 9357 let pub_key = MlDsaVerKey::<MlDsa44>::decode(&[1u8; 1312].into()) 9358 .to_public_key_der() 9359 .unwrap(); 9360 let att_obj_len = att_obj.len(); 9361 let b64_cdata_json = base64url_nopad::encode(c_data_json.as_bytes()); 9362 let b64_adata = base64url_nopad::encode(&att_obj[att_obj_len - 1393..]); 9363 let b64_key = base64url_nopad::encode(pub_key.as_bytes()); 9364 let b64_aobj = base64url_nopad::encode(att_obj.as_slice()); 9365 // Base case is valid. 9366 assert!( 9367 serde_json::from_str::<Registration>( 9368 serde_json::json!({ 9369 "id": "AAAAAAAAAAAAAAAAAAAAAA", 9370 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 9371 "response": { 9372 "clientDataJSON": b64_cdata_json, 9373 "authenticatorData": b64_adata, 9374 "transports": [], 9375 "publicKey": b64_key, 9376 "publicKeyAlgorithm": -48i8, 9377 "attestationObject": b64_aobj, 9378 }, 9379 "clientExtensionResults": {}, 9380 "type": "public-key" 9381 }) 9382 .to_string() 9383 .as_str() 9384 ) 9385 .is_ok_and( 9386 |reg| reg.response.client_data_json == c_data_json.as_bytes() 9387 && reg.response.attestation_object_and_c_data_hash[..att_obj_len] == att_obj 9388 && reg.response.attestation_object_and_c_data_hash[att_obj_len..] 9389 == *Sha256::digest(c_data_json.as_bytes()) 9390 && reg.response.transports.is_empty() 9391 && matches!(reg.authenticator_attachment, AuthenticatorAttachment::None) 9392 && reg.client_extension_results.cred_props.is_none() 9393 && reg.client_extension_results.prf.is_none() 9394 ) 9395 ); 9396 // `publicKeyAlgorithm` mismatch. 9397 let mut err = Error::invalid_value( 9398 Unexpected::Other(format!("{:?}", CoseAlgorithmIdentifier::Eddsa).as_str()), 9399 &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {:?}", CoseAlgorithmIdentifier::Mldsa44).as_str() 9400 ) 9401 .to_string().into_bytes(); 9402 assert_eq!( 9403 serde_json::from_str::<Registration>( 9404 serde_json::json!({ 9405 "id": "AAAAAAAAAAAAAAAAAAAAAA", 9406 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 9407 "response": { 9408 "clientDataJSON": b64_cdata_json, 9409 "authenticatorData": b64_adata, 9410 "transports": [], 9411 "publicKey": b64_key, 9412 "publicKeyAlgorithm": -8i8, 9413 "attestationObject": b64_aobj, 9414 }, 9415 "clientExtensionResults": {}, 9416 "type": "public-key" 9417 }) 9418 .to_string() 9419 .as_str() 9420 ) 9421 .unwrap_err() 9422 .to_string() 9423 .into_bytes() 9424 .get(..err.len()), 9425 Some(err.as_slice()) 9426 ); 9427 // Missing `publicKeyAlgorithm`. 9428 err = Error::missing_field("publicKeyAlgorithm") 9429 .to_string() 9430 .into_bytes(); 9431 assert_eq!( 9432 serde_json::from_str::<Registration>( 9433 serde_json::json!({ 9434 "id": "AAAAAAAAAAAAAAAAAAAAAA", 9435 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 9436 "response": { 9437 "clientDataJSON": b64_cdata_json, 9438 "authenticatorData": b64_adata, 9439 "transports": [], 9440 "publicKey": b64_key, 9441 "attestationObject": b64_aobj, 9442 }, 9443 "clientExtensionResults": {}, 9444 "type": "public-key" 9445 }) 9446 .to_string() 9447 .as_str() 9448 ) 9449 .unwrap_err() 9450 .to_string() 9451 .into_bytes() 9452 .get(..err.len()), 9453 Some(err.as_slice()) 9454 ); 9455 // `null` `publicKeyAlgorithm`. 9456 err = Error::invalid_type(Unexpected::Other("null"), &"publicKeyAlgorithm") 9457 .to_string() 9458 .into_bytes(); 9459 assert_eq!( 9460 serde_json::from_str::<Registration>( 9461 serde_json::json!({ 9462 "id": "AAAAAAAAAAAAAAAAAAAAAA", 9463 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 9464 "response": { 9465 "clientDataJSON": b64_cdata_json, 9466 "authenticatorData": b64_adata, 9467 "transports": [], 9468 "publicKey": b64_key, 9469 "publicKeyAlgorithm": null, 9470 "attestationObject": b64_aobj, 9471 }, 9472 "clientExtensionResults": {}, 9473 "type": "public-key" 9474 }) 9475 .to_string() 9476 .as_str() 9477 ) 9478 .unwrap_err() 9479 .to_string() 9480 .into_bytes() 9481 .get(..err.len()), 9482 Some(err.as_slice()) 9483 ); 9484 // `publicKey` mismatch. 9485 let bad_pub_key = MlDsaVerKey::<MlDsa44>::decode(&[2; 1312].into()); 9486 err = Error::invalid_value( 9487 Unexpected::Bytes([0; 32].as_slice()), 9488 &format!( 9489 "DER-encoded public key to match the public key within the attestation object: MlDsa44(MlDsa44PubKey({:?}))", 9490 &[1u8; 1312] 9491 ) 9492 .as_str(), 9493 ) 9494 .to_string().into_bytes(); 9495 assert_eq!(serde_json::from_str::<Registration>( 9496 serde_json::json!({ 9497 "id": "AAAAAAAAAAAAAAAAAAAAAA", 9498 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 9499 "response": { 9500 "clientDataJSON": b64_cdata_json, 9501 "authenticatorData": b64_adata, 9502 "transports": [], 9503 "publicKey": base64url_nopad::encode(bad_pub_key.to_public_key_der().unwrap().as_bytes()), 9504 "publicKeyAlgorithm": -48i8, 9505 "attestationObject": b64_aobj, 9506 }, 9507 "clientExtensionResults": {}, 9508 "type": "public-key" 9509 }) 9510 .to_string() 9511 .as_str() 9512 ) 9513 .unwrap_err().to_string().into_bytes().get(..err.len()), 9514 Some(err.as_slice()) 9515 ); 9516 // Missing `publicKey` is allowed when not using EdDSA, ES256, or RS256. 9517 assert!( 9518 serde_json::from_str::<Registration>( 9519 serde_json::json!({ 9520 "id": "AAAAAAAAAAAAAAAAAAAAAA", 9521 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 9522 "response": { 9523 "clientDataJSON": b64_cdata_json, 9524 "authenticatorData": b64_adata, 9525 "transports": [], 9526 "publicKeyAlgorithm": -48i8, 9527 "attestationObject": b64_aobj, 9528 }, 9529 "clientExtensionResults": {}, 9530 "type": "public-key" 9531 }) 9532 .to_string() 9533 .as_str() 9534 ) 9535 .is_ok() 9536 ); 9537 // `publicKeyAlgorithm` mismatch when `publicKey` does not exist. 9538 err = Error::invalid_value( 9539 Unexpected::Other(format!("{:?}", CoseAlgorithmIdentifier::Es256).as_str()), 9540 &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {:?}", CoseAlgorithmIdentifier::Mldsa44).as_str() 9541 ) 9542 .to_string().into_bytes(); 9543 assert_eq!( 9544 serde_json::from_str::<Registration>( 9545 serde_json::json!({ 9546 "id": "AAAAAAAAAAAAAAAAAAAAAA", 9547 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 9548 "response": { 9549 "clientDataJSON": b64_cdata_json, 9550 "authenticatorData": b64_adata, 9551 "transports": [], 9552 "publicKeyAlgorithm": -7i8, 9553 "attestationObject": b64_aobj, 9554 }, 9555 "clientExtensionResults": {}, 9556 "type": "public-key" 9557 }) 9558 .to_string() 9559 .as_str() 9560 ) 9561 .unwrap_err() 9562 .to_string() 9563 .into_bytes() 9564 .get(..err.len()), 9565 Some(err.as_slice()) 9566 ); 9567 // `null` `publicKey` is allowed when not using EdDSA, ES256, or RS256. 9568 assert!( 9569 serde_json::from_str::<Registration>( 9570 serde_json::json!({ 9571 "id": "AAAAAAAAAAAAAAAAAAAAAA", 9572 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 9573 "response": { 9574 "clientDataJSON": b64_cdata_json, 9575 "authenticatorData": b64_adata, 9576 "transports": [], 9577 "publicKey": null, 9578 "publicKeyAlgorithm": -48i8, 9579 "attestationObject": b64_aobj, 9580 }, 9581 "clientExtensionResults": {}, 9582 "type": "public-key" 9583 }) 9584 .to_string() 9585 .as_str() 9586 ) 9587 .is_ok() 9588 ); 9589 // `publicKeyAlgorithm` mismatch when `publicKey` is null. 9590 err = Error::invalid_value( 9591 Unexpected::Other(format!("{:?}", CoseAlgorithmIdentifier::Es256).as_str()), 9592 &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {:?}", CoseAlgorithmIdentifier::Mldsa44).as_str() 9593 ) 9594 .to_string().into_bytes(); 9595 assert_eq!( 9596 serde_json::from_str::<Registration>( 9597 serde_json::json!({ 9598 "id": "AAAAAAAAAAAAAAAAAAAAAA", 9599 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 9600 "response": { 9601 "clientDataJSON": b64_cdata_json, 9602 "authenticatorData": b64_adata, 9603 "transports": [], 9604 "publicKey": null, 9605 "publicKeyAlgorithm": -7i8, 9606 "attestationObject": b64_aobj, 9607 }, 9608 "clientExtensionResults": {}, 9609 "type": "public-key" 9610 }) 9611 .to_string() 9612 .as_str() 9613 ) 9614 .unwrap_err() 9615 .to_string() 9616 .into_bytes() 9617 .get(..err.len()), 9618 Some(err.as_slice()) 9619 ); 9620 } 9621 #[expect(clippy::unwrap_used, reason = "OK in tests")] 9622 #[expect(clippy::indexing_slicing, reason = "comments justify correctness")] 9623 #[expect(clippy::too_many_lines, reason = "a lot to test")] 9624 #[test] 9625 fn es256_registration_deserialize_data_mismatch() { 9626 let c_data_json = serde_json::json!({}).to_string(); 9627 let mut att_obj: [u8; 178] = [ 9628 cbor::MAP_3, 9629 cbor::TEXT_3, 9630 b'f', 9631 b'm', 9632 b't', 9633 cbor::TEXT_4, 9634 b'n', 9635 b'o', 9636 b'n', 9637 b'e', 9638 cbor::TEXT_7, 9639 b'a', 9640 b't', 9641 b't', 9642 b'S', 9643 b't', 9644 b'm', 9645 b't', 9646 cbor::MAP_0, 9647 cbor::TEXT_8, 9648 b'a', 9649 b'u', 9650 b't', 9651 b'h', 9652 b'D', 9653 b'a', 9654 b't', 9655 b'a', 9656 cbor::BYTES_INFO_24, 9657 148, 9658 // `rpIdHash`. 9659 0, 9660 0, 9661 0, 9662 0, 9663 0, 9664 0, 9665 0, 9666 0, 9667 0, 9668 0, 9669 0, 9670 0, 9671 0, 9672 0, 9673 0, 9674 0, 9675 0, 9676 0, 9677 0, 9678 0, 9679 0, 9680 0, 9681 0, 9682 0, 9683 0, 9684 0, 9685 0, 9686 0, 9687 0, 9688 0, 9689 0, 9690 0, 9691 // `flags`. 9692 0b0100_0101, 9693 // `signCount`. 9694 0, 9695 0, 9696 0, 9697 0, 9698 // `aaguid`. 9699 0, 9700 0, 9701 0, 9702 0, 9703 0, 9704 0, 9705 0, 9706 0, 9707 0, 9708 0, 9709 0, 9710 0, 9711 0, 9712 0, 9713 0, 9714 0, 9715 // `credentialIdLength`. 9716 0, 9717 16, 9718 // `credentialId`. 9719 0, 9720 0, 9721 0, 9722 0, 9723 0, 9724 0, 9725 0, 9726 0, 9727 0, 9728 0, 9729 0, 9730 0, 9731 0, 9732 0, 9733 0, 9734 0, 9735 // P-256 COSE key. 9736 cbor::MAP_5, 9737 KTY, 9738 EC2, 9739 ALG, 9740 ES256, 9741 // `crv`. 9742 cbor::NEG_ONE, 9743 // `P-256`. 9744 cbor::ONE, 9745 // `x`. 9746 cbor::NEG_TWO, 9747 cbor::BYTES_INFO_24, 9748 32, 9749 // x-coordinate. This will be overwritten later. 9750 0, 9751 0, 9752 0, 9753 0, 9754 0, 9755 0, 9756 0, 9757 0, 9758 0, 9759 0, 9760 0, 9761 0, 9762 0, 9763 0, 9764 0, 9765 0, 9766 0, 9767 0, 9768 0, 9769 0, 9770 0, 9771 0, 9772 0, 9773 0, 9774 0, 9775 0, 9776 0, 9777 0, 9778 0, 9779 0, 9780 0, 9781 0, 9782 // `y`. 9783 cbor::NEG_THREE, 9784 cbor::BYTES_INFO_24, 9785 32, 9786 // y-coordinate. This will be overwritten later. 9787 0, 9788 0, 9789 0, 9790 0, 9791 0, 9792 0, 9793 0, 9794 0, 9795 0, 9796 0, 9797 0, 9798 0, 9799 0, 9800 0, 9801 0, 9802 0, 9803 0, 9804 0, 9805 0, 9806 0, 9807 0, 9808 0, 9809 0, 9810 0, 9811 0, 9812 0, 9813 0, 9814 0, 9815 0, 9816 0, 9817 0, 9818 0, 9819 ]; 9820 let key = P256Key::from_bytes( 9821 &[ 9822 137, 133, 36, 206, 163, 47, 255, 5, 76, 144, 163, 141, 40, 109, 108, 240, 246, 115, 9823 178, 237, 169, 68, 6, 129, 92, 21, 238, 127, 55, 158, 207, 95, 9824 ] 9825 .into(), 9826 ) 9827 .unwrap() 9828 .public_key(); 9829 let enc_key = key.to_sec1_point(false); 9830 let pub_key = key.to_public_key_der().unwrap(); 9831 let att_obj_len = att_obj.len(); 9832 let x_start = att_obj_len - 67; 9833 let y_meta_start = x_start + 32; 9834 let y_start = y_meta_start + 3; 9835 att_obj[x_start..y_meta_start].copy_from_slice(enc_key.x().unwrap()); 9836 att_obj[y_start..].copy_from_slice(enc_key.y().unwrap()); 9837 let b64_cdata_json = base64url_nopad::encode(c_data_json.as_bytes()); 9838 let b64_adata = base64url_nopad::encode(&att_obj[att_obj.len() - 148..]); 9839 let b64_key = base64url_nopad::encode(pub_key.as_bytes()); 9840 let b64_aobj = base64url_nopad::encode(att_obj.as_slice()); 9841 // Base case is valid. 9842 assert!( 9843 serde_json::from_str::<Registration>( 9844 serde_json::json!({ 9845 "id": "AAAAAAAAAAAAAAAAAAAAAA", 9846 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 9847 "response": { 9848 "clientDataJSON": b64_cdata_json, 9849 "authenticatorData": b64_adata, 9850 "transports": [], 9851 "publicKey": b64_key, 9852 "publicKeyAlgorithm": -7i8, 9853 "attestationObject": b64_aobj, 9854 }, 9855 "clientExtensionResults": {}, 9856 "type": "public-key" 9857 }) 9858 .to_string() 9859 .as_str() 9860 ) 9861 .is_ok_and( 9862 |reg| reg.response.client_data_json == c_data_json.as_bytes() 9863 && reg.response.attestation_object_and_c_data_hash[..att_obj.len()] == att_obj 9864 && reg.response.attestation_object_and_c_data_hash[att_obj.len()..] 9865 == *Sha256::digest(c_data_json.as_bytes()) 9866 && reg.response.transports.is_empty() 9867 && matches!(reg.authenticator_attachment, AuthenticatorAttachment::None) 9868 && reg.client_extension_results.cred_props.is_none() 9869 && reg.client_extension_results.prf.is_none() 9870 ) 9871 ); 9872 // `publicKeyAlgorithm` mismatch. 9873 let mut err = Error::invalid_value( 9874 Unexpected::Other(format!("{:?}", CoseAlgorithmIdentifier::Eddsa).as_str()), 9875 &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {:?}", CoseAlgorithmIdentifier::Es256).as_str() 9876 ) 9877 .to_string().into_bytes(); 9878 assert_eq!( 9879 serde_json::from_str::<Registration>( 9880 serde_json::json!({ 9881 "id": "AAAAAAAAAAAAAAAAAAAAAA", 9882 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 9883 "response": { 9884 "clientDataJSON": b64_cdata_json, 9885 "authenticatorData": b64_adata, 9886 "transports": [], 9887 "publicKey": b64_key, 9888 "publicKeyAlgorithm": -8i8, 9889 "attestationObject": b64_aobj, 9890 }, 9891 "clientExtensionResults": {}, 9892 "type": "public-key" 9893 }) 9894 .to_string() 9895 .as_str() 9896 ) 9897 .unwrap_err() 9898 .to_string() 9899 .into_bytes() 9900 .get(..err.len()), 9901 Some(err.as_slice()) 9902 ); 9903 // Missing `publicKeyAlgorithm`. 9904 err = Error::missing_field("publicKeyAlgorithm") 9905 .to_string() 9906 .into_bytes(); 9907 assert_eq!( 9908 serde_json::from_str::<Registration>( 9909 serde_json::json!({ 9910 "id": "AAAAAAAAAAAAAAAAAAAAAA", 9911 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 9912 "response": { 9913 "clientDataJSON": b64_cdata_json, 9914 "authenticatorData": b64_adata, 9915 "transports": [], 9916 "publicKey": b64_key, 9917 "attestationObject": b64_aobj, 9918 }, 9919 "clientExtensionResults": {}, 9920 "type": "public-key" 9921 }) 9922 .to_string() 9923 .as_str() 9924 ) 9925 .unwrap_err() 9926 .to_string() 9927 .into_bytes() 9928 .get(..err.len()), 9929 Some(err.as_slice()) 9930 ); 9931 // `null` `publicKeyAlgorithm`. 9932 err = Error::invalid_type(Unexpected::Other("null"), &"publicKeyAlgorithm") 9933 .to_string() 9934 .into_bytes(); 9935 assert_eq!( 9936 serde_json::from_str::<Registration>( 9937 serde_json::json!({ 9938 "id": "AAAAAAAAAAAAAAAAAAAAAA", 9939 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 9940 "response": { 9941 "clientDataJSON": b64_cdata_json, 9942 "authenticatorData": b64_adata, 9943 "transports": [], 9944 "publicKey": b64_key, 9945 "publicKeyAlgorithm": null, 9946 "attestationObject": b64_aobj, 9947 }, 9948 "clientExtensionResults": {}, 9949 "type": "public-key" 9950 }) 9951 .to_string() 9952 .as_str() 9953 ) 9954 .unwrap_err() 9955 .to_string() 9956 .into_bytes() 9957 .get(..err.len()), 9958 Some(err.as_slice()) 9959 ); 9960 // `publicKey` mismatch. 9961 let bad_pub_key = P256PubKey::from_sec1_point(&P256Pt::from_affine_coordinates( 9962 &[ 9963 66, 71, 188, 41, 125, 2, 226, 44, 148, 62, 63, 190, 172, 64, 33, 214, 6, 37, 148, 23, 9964 240, 235, 203, 84, 112, 219, 232, 197, 54, 182, 17, 235, 9965 ] 9966 .into(), 9967 &[ 9968 22, 172, 123, 13, 170, 242, 217, 248, 193, 209, 206, 163, 92, 4, 162, 168, 113, 63, 2, 9969 117, 16, 223, 239, 196, 109, 179, 10, 130, 43, 213, 205, 92, 9970 ] 9971 .into(), 9972 false, 9973 )) 9974 .unwrap(); 9975 err = Error::invalid_value( 9976 Unexpected::Bytes([0; 32].as_slice()), 9977 &format!( 9978 "DER-encoded public key to match the public key within the attestation object: P256(UncompressedP256PubKey({:?}, {:?}))", 9979 &att_obj[x_start..y_meta_start], 9980 &att_obj[y_start..], 9981 ) 9982 .as_str(), 9983 ) 9984 .to_string().into_bytes(); 9985 assert_eq!(serde_json::from_str::<Registration>( 9986 serde_json::json!({ 9987 "id": "AAAAAAAAAAAAAAAAAAAAAA", 9988 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 9989 "response": { 9990 "clientDataJSON": b64_cdata_json, 9991 "authenticatorData": b64_adata, 9992 "transports": [], 9993 "publicKey": base64url_nopad::encode(bad_pub_key.to_public_key_der().unwrap().as_bytes()), 9994 "publicKeyAlgorithm": -7i8, 9995 "attestationObject": b64_aobj, 9996 }, 9997 "clientExtensionResults": {}, 9998 "type": "public-key" 9999 }) 10000 .to_string() 10001 .as_str() 10002 ) 10003 .unwrap_err().to_string().into_bytes().get(..err.len()), 10004 Some(err.as_slice()) 10005 ); 10006 // Missing `publicKey` when using EdDSA, ES256, or RS256. 10007 err = Error::missing_field("publicKey").to_string().into_bytes(); 10008 assert_eq!( 10009 serde_json::from_str::<Registration>( 10010 serde_json::json!({ 10011 "id": "AAAAAAAAAAAAAAAAAAAAAA", 10012 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 10013 "response": { 10014 "clientDataJSON": b64_cdata_json, 10015 "authenticatorData": b64_adata, 10016 "transports": [], 10017 "publicKeyAlgorithm": -7i8, 10018 "attestationObject": b64_aobj, 10019 }, 10020 "clientExtensionResults": {}, 10021 "type": "public-key" 10022 }) 10023 .to_string() 10024 .as_str() 10025 ) 10026 .unwrap_err() 10027 .to_string() 10028 .into_bytes() 10029 .get(..err.len()), 10030 Some(err.as_slice()) 10031 ); 10032 // `null` `publicKey` when using EdDSA, ES256, or RS256. 10033 err = Error::invalid_type(Unexpected::Other("null"), &"publicKey") 10034 .to_string() 10035 .into_bytes(); 10036 assert_eq!( 10037 serde_json::from_str::<Registration>( 10038 serde_json::json!({ 10039 "id": "AAAAAAAAAAAAAAAAAAAAAA", 10040 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 10041 "response": { 10042 "clientDataJSON": b64_cdata_json, 10043 "authenticatorData": b64_adata, 10044 "transports": [], 10045 "publicKey": null, 10046 "publicKeyAlgorithm": -7i8, 10047 "attestationObject": b64_aobj, 10048 }, 10049 "clientExtensionResults": {}, 10050 "type": "public-key" 10051 }) 10052 .to_string() 10053 .as_str() 10054 ) 10055 .unwrap_err() 10056 .to_string() 10057 .into_bytes() 10058 .get(..err.len()), 10059 Some(err.as_slice()) 10060 ); 10061 } 10062 #[expect( 10063 clippy::assertions_on_result_states, 10064 clippy::unwrap_used, 10065 reason = "OK in tests" 10066 )] 10067 #[expect(clippy::indexing_slicing, reason = "comments justify correctness")] 10068 #[expect(clippy::too_many_lines, reason = "a lot to test")] 10069 #[test] 10070 fn es384_registration_deserialize_data_mismatch() { 10071 let c_data_json = serde_json::json!({}).to_string(); 10072 let mut att_obj: [u8; 211] = [ 10073 cbor::MAP_3, 10074 cbor::TEXT_3, 10075 b'f', 10076 b'm', 10077 b't', 10078 cbor::TEXT_4, 10079 b'n', 10080 b'o', 10081 b'n', 10082 b'e', 10083 cbor::TEXT_7, 10084 b'a', 10085 b't', 10086 b't', 10087 b'S', 10088 b't', 10089 b'm', 10090 b't', 10091 cbor::MAP_0, 10092 cbor::TEXT_8, 10093 b'a', 10094 b'u', 10095 b't', 10096 b'h', 10097 b'D', 10098 b'a', 10099 b't', 10100 b'a', 10101 cbor::BYTES_INFO_24, 10102 181, 10103 // `rpIdHash`. 10104 0, 10105 0, 10106 0, 10107 0, 10108 0, 10109 0, 10110 0, 10111 0, 10112 0, 10113 0, 10114 0, 10115 0, 10116 0, 10117 0, 10118 0, 10119 0, 10120 0, 10121 0, 10122 0, 10123 0, 10124 0, 10125 0, 10126 0, 10127 0, 10128 0, 10129 0, 10130 0, 10131 0, 10132 0, 10133 0, 10134 0, 10135 0, 10136 // `flags`. 10137 0b0100_0101, 10138 // `signCount`. 10139 0, 10140 0, 10141 0, 10142 0, 10143 // `aaguid`. 10144 0, 10145 0, 10146 0, 10147 0, 10148 0, 10149 0, 10150 0, 10151 0, 10152 0, 10153 0, 10154 0, 10155 0, 10156 0, 10157 0, 10158 0, 10159 0, 10160 // `credentialIdLength`. 10161 0, 10162 16, 10163 // `credentialId`. 10164 0, 10165 0, 10166 0, 10167 0, 10168 0, 10169 0, 10170 0, 10171 0, 10172 0, 10173 0, 10174 0, 10175 0, 10176 0, 10177 0, 10178 0, 10179 0, 10180 // P-384 COSE key. 10181 cbor::MAP_5, 10182 KTY, 10183 EC2, 10184 ALG, 10185 cbor::NEG_INFO_24, 10186 ES384, 10187 // `crv`. 10188 cbor::NEG_ONE, 10189 // `P-384`. 10190 cbor::TWO, 10191 // `x`. 10192 cbor::NEG_TWO, 10193 cbor::BYTES_INFO_24, 10194 48, 10195 // x-coordinate. This will be overwritten later. 10196 0, 10197 0, 10198 0, 10199 0, 10200 0, 10201 0, 10202 0, 10203 0, 10204 0, 10205 0, 10206 0, 10207 0, 10208 0, 10209 0, 10210 0, 10211 0, 10212 0, 10213 0, 10214 0, 10215 0, 10216 0, 10217 0, 10218 0, 10219 0, 10220 0, 10221 0, 10222 0, 10223 0, 10224 0, 10225 0, 10226 0, 10227 0, 10228 0, 10229 0, 10230 0, 10231 0, 10232 0, 10233 0, 10234 0, 10235 0, 10236 0, 10237 0, 10238 0, 10239 0, 10240 0, 10241 0, 10242 0, 10243 0, 10244 // `y`. 10245 cbor::NEG_THREE, 10246 cbor::BYTES_INFO_24, 10247 48, 10248 // y-coordinate. This will be overwritten later. 10249 0, 10250 0, 10251 0, 10252 0, 10253 0, 10254 0, 10255 0, 10256 0, 10257 0, 10258 0, 10259 0, 10260 0, 10261 0, 10262 0, 10263 0, 10264 0, 10265 0, 10266 0, 10267 0, 10268 0, 10269 0, 10270 0, 10271 0, 10272 0, 10273 0, 10274 0, 10275 0, 10276 0, 10277 0, 10278 0, 10279 0, 10280 0, 10281 0, 10282 0, 10283 0, 10284 0, 10285 0, 10286 0, 10287 0, 10288 0, 10289 0, 10290 0, 10291 0, 10292 0, 10293 0, 10294 0, 10295 0, 10296 0, 10297 ]; 10298 let key = P384Key::from_bytes( 10299 &[ 10300 158, 99, 156, 49, 190, 211, 85, 167, 28, 2, 80, 57, 31, 22, 17, 38, 85, 78, 232, 42, 10301 45, 199, 154, 243, 136, 251, 84, 34, 5, 120, 208, 91, 61, 248, 64, 144, 87, 1, 32, 86, 10302 220, 68, 182, 11, 105, 223, 75, 70, 10303 ] 10304 .into(), 10305 ) 10306 .unwrap() 10307 .public_key(); 10308 let enc_key = key.to_sec1_point(false); 10309 let pub_key = key.to_public_key_der().unwrap(); 10310 let att_obj_len = att_obj.len(); 10311 let x_start = att_obj_len - 99; 10312 let y_meta_start = x_start + 48; 10313 let y_start = y_meta_start + 3; 10314 att_obj[x_start..y_meta_start].copy_from_slice(enc_key.x().unwrap()); 10315 att_obj[y_start..].copy_from_slice(enc_key.y().unwrap()); 10316 let b64_cdata_json = base64url_nopad::encode(c_data_json.as_bytes()); 10317 let b64_adata = base64url_nopad::encode(&att_obj[att_obj_len - 181..]); 10318 let b64_key = base64url_nopad::encode(pub_key.as_bytes()); 10319 let b64_aobj = base64url_nopad::encode(att_obj.as_slice()); 10320 // Base case is valid. 10321 assert!( 10322 serde_json::from_str::<Registration>( 10323 serde_json::json!({ 10324 "id": "AAAAAAAAAAAAAAAAAAAAAA", 10325 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 10326 "response": { 10327 "clientDataJSON": b64_cdata_json, 10328 "authenticatorData": b64_adata, 10329 "transports": [], 10330 "publicKey": b64_key, 10331 "publicKeyAlgorithm": -35i8, 10332 "attestationObject": b64_aobj, 10333 }, 10334 "clientExtensionResults": {}, 10335 "type": "public-key" 10336 }) 10337 .to_string() 10338 .as_str() 10339 ) 10340 .is_ok_and( 10341 |reg| reg.response.client_data_json == c_data_json.as_bytes() 10342 && reg.response.attestation_object_and_c_data_hash[..att_obj.len()] == att_obj 10343 && reg.response.attestation_object_and_c_data_hash[att_obj.len()..] 10344 == *Sha256::digest(c_data_json.as_bytes()) 10345 && reg.response.transports.is_empty() 10346 && matches!(reg.authenticator_attachment, AuthenticatorAttachment::None) 10347 && reg.client_extension_results.cred_props.is_none() 10348 && reg.client_extension_results.prf.is_none() 10349 ) 10350 ); 10351 // `publicKeyAlgorithm` mismatch. 10352 let mut err = Error::invalid_value( 10353 Unexpected::Other(format!("{:?}", CoseAlgorithmIdentifier::Es256).as_str()), 10354 &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {:?}", CoseAlgorithmIdentifier::Es384).as_str() 10355 ) 10356 .to_string().into_bytes(); 10357 assert_eq!( 10358 serde_json::from_str::<Registration>( 10359 serde_json::json!({ 10360 "id": "AAAAAAAAAAAAAAAAAAAAAA", 10361 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 10362 "response": { 10363 "clientDataJSON": b64_cdata_json, 10364 "authenticatorData": b64_adata, 10365 "transports": [], 10366 "publicKey": b64_key, 10367 "publicKeyAlgorithm": -7i8, 10368 "attestationObject": b64_aobj, 10369 }, 10370 "clientExtensionResults": {}, 10371 "type": "public-key" 10372 }) 10373 .to_string() 10374 .as_str() 10375 ) 10376 .unwrap_err() 10377 .to_string() 10378 .into_bytes() 10379 .get(..err.len()), 10380 Some(err.as_slice()) 10381 ); 10382 // Missing `publicKeyAlgorithm`. 10383 err = Error::missing_field("publicKeyAlgorithm") 10384 .to_string() 10385 .into_bytes(); 10386 assert_eq!( 10387 serde_json::from_str::<Registration>( 10388 serde_json::json!({ 10389 "id": "AAAAAAAAAAAAAAAAAAAAAA", 10390 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 10391 "response": { 10392 "clientDataJSON": b64_cdata_json, 10393 "authenticatorData": b64_adata, 10394 "transports": [], 10395 "publicKey": b64_key, 10396 "attestationObject": b64_aobj, 10397 }, 10398 "clientExtensionResults": {}, 10399 "type": "public-key" 10400 }) 10401 .to_string() 10402 .as_str() 10403 ) 10404 .unwrap_err() 10405 .to_string() 10406 .into_bytes() 10407 .get(..err.len()), 10408 Some(err.as_slice()) 10409 ); 10410 // `null` `publicKeyAlgorithm`. 10411 err = Error::invalid_type(Unexpected::Other("null"), &"publicKeyAlgorithm") 10412 .to_string() 10413 .into_bytes(); 10414 assert_eq!( 10415 serde_json::from_str::<Registration>( 10416 serde_json::json!({ 10417 "id": "AAAAAAAAAAAAAAAAAAAAAA", 10418 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 10419 "response": { 10420 "clientDataJSON": b64_cdata_json, 10421 "authenticatorData": b64_adata, 10422 "transports": [], 10423 "publicKey": b64_key, 10424 "publicKeyAlgorithm": null, 10425 "attestationObject": b64_aobj, 10426 }, 10427 "clientExtensionResults": {}, 10428 "type": "public-key" 10429 }) 10430 .to_string() 10431 .as_str() 10432 ) 10433 .unwrap_err() 10434 .to_string() 10435 .into_bytes() 10436 .get(..err.len()), 10437 Some(err.as_slice()) 10438 ); 10439 // `publicKey` mismatch. 10440 let bad_pub_key = P384PubKey::from_sec1_point(&P384Pt::from_affine_coordinates( 10441 &[ 10442 192, 10, 27, 46, 66, 67, 80, 98, 33, 230, 156, 95, 1, 135, 150, 110, 64, 243, 22, 118, 10443 5, 255, 107, 44, 234, 111, 217, 105, 125, 114, 39, 7, 126, 2, 191, 111, 48, 93, 234, 10444 175, 18, 172, 59, 28, 97, 106, 178, 152, 10445 ] 10446 .into(), 10447 &[ 10448 57, 36, 196, 12, 109, 129, 253, 115, 88, 154, 6, 43, 195, 85, 169, 5, 230, 51, 28, 205, 10449 142, 28, 150, 35, 24, 222, 170, 253, 14, 248, 84, 151, 109, 191, 152, 111, 222, 70, 10450 134, 247, 109, 171, 211, 33, 214, 217, 200, 111, 10451 ] 10452 .into(), 10453 false, 10454 )) 10455 .unwrap(); 10456 err = Error::invalid_value( 10457 Unexpected::Bytes([0; 32].as_slice()), 10458 &format!( 10459 "DER-encoded public key to match the public key within the attestation object: P384(UncompressedP384PubKey({:?}, {:?}))", 10460 &att_obj[x_start..y_meta_start], 10461 &att_obj[y_start..], 10462 ) 10463 .as_str(), 10464 ) 10465 .to_string().into_bytes(); 10466 assert_eq!(serde_json::from_str::<Registration>( 10467 serde_json::json!({ 10468 "id": "AAAAAAAAAAAAAAAAAAAAAA", 10469 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 10470 "response": { 10471 "clientDataJSON": b64_cdata_json, 10472 "authenticatorData": b64_adata, 10473 "transports": [], 10474 "publicKey": base64url_nopad::encode(bad_pub_key.to_public_key_der().unwrap().as_bytes()), 10475 "publicKeyAlgorithm": -35i8, 10476 "attestationObject": b64_aobj, 10477 }, 10478 "clientExtensionResults": {}, 10479 "type": "public-key" 10480 }) 10481 .to_string() 10482 .as_str() 10483 ) 10484 .unwrap_err().to_string().into_bytes().get(..err.len()), 10485 Some(err.as_slice()) 10486 ); 10487 // Missing `publicKey` is allowed when not using EdDSA, ES256, or RS256. 10488 assert!( 10489 serde_json::from_str::<Registration>( 10490 serde_json::json!({ 10491 "id": "AAAAAAAAAAAAAAAAAAAAAA", 10492 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 10493 "response": { 10494 "clientDataJSON": b64_cdata_json, 10495 "authenticatorData": b64_adata, 10496 "transports": [], 10497 "publicKeyAlgorithm": -35i8, 10498 "attestationObject": b64_aobj, 10499 }, 10500 "clientExtensionResults": {}, 10501 "type": "public-key" 10502 }) 10503 .to_string() 10504 .as_str() 10505 ) 10506 .is_ok() 10507 ); 10508 // `publicKeyAlgorithm` mismatch when `publicKey` does not exist. 10509 err = Error::invalid_value( 10510 Unexpected::Other(format!("{:?}", CoseAlgorithmIdentifier::Es256).as_str()), 10511 &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {:?}", CoseAlgorithmIdentifier::Es384).as_str() 10512 ) 10513 .to_string().into_bytes(); 10514 assert_eq!( 10515 serde_json::from_str::<Registration>( 10516 serde_json::json!({ 10517 "id": "AAAAAAAAAAAAAAAAAAAAAA", 10518 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 10519 "response": { 10520 "clientDataJSON": b64_cdata_json, 10521 "authenticatorData": b64_adata, 10522 "transports": [], 10523 "publicKeyAlgorithm": -7i8, 10524 "attestationObject": b64_aobj, 10525 }, 10526 "clientExtensionResults": {}, 10527 "type": "public-key" 10528 }) 10529 .to_string() 10530 .as_str() 10531 ) 10532 .unwrap_err() 10533 .to_string() 10534 .into_bytes() 10535 .get(..err.len()), 10536 Some(err.as_slice()) 10537 ); 10538 // `null` `publicKey` is allowed when not using EdDSA, ES256, or RS256. 10539 assert!( 10540 serde_json::from_str::<Registration>( 10541 serde_json::json!({ 10542 "id": "AAAAAAAAAAAAAAAAAAAAAA", 10543 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 10544 "response": { 10545 "clientDataJSON": b64_cdata_json, 10546 "authenticatorData": b64_adata, 10547 "transports": [], 10548 "publicKey": null, 10549 "publicKeyAlgorithm": -35i8, 10550 "attestationObject": b64_aobj, 10551 }, 10552 "clientExtensionResults": {}, 10553 "type": "public-key" 10554 }) 10555 .to_string() 10556 .as_str() 10557 ) 10558 .is_ok() 10559 ); 10560 // `publicKeyAlgorithm` mismatch when `publicKey` is null. 10561 err = Error::invalid_value( 10562 Unexpected::Other(format!("{:?}", CoseAlgorithmIdentifier::Es256).as_str()), 10563 &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {:?}", CoseAlgorithmIdentifier::Es384).as_str() 10564 ) 10565 .to_string().into_bytes(); 10566 assert_eq!( 10567 serde_json::from_str::<Registration>( 10568 serde_json::json!({ 10569 "id": "AAAAAAAAAAAAAAAAAAAAAA", 10570 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 10571 "response": { 10572 "clientDataJSON": b64_cdata_json, 10573 "authenticatorData": b64_adata, 10574 "transports": [], 10575 "publicKey": null, 10576 "publicKeyAlgorithm": -7i8, 10577 "attestationObject": b64_aobj, 10578 }, 10579 "clientExtensionResults": {}, 10580 "type": "public-key" 10581 }) 10582 .to_string() 10583 .as_str() 10584 ) 10585 .unwrap_err() 10586 .to_string() 10587 .into_bytes() 10588 .get(..err.len()), 10589 Some(err.as_slice()) 10590 ); 10591 } 10592 #[expect(clippy::unwrap_used, reason = "OK in tests")] 10593 #[expect(clippy::indexing_slicing, reason = "comments justify correctness")] 10594 #[expect(clippy::too_many_lines, reason = "a lot to test")] 10595 #[test] 10596 fn rs256_registration_deserialize_data_mismatch() { 10597 let c_data_json = serde_json::json!({}).to_string(); 10598 let mut att_obj: [u8; 374] = [ 10599 cbor::MAP_3, 10600 cbor::TEXT_3, 10601 b'f', 10602 b'm', 10603 b't', 10604 cbor::TEXT_4, 10605 b'n', 10606 b'o', 10607 b'n', 10608 b'e', 10609 cbor::TEXT_7, 10610 b'a', 10611 b't', 10612 b't', 10613 b'S', 10614 b't', 10615 b'm', 10616 b't', 10617 cbor::MAP_0, 10618 cbor::TEXT_8, 10619 b'a', 10620 b'u', 10621 b't', 10622 b'h', 10623 b'D', 10624 b'a', 10625 b't', 10626 b'a', 10627 cbor::BYTES_INFO_25, 10628 1, 10629 87, 10630 // `rpIdHash`. 10631 0, 10632 0, 10633 0, 10634 0, 10635 0, 10636 0, 10637 0, 10638 0, 10639 0, 10640 0, 10641 0, 10642 0, 10643 0, 10644 0, 10645 0, 10646 0, 10647 0, 10648 0, 10649 0, 10650 0, 10651 0, 10652 0, 10653 0, 10654 0, 10655 0, 10656 0, 10657 0, 10658 0, 10659 0, 10660 0, 10661 0, 10662 0, 10663 // `flags`. 10664 0b0100_0101, 10665 // `signCount`. 10666 0, 10667 0, 10668 0, 10669 0, 10670 // `aaguid`. 10671 0, 10672 0, 10673 0, 10674 0, 10675 0, 10676 0, 10677 0, 10678 0, 10679 0, 10680 0, 10681 0, 10682 0, 10683 0, 10684 0, 10685 0, 10686 0, 10687 // `credentialIdLength`. 10688 0, 10689 16, 10690 // `credentialId`. 10691 0, 10692 0, 10693 0, 10694 0, 10695 0, 10696 0, 10697 0, 10698 0, 10699 0, 10700 0, 10701 0, 10702 0, 10703 0, 10704 0, 10705 0, 10706 0, 10707 // RSA COSE key. 10708 cbor::MAP_4, 10709 KTY, 10710 RSA, 10711 ALG, 10712 cbor::NEG_INFO_25, 10713 // RS256. 10714 1, 10715 0, 10716 // `n`. 10717 cbor::NEG_ONE, 10718 cbor::BYTES_INFO_25, 10719 1, 10720 0, 10721 // n. This will be overwritten later. 10722 0, 10723 0, 10724 0, 10725 0, 10726 0, 10727 0, 10728 0, 10729 0, 10730 0, 10731 0, 10732 0, 10733 0, 10734 0, 10735 0, 10736 0, 10737 0, 10738 0, 10739 0, 10740 0, 10741 0, 10742 0, 10743 0, 10744 0, 10745 0, 10746 0, 10747 0, 10748 0, 10749 0, 10750 0, 10751 0, 10752 0, 10753 0, 10754 0, 10755 0, 10756 0, 10757 0, 10758 0, 10759 0, 10760 0, 10761 0, 10762 0, 10763 0, 10764 0, 10765 0, 10766 0, 10767 0, 10768 0, 10769 0, 10770 0, 10771 0, 10772 0, 10773 0, 10774 0, 10775 0, 10776 0, 10777 0, 10778 0, 10779 0, 10780 0, 10781 0, 10782 0, 10783 0, 10784 0, 10785 0, 10786 0, 10787 0, 10788 0, 10789 0, 10790 0, 10791 0, 10792 0, 10793 0, 10794 0, 10795 0, 10796 0, 10797 0, 10798 0, 10799 0, 10800 0, 10801 0, 10802 0, 10803 0, 10804 0, 10805 0, 10806 0, 10807 0, 10808 0, 10809 0, 10810 0, 10811 0, 10812 0, 10813 0, 10814 0, 10815 0, 10816 0, 10817 0, 10818 0, 10819 0, 10820 0, 10821 0, 10822 0, 10823 0, 10824 0, 10825 0, 10826 0, 10827 0, 10828 0, 10829 0, 10830 0, 10831 0, 10832 0, 10833 0, 10834 0, 10835 0, 10836 0, 10837 0, 10838 0, 10839 0, 10840 0, 10841 0, 10842 0, 10843 0, 10844 0, 10845 0, 10846 0, 10847 0, 10848 0, 10849 0, 10850 0, 10851 0, 10852 0, 10853 0, 10854 0, 10855 0, 10856 0, 10857 0, 10858 0, 10859 0, 10860 0, 10861 0, 10862 0, 10863 0, 10864 0, 10865 0, 10866 0, 10867 0, 10868 0, 10869 0, 10870 0, 10871 0, 10872 0, 10873 0, 10874 0, 10875 0, 10876 0, 10877 0, 10878 0, 10879 0, 10880 0, 10881 0, 10882 0, 10883 0, 10884 0, 10885 0, 10886 0, 10887 0, 10888 0, 10889 0, 10890 0, 10891 0, 10892 0, 10893 0, 10894 0, 10895 0, 10896 0, 10897 0, 10898 0, 10899 0, 10900 0, 10901 0, 10902 0, 10903 0, 10904 0, 10905 0, 10906 0, 10907 0, 10908 0, 10909 0, 10910 0, 10911 0, 10912 0, 10913 0, 10914 0, 10915 0, 10916 0, 10917 0, 10918 0, 10919 0, 10920 0, 10921 0, 10922 0, 10923 0, 10924 0, 10925 0, 10926 0, 10927 0, 10928 0, 10929 0, 10930 0, 10931 0, 10932 0, 10933 0, 10934 0, 10935 0, 10936 0, 10937 0, 10938 0, 10939 0, 10940 0, 10941 0, 10942 0, 10943 0, 10944 0, 10945 0, 10946 0, 10947 0, 10948 0, 10949 0, 10950 0, 10951 0, 10952 0, 10953 0, 10954 0, 10955 0, 10956 0, 10957 0, 10958 0, 10959 0, 10960 0, 10961 0, 10962 0, 10963 0, 10964 0, 10965 0, 10966 0, 10967 0, 10968 0, 10969 0, 10970 0, 10971 0, 10972 0, 10973 0, 10974 0, 10975 0, 10976 0, 10977 0, 10978 // `e`. 10979 cbor::NEG_TWO, 10980 cbor::BYTES | 3, 10981 // e. 10982 1, 10983 0, 10984 1, 10985 ]; 10986 let n = [ 10987 111, 183, 124, 133, 38, 167, 70, 148, 44, 50, 30, 60, 121, 14, 38, 37, 96, 114, 107, 195, 10988 248, 64, 79, 36, 237, 140, 43, 27, 94, 74, 102, 152, 135, 102, 184, 150, 186, 206, 185, 19, 10989 165, 209, 48, 98, 98, 9, 3, 205, 208, 82, 250, 105, 132, 201, 73, 62, 60, 165, 100, 128, 10990 153, 9, 41, 118, 66, 95, 236, 214, 73, 135, 197, 68, 184, 10, 27, 116, 204, 145, 50, 174, 10991 58, 42, 183, 181, 119, 232, 126, 252, 217, 96, 162, 190, 103, 122, 64, 87, 145, 45, 32, 10992 207, 17, 239, 223, 3, 35, 14, 112, 119, 124, 141, 123, 208, 239, 105, 81, 217, 151, 162, 10993 190, 17, 88, 182, 176, 158, 81, 200, 42, 166, 133, 48, 23, 236, 55, 117, 248, 233, 151, 10994 203, 122, 155, 231, 46, 177, 20, 20, 151, 64, 222, 239, 226, 7, 21, 254, 81, 202, 64, 232, 10995 161, 235, 22, 51, 246, 207, 213, 0, 229, 138, 46, 222, 205, 157, 108, 139, 253, 230, 80, 10996 50, 2, 122, 212, 163, 100, 180, 114, 12, 113, 52, 56, 99, 188, 42, 198, 212, 23, 182, 222, 10997 56, 221, 200, 79, 96, 239, 221, 135, 10, 17, 106, 183, 56, 104, 68, 94, 198, 196, 35, 200, 10998 83, 204, 26, 185, 204, 212, 31, 183, 19, 111, 233, 13, 72, 93, 53, 65, 111, 59, 242, 122, 10999 160, 244, 162, 126, 38, 235, 156, 47, 88, 39, 132, 153, 79, 0, 133, 78, 7, 218, 165, 241, 11000 ]; 11001 let e = 0x0001_0001u32; 11002 let d = [ 11003 145, 79, 21, 97, 233, 3, 192, 194, 177, 68, 181, 80, 120, 197, 23, 44, 185, 74, 144, 0, 11004 132, 149, 139, 11, 16, 224, 4, 112, 236, 94, 238, 97, 121, 124, 213, 145, 24, 253, 168, 35, 11005 190, 205, 132, 115, 33, 201, 38, 253, 246, 180, 66, 155, 165, 46, 3, 254, 68, 108, 154, 11006 247, 246, 45, 187, 0, 204, 96, 185, 157, 249, 174, 158, 38, 62, 244, 183, 76, 102, 6, 219, 11007 92, 212, 138, 59, 147, 163, 219, 111, 39, 105, 21, 236, 196, 38, 255, 114, 247, 82, 104, 11008 113, 204, 29, 152, 209, 219, 48, 239, 74, 129, 19, 247, 33, 239, 119, 166, 216, 152, 94, 11009 138, 238, 164, 242, 129, 50, 150, 57, 20, 53, 224, 56, 241, 138, 97, 111, 215, 107, 212, 11010 195, 146, 108, 143, 0, 229, 181, 171, 73, 152, 105, 146, 25, 243, 242, 140, 252, 248, 162, 11011 247, 63, 168, 180, 20, 153, 120, 10, 248, 211, 1, 71, 127, 212, 249, 237, 203, 202, 48, 26, 11012 216, 226, 228, 186, 13, 204, 70, 255, 240, 89, 255, 59, 83, 31, 253, 55, 43, 158, 90, 248, 11013 83, 32, 159, 105, 57, 134, 34, 96, 18, 255, 245, 153, 162, 60, 91, 99, 220, 51, 44, 85, 11014 114, 67, 125, 202, 65, 217, 245, 40, 8, 81, 165, 142, 24, 245, 127, 122, 247, 152, 212, 75, 11015 45, 59, 90, 184, 234, 31, 147, 36, 8, 212, 45, 50, 23, 3, 25, 253, 87, 227, 79, 119, 161, 11016 ]; 11017 let p = BoxedUint::from_le_slice_vartime( 11018 [ 11019 215, 166, 5, 21, 11, 179, 41, 77, 198, 92, 165, 48, 77, 162, 42, 41, 206, 141, 60, 69, 11020 47, 164, 19, 92, 46, 72, 100, 238, 100, 53, 214, 197, 163, 185, 6, 140, 229, 250, 195, 11021 77, 8, 12, 5, 236, 178, 173, 86, 201, 43, 213, 165, 51, 108, 101, 161, 99, 76, 240, 14, 11022 234, 76, 197, 137, 53, 198, 168, 135, 205, 212, 198, 120, 29, 16, 82, 98, 233, 236, 11023 177, 12, 171, 141, 100, 107, 146, 33, 176, 125, 202, 172, 79, 147, 179, 30, 62, 247, 11024 206, 169, 19, 168, 114, 26, 73, 108, 178, 105, 84, 89, 191, 168, 253, 228, 214, 54, 16, 11025 212, 199, 111, 72, 3, 41, 247, 227, 165, 244, 32, 188, 24, 247, 11026 ] 11027 .as_slice(), 11028 ); 11029 let p_2 = BoxedUint::from_le_slice_vartime( 11030 [ 11031 41, 25, 198, 240, 134, 206, 121, 57, 11, 5, 134, 192, 212, 77, 229, 197, 14, 78, 85, 11032 212, 190, 114, 179, 188, 21, 171, 174, 12, 104, 74, 15, 164, 136, 173, 62, 177, 141, 11033 213, 93, 102, 147, 83, 59, 124, 146, 59, 175, 213, 55, 27, 25, 248, 154, 29, 39, 85, 11034 50, 235, 134, 60, 203, 106, 186, 195, 190, 185, 71, 169, 142, 236, 92, 11, 250, 187, 11035 198, 8, 201, 184, 120, 178, 227, 87, 63, 243, 89, 227, 234, 184, 28, 252, 112, 211, 11036 193, 69, 23, 92, 5, 72, 93, 53, 69, 159, 73, 160, 105, 244, 249, 94, 214, 173, 9, 236, 11037 4, 255, 129, 11, 224, 140, 252, 168, 57, 143, 176, 241, 60, 219, 90, 250, 11038 ] 11039 .as_slice(), 11040 ); 11041 let key = RsaPrivateKey::from_components( 11042 BoxedUint::from_le_slice_vartime(n.as_slice()), 11043 e.into(), 11044 BoxedUint::from_le_slice_vartime(d.as_slice()), 11045 vec![p, p_2], 11046 ) 11047 .unwrap() 11048 .to_public_key(); 11049 let pub_key = key.to_public_key_der().unwrap(); 11050 let att_obj_len = att_obj.len(); 11051 let n_start_idx = att_obj_len - 261; 11052 let e_meta_start_idx = n_start_idx + 256; 11053 // Correct and won't `panic`. 11054 att_obj[n_start_idx..e_meta_start_idx] 11055 .copy_from_slice(key.n().to_be_bytes_trimmed_vartime().as_ref()); 11056 let b64_cdata_json = base64url_nopad::encode(c_data_json.as_bytes()); 11057 // Won't `panic`. 11058 let b64_adata = base64url_nopad::encode(&att_obj[31..]); 11059 let b64_key = base64url_nopad::encode(pub_key.as_bytes()); 11060 let b64_aobj = base64url_nopad::encode(att_obj.as_slice()); 11061 // Base case is valid. 11062 assert!( 11063 serde_json::from_str::<Registration>( 11064 serde_json::json!({ 11065 "id": "AAAAAAAAAAAAAAAAAAAAAA", 11066 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 11067 "response": { 11068 "clientDataJSON": b64_cdata_json, 11069 "authenticatorData": b64_adata, 11070 "transports": [], 11071 "publicKey": b64_key, 11072 "publicKeyAlgorithm": -257i16, 11073 "attestationObject": b64_aobj, 11074 }, 11075 "clientExtensionResults": {}, 11076 "type": "public-key" 11077 }) 11078 .to_string() 11079 .as_str() 11080 ) 11081 .is_ok_and( 11082 |reg| reg.response.client_data_json == c_data_json.as_bytes() 11083 && reg.response.attestation_object_and_c_data_hash[..att_obj_len] == att_obj 11084 && reg.response.attestation_object_and_c_data_hash[att_obj_len..] 11085 == *Sha256::digest(c_data_json.as_bytes()) 11086 && reg.response.transports.is_empty() 11087 && matches!(reg.authenticator_attachment, AuthenticatorAttachment::None) 11088 && reg.client_extension_results.cred_props.is_none() 11089 && reg.client_extension_results.prf.is_none() 11090 ) 11091 ); 11092 // `publicKeyAlgorithm` mismatch. 11093 let mut err = Error::invalid_value( 11094 Unexpected::Other(format!("{:?}", CoseAlgorithmIdentifier::Eddsa).as_str()), 11095 &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {:?}", CoseAlgorithmIdentifier::Rs256).as_str() 11096 ) 11097 .to_string().into_bytes(); 11098 assert_eq!( 11099 serde_json::from_str::<Registration>( 11100 serde_json::json!({ 11101 "id": "AAAAAAAAAAAAAAAAAAAAAA", 11102 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 11103 "response": { 11104 "clientDataJSON": b64_cdata_json, 11105 "authenticatorData": b64_adata, 11106 "transports": [], 11107 "publicKey": b64_key, 11108 "publicKeyAlgorithm": -8i8, 11109 "attestationObject": b64_aobj, 11110 }, 11111 "clientExtensionResults": {}, 11112 "type": "public-key" 11113 }) 11114 .to_string() 11115 .as_str() 11116 ) 11117 .unwrap_err() 11118 .to_string() 11119 .into_bytes() 11120 .get(..err.len()), 11121 Some(err.as_slice()) 11122 ); 11123 // Missing `publicKeyAlgorithm`. 11124 err = Error::missing_field("publicKeyAlgorithm") 11125 .to_string() 11126 .into_bytes(); 11127 assert_eq!( 11128 serde_json::from_str::<Registration>( 11129 serde_json::json!({ 11130 "id": "AAAAAAAAAAAAAAAAAAAAAA", 11131 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 11132 "response": { 11133 "clientDataJSON": b64_cdata_json, 11134 "authenticatorData": b64_adata, 11135 "transports": [], 11136 "publicKey": b64_key, 11137 "attestationObject": b64_aobj, 11138 }, 11139 "clientExtensionResults": {}, 11140 "type": "public-key" 11141 }) 11142 .to_string() 11143 .as_str() 11144 ) 11145 .unwrap_err() 11146 .to_string() 11147 .into_bytes() 11148 .get(..err.len()), 11149 Some(err.as_slice()) 11150 ); 11151 // `null` `publicKeyAlgorithm`. 11152 err = Error::invalid_type(Unexpected::Other("null"), &"publicKeyAlgorithm") 11153 .to_string() 11154 .into_bytes(); 11155 assert_eq!( 11156 serde_json::from_str::<Registration>( 11157 serde_json::json!({ 11158 "id": "AAAAAAAAAAAAAAAAAAAAAA", 11159 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 11160 "response": { 11161 "clientDataJSON": b64_cdata_json, 11162 "authenticatorData": b64_adata, 11163 "transports": [], 11164 "publicKey": b64_key, 11165 "publicKeyAlgorithm": null, 11166 "attestationObject": b64_aobj, 11167 }, 11168 "clientExtensionResults": {}, 11169 "type": "public-key" 11170 }) 11171 .to_string() 11172 .as_str() 11173 ) 11174 .unwrap_err() 11175 .to_string() 11176 .into_bytes() 11177 .get(..err.len()), 11178 Some(err.as_slice()) 11179 ); 11180 // `publicKey` mismatch. 11181 let bad_pub_key = RsaPrivateKey::from_components( 11182 BoxedUint::from_le_slice_vartime( 11183 [ 11184 175, 161, 161, 75, 52, 244, 72, 168, 29, 119, 33, 120, 3, 222, 231, 152, 222, 119, 11185 112, 83, 221, 237, 74, 174, 79, 216, 147, 251, 245, 94, 234, 114, 254, 21, 17, 254, 11186 8, 115, 75, 127, 150, 87, 59, 109, 230, 116, 85, 90, 11, 160, 63, 217, 9, 38, 187, 11187 250, 226, 183, 38, 164, 182, 218, 22, 19, 58, 189, 83, 219, 11, 144, 15, 99, 151, 11188 166, 46, 57, 17, 111, 189, 131, 142, 113, 85, 122, 188, 238, 52, 21, 116, 125, 102, 11189 195, 182, 165, 29, 156, 213, 182, 125, 156, 88, 56, 221, 2, 98, 43, 210, 115, 32, 11190 4, 105, 88, 181, 158, 207, 236, 162, 250, 253, 240, 72, 8, 253, 50, 220, 247, 76, 11191 170, 143, 68, 225, 231, 113, 64, 244, 17, 138, 162, 233, 33, 2, 67, 11, 223, 188, 11192 232, 152, 193, 20, 32, 243, 52, 64, 43, 2, 243, 8, 77, 150, 232, 109, 148, 95, 127, 11193 55, 71, 162, 34, 54, 83, 135, 52, 172, 191, 32, 42, 106, 43, 211, 206, 100, 104, 11194 110, 232, 5, 43, 120, 180, 166, 40, 144, 233, 239, 103, 134, 103, 255, 224, 138, 11195 184, 208, 137, 127, 36, 189, 143, 248, 201, 2, 218, 51, 232, 96, 30, 83, 124, 109, 11196 241, 23, 179, 247, 151, 238, 212, 204, 44, 43, 223, 148, 241, 172, 10, 235, 155, 11197 94, 68, 116, 24, 116, 191, 86, 53, 127, 35, 133, 198, 204, 59, 76, 110, 16, 1, 15, 11198 148, 135, 157, 11199 ] 11200 .as_slice(), 11201 ), 11202 0x0001_0001u32.into(), 11203 BoxedUint::from_le_slice_vartime( 11204 [ 11205 129, 93, 123, 251, 104, 29, 84, 203, 116, 100, 75, 237, 111, 160, 12, 100, 172, 76, 11206 57, 178, 144, 235, 81, 61, 115, 243, 28, 40, 183, 22, 56, 150, 68, 38, 220, 62, 11207 233, 110, 48, 174, 35, 197, 244, 109, 148, 109, 36, 69, 69, 82, 225, 113, 175, 6, 11208 239, 27, 193, 101, 50, 239, 122, 102, 7, 46, 98, 79, 195, 116, 155, 158, 138, 147, 11209 51, 93, 24, 237, 246, 82, 14, 109, 144, 250, 239, 93, 63, 214, 96, 130, 226, 134, 11210 198, 145, 161, 11, 231, 97, 214, 180, 255, 95, 158, 88, 108, 254, 243, 177, 133, 11211 184, 92, 95, 148, 88, 55, 124, 245, 244, 84, 86, 4, 121, 44, 231, 97, 176, 190, 29, 11212 155, 40, 57, 69, 165, 80, 168, 9, 56, 43, 233, 6, 14, 157, 112, 223, 64, 88, 141, 11213 7, 65, 23, 64, 208, 6, 83, 61, 8, 182, 248, 126, 84, 179, 163, 80, 238, 90, 133, 4, 11214 14, 71, 177, 175, 27, 29, 151, 211, 108, 162, 195, 7, 157, 167, 86, 169, 3, 87, 11215 235, 89, 158, 237, 216, 31, 243, 197, 62, 5, 84, 131, 230, 186, 248, 49, 12, 93, 11216 244, 61, 135, 180, 17, 162, 241, 13, 115, 241, 138, 219, 98, 155, 166, 191, 63, 12, 11217 37, 1, 165, 178, 84, 200, 72, 80, 41, 77, 136, 217, 141, 246, 209, 31, 243, 159, 11218 71, 43, 246, 159, 182, 171, 116, 12, 3, 142, 235, 218, 164, 70, 90, 147, 238, 42, 11219 75, 11220 ] 11221 .as_slice(), 11222 ), 11223 vec![ 11224 BoxedUint::from_le_slice_vartime( 11225 [ 11226 215, 199, 110, 28, 64, 16, 16, 109, 106, 152, 150, 124, 52, 166, 121, 92, 242, 11227 13, 0, 69, 7, 152, 72, 172, 118, 63, 156, 180, 140, 39, 53, 29, 197, 224, 177, 11228 48, 41, 221, 102, 65, 17, 185, 55, 62, 219, 152, 227, 7, 78, 219, 14, 139, 71, 11229 204, 144, 152, 14, 39, 247, 244, 165, 224, 234, 60, 213, 74, 237, 30, 102, 177, 11230 242, 138, 168, 31, 122, 47, 206, 155, 225, 113, 103, 175, 152, 244, 27, 233, 11231 112, 223, 248, 38, 215, 178, 20, 244, 8, 121, 26, 11, 70, 122, 16, 85, 167, 87, 11232 64, 216, 228, 227, 173, 57, 250, 8, 221, 38, 12, 203, 212, 1, 112, 43, 72, 91, 11233 225, 97, 228, 57, 154, 193, 11234 ] 11235 .as_slice(), 11236 ), 11237 BoxedUint::from_le_slice_vartime( 11238 [ 11239 233, 89, 204, 152, 31, 242, 8, 110, 38, 190, 111, 159, 105, 105, 45, 85, 15, 11240 244, 30, 250, 174, 226, 219, 111, 107, 191, 196, 135, 17, 123, 186, 167, 85, 11241 13, 120, 197, 159, 129, 78, 237, 152, 31, 230, 26, 229, 253, 197, 211, 105, 11242 204, 126, 142, 250, 55, 26, 172, 65, 160, 45, 6, 99, 86, 66, 238, 107, 6, 98, 11243 171, 93, 224, 201, 160, 31, 204, 82, 120, 228, 158, 238, 6, 190, 12, 150, 153, 11244 239, 95, 57, 71, 100, 239, 235, 155, 73, 200, 5, 225, 127, 185, 46, 48, 243, 11245 84, 33, 142, 17, 19, 20, 23, 215, 16, 114, 58, 211, 14, 73, 148, 168, 252, 159, 11246 252, 125, 57, 101, 211, 188, 12, 77, 208, 11247 ] 11248 .as_slice(), 11249 ), 11250 ], 11251 ) 11252 .unwrap() 11253 .to_public_key(); 11254 err = Error::invalid_value( 11255 Unexpected::Bytes([0; 32].as_slice()), 11256 &format!( 11257 "DER-encoded public key to match the public key within the attestation object: Rsa(RsaPubKey({:?}, 65537))", 11258 // Correct and won't `panic`. 11259 &att_obj[n_start_idx..e_meta_start_idx], 11260 ) 11261 .as_str(), 11262 ) 11263 .to_string().into_bytes(); 11264 assert_eq!(serde_json::from_str::<Registration>( 11265 serde_json::json!({ 11266 "id": "AAAAAAAAAAAAAAAAAAAAAA", 11267 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 11268 "response": { 11269 "clientDataJSON": b64_cdata_json, 11270 "authenticatorData": b64_adata, 11271 "transports": [], 11272 "publicKey": base64url_nopad::encode(bad_pub_key.to_public_key_der().unwrap().as_bytes()), 11273 "publicKeyAlgorithm": -257i16, 11274 "attestationObject": b64_aobj, 11275 }, 11276 "clientExtensionResults": {}, 11277 "type": "public-key" 11278 }) 11279 .to_string() 11280 .as_str() 11281 ) 11282 .unwrap_err().to_string().into_bytes().get(..err.len()), 11283 Some(err.as_slice()) 11284 ); 11285 // Missing `publicKey` when using EdDSA, ES256, or RS256. 11286 err = Error::missing_field("publicKey").to_string().into_bytes(); 11287 assert_eq!( 11288 serde_json::from_str::<Registration>( 11289 serde_json::json!({ 11290 "id": "AAAAAAAAAAAAAAAAAAAAAA", 11291 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 11292 "response": { 11293 "clientDataJSON": b64_cdata_json, 11294 "authenticatorData": b64_adata, 11295 "transports": [], 11296 "publicKeyAlgorithm": -257i16, 11297 "attestationObject": b64_aobj, 11298 }, 11299 "clientExtensionResults": {}, 11300 "type": "public-key" 11301 }) 11302 .to_string() 11303 .as_str() 11304 ) 11305 .unwrap_err() 11306 .to_string() 11307 .into_bytes() 11308 .get(..err.len()), 11309 Some(err.as_slice()) 11310 ); 11311 // `null` `publicKey` when using EdDSA, ES256, or RS256. 11312 err = Error::invalid_type(Unexpected::Other("null"), &"publicKey") 11313 .to_string() 11314 .into_bytes(); 11315 assert_eq!( 11316 serde_json::from_str::<Registration>( 11317 serde_json::json!({ 11318 "id": "AAAAAAAAAAAAAAAAAAAAAA", 11319 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 11320 "response": { 11321 "clientDataJSON": b64_cdata_json, 11322 "authenticatorData": b64_adata, 11323 "transports": [], 11324 "publicKey": null, 11325 "publicKeyAlgorithm": -257i16, 11326 "attestationObject": b64_aobj, 11327 }, 11328 "clientExtensionResults": {}, 11329 "type": "public-key" 11330 }) 11331 .to_string() 11332 .as_str() 11333 ) 11334 .unwrap_err() 11335 .to_string() 11336 .into_bytes() 11337 .get(..err.len()), 11338 Some(err.as_slice()) 11339 ); 11340 }