Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit abc35c26 authored by uael's avatar uael
Browse files

lmp: handle passkey entry failure on responding side

As the LMP test specifications does not define those cases, add
two custom test cases to cover the changes.

Bug: 290987423
Test: atest avatar
Change-Id: I46bd879da8c3ec79cbe754d7f833e22e05a1c6cf
parent 36a5b421
Loading
Loading
Loading
Loading
+38 −7
Original line number Diff line number Diff line
@@ -474,8 +474,13 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> {
                        }
                        .build(),
                    );
                    // TODO: handle error
                    ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await
                    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 {
@@ -694,9 +699,19 @@ pub async fn respond(ctx: &impl Context, request: lmp::IoCapabilityReq) -> Resul
            }
            AuthenticationMethod::PasskeyEntry => {
                let confirm = if responder.io_capability == hci::IoCapability::KeyboardOnly {
                    // TODO: handle error
                    let _user_passkey = user_passkey_request(ctx).await;
                    ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await
                    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 {
@@ -937,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;

@@ -945,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() {
+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(),
    }
}
+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(),
    }
}