Loading tools/rootcanal/rust/src/lmp/procedure/secure_simple_pairing.rs +137 −65 Original line number Diff line number Diff line Loading @@ -143,11 +143,14 @@ async fn receive_public_key(ctx: &impl Context, transaction_id: u8) -> PublicKey const COMMITMENT_VALUE_SIZE: usize = 16; const NONCE_SIZE: usize = 16; async fn receive_commitment(ctx: &impl Context, skip_first: bool) { let commitment_value = [0; COMMITMENT_VALUE_SIZE]; fn build_commitment(_ctx: &impl Context) -> [u8; COMMITMENT_VALUE_SIZE] { [0; COMMITMENT_VALUE_SIZE] } if !skip_first { let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; async fn receive_commitment(ctx: &impl Context, confirm: Option<lmp::SimplePairingConfirm>) { let commitment_value = build_commitment(ctx); if let Some(confirm) = confirm { if confirm.get_commitment_value() != &commitment_value { todo!(); } Loading Loading @@ -177,16 +180,8 @@ async fn receive_commitment(ctx: &impl Context, skip_first: bool) { .await; } async fn send_commitment(ctx: &impl Context, skip_first: bool) { let commitment_value = [0; COMMITMENT_VALUE_SIZE]; if !skip_first { ctx.send_lmp_packet( lmp::SimplePairingConfirmBuilder { transaction_id: 0, commitment_value }.build(), ); } let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; async fn send_commitment(ctx: &impl Context, confirm: lmp::SimplePairingConfirm) { let commitment_value = build_commitment(ctx); if confirm.get_commitment_value() != &commitment_value { todo!(); Loading Loading @@ -437,7 +432,8 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { match auth_method { AuthenticationMethod::NumericComparisonJustWork | AuthenticationMethod::NumericComparisonUserConfirm => { send_commitment(ctx, true).await; let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; send_commitment(ctx, confirm).await; if user_confirmation_request(ctx).await.is_err() { ctx.send_lmp_packet( Loading @@ -448,13 +444,21 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { Ok(()) } AuthenticationMethod::PasskeyEntry => { if initiator.io_capability == hci::IoCapability::KeyboardOnly { let confirm = if initiator.io_capability == hci::IoCapability::KeyboardOnly { if user_passkey_request(ctx).await.is_err() { ctx.send_lmp_packet( lmp::PasskeyFailedBuilder { transaction_id: 0 }.build(), ); Err(())?; } ctx.send_lmp_packet( lmp::SimplePairingConfirmBuilder { transaction_id: 0, commitment_value: build_commitment(ctx), } .build(), ); ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await } else { ctx.send_hci_event( hci::UserPasskeyNotificationBuilder { Loading @@ -463,9 +467,32 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { } .build(), ); ctx.send_lmp_packet( lmp::SimplePairingConfirmBuilder { transaction_id: 0, commitment_value: build_commitment(ctx), } for _ in 0..PASSKEY_ENTRY_REPEAT_NUMBER { send_commitment(ctx, false).await; .build(), ); match ctx .receive_lmp_packet::<Either<lmp::SimplePairingConfirm, lmp::NotAccepted>>() .await { Either::Left(confirm) => confirm, Either::Right(_) => Err(())?, } }; send_commitment(ctx, confirm).await; for _ in 1..PASSKEY_ENTRY_REPEAT_NUMBER { ctx.send_lmp_packet( lmp::SimplePairingConfirmBuilder { transaction_id: 0, commitment_value: build_commitment(ctx), } .build(), ); let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; send_commitment(ctx, confirm).await; } Ok(()) } Loading @@ -474,7 +501,15 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { remote_oob_data_request(ctx).await?; } send_commitment(ctx, false).await; ctx.send_lmp_packet( lmp::SimplePairingConfirmBuilder { transaction_id: 0, commitment_value: build_commitment(ctx), } .build(), ); let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; send_commitment(ctx, confirm).await; Ok(()) } } Loading Loading @@ -653,48 +688,52 @@ pub async fn respond(ctx: &impl Context, request: lmp::IoCapabilityReq) -> Resul // Authentication Stage 1 let auth_method = authentication_method(initiator, responder); let negative_user_confirmation = match auth_method { let result: Result<bool, ()> = async { match auth_method { AuthenticationMethod::NumericComparisonJustWork | AuthenticationMethod::NumericComparisonUserConfirm => { receive_commitment(ctx, true).await; receive_commitment(ctx, None).await; let user_confirmation = user_confirmation_request(ctx).await; user_confirmation.is_err() Ok(user_confirmation.is_err()) } AuthenticationMethod::PasskeyEntry => { let skip_first_commitment = if responder.io_capability == hci::IoCapability::KeyboardOnly { // TODO: handle error let _user_passkey = user_passkey_request(ctx).await; false let confirm = if responder.io_capability == hci::IoCapability::KeyboardOnly { let user_passkey = user_passkey_request(ctx).await; let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; if user_passkey.is_err() { ctx.send_lmp_packet( lmp::NotAcceptedBuilder { transaction_id: 0, not_accepted_opcode: lmp::Opcode::SimplePairingConfirm, error_code: hci::ErrorCode::AuthenticationFailure.into(), }.build(), ); return Err(()); } confirm } else { ctx.send_hci_event( hci::UserPasskeyNotificationBuilder { bd_addr: ctx.peer_address(), passkey: 0 } hci::UserPasskeyNotificationBuilder { bd_addr: ctx.peer_address(), passkey: 0, } .build(), ); match ctx .receive_lmp_packet::<Either<lmp::SimplePairingConfirm, lmp::PasskeyFailed>>() .await { Either::Left(_) => true, // TODO: check for `confirm.get_commitment_value()` Either::Right(_) => { ctx.send_hci_event( hci::SimplePairingCompleteBuilder { status: hci::ErrorCode::AuthenticationFailure, bd_addr: ctx.peer_address(), } .build(), ); return Err(()); } Either::Left(confirm) => confirm, Either::Right(_) => Err(())?, } }; receive_commitment(ctx, skip_first_commitment).await; receive_commitment(ctx, Some(confirm)).await; for _ in 1..PASSKEY_ENTRY_REPEAT_NUMBER { receive_commitment(ctx, false).await; let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; receive_commitment(ctx, Some(confirm)).await; } false Ok(false) } AuthenticationMethod::OutOfBand => { if responder.oob_data_present != hci::OobDataPresent::NotPresent { Loading @@ -702,8 +741,25 @@ pub async fn respond(ctx: &impl Context, request: lmp::IoCapabilityReq) -> Resul let _remote_oob_data = remote_oob_data_request(ctx).await; } receive_commitment(ctx, false).await; false let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; receive_commitment(ctx, Some(confirm)).await; Ok(false) } } } .await; let negative_user_confirmation = match result { Ok(negative_user_confirmation) => negative_user_confirmation, Err(_) => { ctx.send_hci_event( hci::SimplePairingCompleteBuilder { status: hci::ErrorCode::AuthenticationFailure, bd_addr: ctx.peer_address(), } .build(), ); return Err(()); } }; Loading Loading @@ -896,7 +952,7 @@ mod tests { } #[test] fn passkey_entry_initiator_failure_on_initiating_side() { fn passkey_entry_initiator_negative_reply_on_initiating_side() { let context = TestContext::new(); let procedure = initiate; Loading @@ -904,13 +960,29 @@ mod tests { } #[test] fn passkey_entry_responder_failure_on_initiating_side() { fn passkey_entry_responder_negative_reply_on_responding_side() { let context = TestContext::new(); let procedure = respond; include!("../../../test/SP/BV-14bis-C.in"); } #[test] fn passkey_entry_responder_negative_reply_on_initiating_side() { let context = TestContext::new(); let procedure = respond; include!("../../../test/SP/BV-15-C.in"); } #[test] fn passkey_entry_initiator_negative_reply_on_responding_side() { let context = TestContext::new(); let procedure = initiate; include!("../../../test/SP/BV-15bis-C.in"); } #[test] #[should_panic] // TODO: make the test pass fn passkey_entry_initiator_failure_on_responding_side() { Loading tools/rootcanal/rust/test/SP/BV-14bis-C.in 0 → 100644 +106 −0 Original line number Diff line number Diff line // Passkey entry responder, negative reply on responding side: // - Test case not present in LMP.TS, but other permutations are described in SP/BV-14-C, SP/BV-15-C // - IUT is KeyboardOnly, responder // - Lower Tester is Display, initiator // - IUT fails passkey entry with User_Passkey_Request_NegativeReply, responds Not Accepted to the SimplePairingConfirm sequence! { procedure, context, // ACL Connection Established Lower Tester -> IUT: IoCapabilityReq { transaction_id: 0, io_capabilities: 0x00, oob_authentication_data: 0x00, authentication_requirement: 0x01, } IUT -> Upper Tester: IoCapabilityResponse { bd_addr: context.peer_address(), io_capability: IoCapability::DisplayOnly, oob_data_present: OobDataPresent::NotPresent, authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection, } IUT -> Upper Tester: IoCapabilityRequest { bd_addr: context.peer_address(), } Upper Tester -> IUT: IoCapabilityRequestReply { bd_addr: context.peer_address(), io_capability: IoCapability::KeyboardOnly, oob_present: OobDataPresent::NotPresent, authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection, } IUT -> Upper Tester: IoCapabilityRequestReplyComplete { num_hci_command_packets: 1, status: ErrorCode::Success, bd_addr: context.peer_address(), } IUT -> Lower Tester: IoCapabilityRes { transaction_id: 0, io_capabilities: 0x02, oob_authentication_data: 0x00, authentication_requirement: 0x01, } // Public Key Exchange Lower Tester -> IUT: EncapsulatedHeader { transaction_id: 0, major_type: 1, minor_type: 1, payload_length: 48, } IUT -> Lower Tester: Accepted { transaction_id: 0, accepted_opcode: Opcode::EncapsulatedHeader, } repeat 3 times with (part in peer_p192_public_key()) { Lower Tester -> IUT: EncapsulatedPayload { transaction_id: 0, data: part, } IUT -> Lower Tester: Accepted { transaction_id: 0, accepted_opcode: Opcode::EncapsulatedPayload, } } IUT -> Lower Tester: EncapsulatedHeader { transaction_id: 0, major_type: 1, minor_type: 1, payload_length: 48, } Lower Tester -> IUT: Accepted { transaction_id: 0, accepted_opcode: Opcode::EncapsulatedHeader, } repeat 3 times with (part in local_p192_public_key(&context)) { IUT -> Lower Tester: EncapsulatedPayload { transaction_id: 0, data: part, } Lower Tester -> IUT: Accepted { transaction_id: 0, accepted_opcode: Opcode::EncapsulatedPayload, } } // Authentication Stage 1: Passkey Entry Protocol IUT -> Upper Tester: UserPasskeyRequest { bd_addr: context.peer_address(), } Upper Tester -> IUT: UserPasskeyRequestNegativeReply { bd_addr: context.peer_address(), } IUT -> Upper Tester: UserPasskeyRequestNegativeReplyComplete { num_hci_command_packets: 1, status: ErrorCode::Success, bd_addr: context.peer_address(), } Lower Tester -> IUT: SimplePairingConfirm { transaction_id: 0, commitment_value: [0; 16], } IUT -> Lower Tester: NotAccepted { transaction_id: 0, not_accepted_opcode: Opcode::SimplePairingConfirm, error_code: ErrorCode::AuthenticationFailure.into(), } IUT -> Upper Tester: SimplePairingComplete { status: ErrorCode::AuthenticationFailure, bd_addr: context.peer_address(), } } tools/rootcanal/rust/test/SP/BV-15bis-C.in 0 → 100644 +118 −0 Original line number Diff line number Diff line // Passkey entry initiator, negative reply on responding side: // - Test case not present in LMP.TS, but other permutations are described in SP/BV-14-C, SP/BV-15-C // - IUT is DisplayOnly, initiator // - Lower Tester is KeyboardOnly, responder // - Lower Tester fails passkey entry with User_Passkey_Request_NegativeReply, responds Not Accepted to the SimplePairingConfirm sequence! { procedure, context, // ACL Connection Established Upper Tester -> IUT: AuthenticationRequested { connection_handle: context.peer_handle() } IUT -> Upper Tester: AuthenticationRequestedStatus { num_hci_command_packets: 1, status: ErrorCode::Success, } IUT -> Upper Tester: LinkKeyRequest { bd_addr: context.peer_address(), } Upper Tester -> IUT: LinkKeyRequestNegativeReply { bd_addr: context.peer_address(), } IUT -> Upper Tester: LinkKeyRequestNegativeReplyComplete { num_hci_command_packets: 1, status: ErrorCode::Success, bd_addr: context.peer_address(), } IUT -> Upper Tester: IoCapabilityRequest { bd_addr: context.peer_address(), } Upper Tester -> IUT: IoCapabilityRequestReply { bd_addr: context.peer_address(), io_capability: IoCapability::DisplayOnly, oob_present: OobDataPresent::NotPresent, authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection, } IUT -> Upper Tester: IoCapabilityRequestReplyComplete { num_hci_command_packets: 1, status: ErrorCode::Success, bd_addr: context.peer_address(), } IUT -> Lower Tester: IoCapabilityReq { transaction_id: 0, io_capabilities: 0x00, oob_authentication_data: 0x00, authentication_requirement: 0x01, } Lower Tester -> IUT: IoCapabilityRes { transaction_id: 0, io_capabilities: 0x02, oob_authentication_data: 0x00, authentication_requirement: 0x01, } IUT -> Upper Tester: IoCapabilityResponse { bd_addr: context.peer_address(), io_capability: IoCapability::KeyboardOnly, oob_data_present: OobDataPresent::NotPresent, authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection, } // Public Key Exchange IUT -> Lower Tester: EncapsulatedHeader { transaction_id: 0, major_type: 1, minor_type: 1, payload_length: 48, } Lower Tester -> IUT: Accepted { transaction_id: 0, accepted_opcode: Opcode::EncapsulatedHeader, } repeat 3 times with (part in local_p192_public_key(&context)) { IUT -> Lower Tester: EncapsulatedPayload { transaction_id: 0, data: part, } Lower Tester -> IUT: Accepted { transaction_id: 0, accepted_opcode: Opcode::EncapsulatedPayload, } } Lower Tester -> IUT: EncapsulatedHeader { transaction_id: 0, major_type: 1, minor_type: 1, payload_length: 48, } IUT -> Lower Tester: Accepted { transaction_id: 0, accepted_opcode: Opcode::EncapsulatedHeader, } repeat 3 times with (part in peer_p192_public_key()) { Lower Tester -> IUT: EncapsulatedPayload { transaction_id: 0, data: part, } IUT -> Lower Tester: Accepted { transaction_id: 0, accepted_opcode: Opcode::EncapsulatedPayload, } } // Authentication Stage 1: Passkey Entry Protocol IUT -> Upper Tester: UserPasskeyNotification { bd_addr: context.peer_address(), passkey: 0 } IUT -> Lower Tester: SimplePairingConfirm { transaction_id: 0, commitment_value: [0; 16], } Lower Tester -> IUT: NotAccepted { transaction_id: 0, not_accepted_opcode: Opcode::SimplePairingConfirm, error_code: ErrorCode::AuthenticationFailure.into(), } IUT -> Upper Tester: SimplePairingComplete { status: ErrorCode::AuthenticationFailure, bd_addr: context.peer_address(), } IUT -> Upper Tester: AuthenticationComplete { status: ErrorCode::AuthenticationFailure, connection_handle: context.peer_handle(), } } Loading
tools/rootcanal/rust/src/lmp/procedure/secure_simple_pairing.rs +137 −65 Original line number Diff line number Diff line Loading @@ -143,11 +143,14 @@ async fn receive_public_key(ctx: &impl Context, transaction_id: u8) -> PublicKey const COMMITMENT_VALUE_SIZE: usize = 16; const NONCE_SIZE: usize = 16; async fn receive_commitment(ctx: &impl Context, skip_first: bool) { let commitment_value = [0; COMMITMENT_VALUE_SIZE]; fn build_commitment(_ctx: &impl Context) -> [u8; COMMITMENT_VALUE_SIZE] { [0; COMMITMENT_VALUE_SIZE] } if !skip_first { let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; async fn receive_commitment(ctx: &impl Context, confirm: Option<lmp::SimplePairingConfirm>) { let commitment_value = build_commitment(ctx); if let Some(confirm) = confirm { if confirm.get_commitment_value() != &commitment_value { todo!(); } Loading Loading @@ -177,16 +180,8 @@ async fn receive_commitment(ctx: &impl Context, skip_first: bool) { .await; } async fn send_commitment(ctx: &impl Context, skip_first: bool) { let commitment_value = [0; COMMITMENT_VALUE_SIZE]; if !skip_first { ctx.send_lmp_packet( lmp::SimplePairingConfirmBuilder { transaction_id: 0, commitment_value }.build(), ); } let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; async fn send_commitment(ctx: &impl Context, confirm: lmp::SimplePairingConfirm) { let commitment_value = build_commitment(ctx); if confirm.get_commitment_value() != &commitment_value { todo!(); Loading Loading @@ -437,7 +432,8 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { match auth_method { AuthenticationMethod::NumericComparisonJustWork | AuthenticationMethod::NumericComparisonUserConfirm => { send_commitment(ctx, true).await; let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; send_commitment(ctx, confirm).await; if user_confirmation_request(ctx).await.is_err() { ctx.send_lmp_packet( Loading @@ -448,13 +444,21 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { Ok(()) } AuthenticationMethod::PasskeyEntry => { if initiator.io_capability == hci::IoCapability::KeyboardOnly { let confirm = if initiator.io_capability == hci::IoCapability::KeyboardOnly { if user_passkey_request(ctx).await.is_err() { ctx.send_lmp_packet( lmp::PasskeyFailedBuilder { transaction_id: 0 }.build(), ); Err(())?; } ctx.send_lmp_packet( lmp::SimplePairingConfirmBuilder { transaction_id: 0, commitment_value: build_commitment(ctx), } .build(), ); ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await } else { ctx.send_hci_event( hci::UserPasskeyNotificationBuilder { Loading @@ -463,9 +467,32 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { } .build(), ); ctx.send_lmp_packet( lmp::SimplePairingConfirmBuilder { transaction_id: 0, commitment_value: build_commitment(ctx), } for _ in 0..PASSKEY_ENTRY_REPEAT_NUMBER { send_commitment(ctx, false).await; .build(), ); match ctx .receive_lmp_packet::<Either<lmp::SimplePairingConfirm, lmp::NotAccepted>>() .await { Either::Left(confirm) => confirm, Either::Right(_) => Err(())?, } }; send_commitment(ctx, confirm).await; for _ in 1..PASSKEY_ENTRY_REPEAT_NUMBER { ctx.send_lmp_packet( lmp::SimplePairingConfirmBuilder { transaction_id: 0, commitment_value: build_commitment(ctx), } .build(), ); let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; send_commitment(ctx, confirm).await; } Ok(()) } Loading @@ -474,7 +501,15 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { remote_oob_data_request(ctx).await?; } send_commitment(ctx, false).await; ctx.send_lmp_packet( lmp::SimplePairingConfirmBuilder { transaction_id: 0, commitment_value: build_commitment(ctx), } .build(), ); let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; send_commitment(ctx, confirm).await; Ok(()) } } Loading Loading @@ -653,48 +688,52 @@ pub async fn respond(ctx: &impl Context, request: lmp::IoCapabilityReq) -> Resul // Authentication Stage 1 let auth_method = authentication_method(initiator, responder); let negative_user_confirmation = match auth_method { let result: Result<bool, ()> = async { match auth_method { AuthenticationMethod::NumericComparisonJustWork | AuthenticationMethod::NumericComparisonUserConfirm => { receive_commitment(ctx, true).await; receive_commitment(ctx, None).await; let user_confirmation = user_confirmation_request(ctx).await; user_confirmation.is_err() Ok(user_confirmation.is_err()) } AuthenticationMethod::PasskeyEntry => { let skip_first_commitment = if responder.io_capability == hci::IoCapability::KeyboardOnly { // TODO: handle error let _user_passkey = user_passkey_request(ctx).await; false let confirm = if responder.io_capability == hci::IoCapability::KeyboardOnly { let user_passkey = user_passkey_request(ctx).await; let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; if user_passkey.is_err() { ctx.send_lmp_packet( lmp::NotAcceptedBuilder { transaction_id: 0, not_accepted_opcode: lmp::Opcode::SimplePairingConfirm, error_code: hci::ErrorCode::AuthenticationFailure.into(), }.build(), ); return Err(()); } confirm } else { ctx.send_hci_event( hci::UserPasskeyNotificationBuilder { bd_addr: ctx.peer_address(), passkey: 0 } hci::UserPasskeyNotificationBuilder { bd_addr: ctx.peer_address(), passkey: 0, } .build(), ); match ctx .receive_lmp_packet::<Either<lmp::SimplePairingConfirm, lmp::PasskeyFailed>>() .await { Either::Left(_) => true, // TODO: check for `confirm.get_commitment_value()` Either::Right(_) => { ctx.send_hci_event( hci::SimplePairingCompleteBuilder { status: hci::ErrorCode::AuthenticationFailure, bd_addr: ctx.peer_address(), } .build(), ); return Err(()); } Either::Left(confirm) => confirm, Either::Right(_) => Err(())?, } }; receive_commitment(ctx, skip_first_commitment).await; receive_commitment(ctx, Some(confirm)).await; for _ in 1..PASSKEY_ENTRY_REPEAT_NUMBER { receive_commitment(ctx, false).await; let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; receive_commitment(ctx, Some(confirm)).await; } false Ok(false) } AuthenticationMethod::OutOfBand => { if responder.oob_data_present != hci::OobDataPresent::NotPresent { Loading @@ -702,8 +741,25 @@ pub async fn respond(ctx: &impl Context, request: lmp::IoCapabilityReq) -> Resul let _remote_oob_data = remote_oob_data_request(ctx).await; } receive_commitment(ctx, false).await; false let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; receive_commitment(ctx, Some(confirm)).await; Ok(false) } } } .await; let negative_user_confirmation = match result { Ok(negative_user_confirmation) => negative_user_confirmation, Err(_) => { ctx.send_hci_event( hci::SimplePairingCompleteBuilder { status: hci::ErrorCode::AuthenticationFailure, bd_addr: ctx.peer_address(), } .build(), ); return Err(()); } }; Loading Loading @@ -896,7 +952,7 @@ mod tests { } #[test] fn passkey_entry_initiator_failure_on_initiating_side() { fn passkey_entry_initiator_negative_reply_on_initiating_side() { let context = TestContext::new(); let procedure = initiate; Loading @@ -904,13 +960,29 @@ mod tests { } #[test] fn passkey_entry_responder_failure_on_initiating_side() { fn passkey_entry_responder_negative_reply_on_responding_side() { let context = TestContext::new(); let procedure = respond; include!("../../../test/SP/BV-14bis-C.in"); } #[test] fn passkey_entry_responder_negative_reply_on_initiating_side() { let context = TestContext::new(); let procedure = respond; include!("../../../test/SP/BV-15-C.in"); } #[test] fn passkey_entry_initiator_negative_reply_on_responding_side() { let context = TestContext::new(); let procedure = initiate; include!("../../../test/SP/BV-15bis-C.in"); } #[test] #[should_panic] // TODO: make the test pass fn passkey_entry_initiator_failure_on_responding_side() { Loading
tools/rootcanal/rust/test/SP/BV-14bis-C.in 0 → 100644 +106 −0 Original line number Diff line number Diff line // Passkey entry responder, negative reply on responding side: // - Test case not present in LMP.TS, but other permutations are described in SP/BV-14-C, SP/BV-15-C // - IUT is KeyboardOnly, responder // - Lower Tester is Display, initiator // - IUT fails passkey entry with User_Passkey_Request_NegativeReply, responds Not Accepted to the SimplePairingConfirm sequence! { procedure, context, // ACL Connection Established Lower Tester -> IUT: IoCapabilityReq { transaction_id: 0, io_capabilities: 0x00, oob_authentication_data: 0x00, authentication_requirement: 0x01, } IUT -> Upper Tester: IoCapabilityResponse { bd_addr: context.peer_address(), io_capability: IoCapability::DisplayOnly, oob_data_present: OobDataPresent::NotPresent, authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection, } IUT -> Upper Tester: IoCapabilityRequest { bd_addr: context.peer_address(), } Upper Tester -> IUT: IoCapabilityRequestReply { bd_addr: context.peer_address(), io_capability: IoCapability::KeyboardOnly, oob_present: OobDataPresent::NotPresent, authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection, } IUT -> Upper Tester: IoCapabilityRequestReplyComplete { num_hci_command_packets: 1, status: ErrorCode::Success, bd_addr: context.peer_address(), } IUT -> Lower Tester: IoCapabilityRes { transaction_id: 0, io_capabilities: 0x02, oob_authentication_data: 0x00, authentication_requirement: 0x01, } // Public Key Exchange Lower Tester -> IUT: EncapsulatedHeader { transaction_id: 0, major_type: 1, minor_type: 1, payload_length: 48, } IUT -> Lower Tester: Accepted { transaction_id: 0, accepted_opcode: Opcode::EncapsulatedHeader, } repeat 3 times with (part in peer_p192_public_key()) { Lower Tester -> IUT: EncapsulatedPayload { transaction_id: 0, data: part, } IUT -> Lower Tester: Accepted { transaction_id: 0, accepted_opcode: Opcode::EncapsulatedPayload, } } IUT -> Lower Tester: EncapsulatedHeader { transaction_id: 0, major_type: 1, minor_type: 1, payload_length: 48, } Lower Tester -> IUT: Accepted { transaction_id: 0, accepted_opcode: Opcode::EncapsulatedHeader, } repeat 3 times with (part in local_p192_public_key(&context)) { IUT -> Lower Tester: EncapsulatedPayload { transaction_id: 0, data: part, } Lower Tester -> IUT: Accepted { transaction_id: 0, accepted_opcode: Opcode::EncapsulatedPayload, } } // Authentication Stage 1: Passkey Entry Protocol IUT -> Upper Tester: UserPasskeyRequest { bd_addr: context.peer_address(), } Upper Tester -> IUT: UserPasskeyRequestNegativeReply { bd_addr: context.peer_address(), } IUT -> Upper Tester: UserPasskeyRequestNegativeReplyComplete { num_hci_command_packets: 1, status: ErrorCode::Success, bd_addr: context.peer_address(), } Lower Tester -> IUT: SimplePairingConfirm { transaction_id: 0, commitment_value: [0; 16], } IUT -> Lower Tester: NotAccepted { transaction_id: 0, not_accepted_opcode: Opcode::SimplePairingConfirm, error_code: ErrorCode::AuthenticationFailure.into(), } IUT -> Upper Tester: SimplePairingComplete { status: ErrorCode::AuthenticationFailure, bd_addr: context.peer_address(), } }
tools/rootcanal/rust/test/SP/BV-15bis-C.in 0 → 100644 +118 −0 Original line number Diff line number Diff line // Passkey entry initiator, negative reply on responding side: // - Test case not present in LMP.TS, but other permutations are described in SP/BV-14-C, SP/BV-15-C // - IUT is DisplayOnly, initiator // - Lower Tester is KeyboardOnly, responder // - Lower Tester fails passkey entry with User_Passkey_Request_NegativeReply, responds Not Accepted to the SimplePairingConfirm sequence! { procedure, context, // ACL Connection Established Upper Tester -> IUT: AuthenticationRequested { connection_handle: context.peer_handle() } IUT -> Upper Tester: AuthenticationRequestedStatus { num_hci_command_packets: 1, status: ErrorCode::Success, } IUT -> Upper Tester: LinkKeyRequest { bd_addr: context.peer_address(), } Upper Tester -> IUT: LinkKeyRequestNegativeReply { bd_addr: context.peer_address(), } IUT -> Upper Tester: LinkKeyRequestNegativeReplyComplete { num_hci_command_packets: 1, status: ErrorCode::Success, bd_addr: context.peer_address(), } IUT -> Upper Tester: IoCapabilityRequest { bd_addr: context.peer_address(), } Upper Tester -> IUT: IoCapabilityRequestReply { bd_addr: context.peer_address(), io_capability: IoCapability::DisplayOnly, oob_present: OobDataPresent::NotPresent, authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection, } IUT -> Upper Tester: IoCapabilityRequestReplyComplete { num_hci_command_packets: 1, status: ErrorCode::Success, bd_addr: context.peer_address(), } IUT -> Lower Tester: IoCapabilityReq { transaction_id: 0, io_capabilities: 0x00, oob_authentication_data: 0x00, authentication_requirement: 0x01, } Lower Tester -> IUT: IoCapabilityRes { transaction_id: 0, io_capabilities: 0x02, oob_authentication_data: 0x00, authentication_requirement: 0x01, } IUT -> Upper Tester: IoCapabilityResponse { bd_addr: context.peer_address(), io_capability: IoCapability::KeyboardOnly, oob_data_present: OobDataPresent::NotPresent, authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection, } // Public Key Exchange IUT -> Lower Tester: EncapsulatedHeader { transaction_id: 0, major_type: 1, minor_type: 1, payload_length: 48, } Lower Tester -> IUT: Accepted { transaction_id: 0, accepted_opcode: Opcode::EncapsulatedHeader, } repeat 3 times with (part in local_p192_public_key(&context)) { IUT -> Lower Tester: EncapsulatedPayload { transaction_id: 0, data: part, } Lower Tester -> IUT: Accepted { transaction_id: 0, accepted_opcode: Opcode::EncapsulatedPayload, } } Lower Tester -> IUT: EncapsulatedHeader { transaction_id: 0, major_type: 1, minor_type: 1, payload_length: 48, } IUT -> Lower Tester: Accepted { transaction_id: 0, accepted_opcode: Opcode::EncapsulatedHeader, } repeat 3 times with (part in peer_p192_public_key()) { Lower Tester -> IUT: EncapsulatedPayload { transaction_id: 0, data: part, } IUT -> Lower Tester: Accepted { transaction_id: 0, accepted_opcode: Opcode::EncapsulatedPayload, } } // Authentication Stage 1: Passkey Entry Protocol IUT -> Upper Tester: UserPasskeyNotification { bd_addr: context.peer_address(), passkey: 0 } IUT -> Lower Tester: SimplePairingConfirm { transaction_id: 0, commitment_value: [0; 16], } Lower Tester -> IUT: NotAccepted { transaction_id: 0, not_accepted_opcode: Opcode::SimplePairingConfirm, error_code: ErrorCode::AuthenticationFailure.into(), } IUT -> Upper Tester: SimplePairingComplete { status: ErrorCode::AuthenticationFailure, bd_addr: context.peer_address(), } IUT -> Upper Tester: AuthenticationComplete { status: ErrorCode::AuthenticationFailure, connection_handle: context.peer_handle(), } }