• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  *  Copyright 2019 The Android Open Source Project
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 
19 #include <gmock/gmock.h>
20 #include <gtest/gtest.h>
21 #include <memory>
22 
23 #include "os/log.h"
24 #include "os/rand.h"
25 #include "security/pairing_handler_le.h"
26 #include "security/test/mocks.h"
27 
28 using ::testing::_;
29 using ::testing::Eq;
30 using ::testing::Field;
31 using ::testing::VariantWith;
32 
33 using bluetooth::os::GenerateRandom;
34 using bluetooth::security::CommandView;
35 
36 namespace bluetooth {
37 namespace security {
38 
39 namespace {
40 
BuilderToView(std::unique_ptr<BasePacketBuilder> builder)41 CommandView BuilderToView(std::unique_ptr<BasePacketBuilder> builder) {
42   std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
43   BitInserter it(*packet_bytes);
44   builder->Serialize(it);
45   PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
46   auto temp_cmd_view = CommandView::Create(packet_bytes_view);
47   return CommandView::Create(temp_cmd_view);
48 }
49 
50 class PairingResultHandlerMock {
51  public:
52   MOCK_CONST_METHOD1(OnPairingFinished, void(PairingResultOrFailure));
53 };
54 
55 std::unique_ptr<PairingResultHandlerMock> pairingResult;
56 LeSecurityInterfaceMock leSecurityMock;
57 UIMock uiMock;
58 
OnPairingFinished(PairingResultOrFailure r)59 void OnPairingFinished(PairingResultOrFailure r) {
60   if (std::holds_alternative<PairingResult>(r)) {
61     LOG(INFO) << "pairing with " << std::get<PairingResult>(r).connection_address << " finished successfully!";
62   } else {
63     LOG(INFO) << "pairing with ... failed!";
64   }
65   pairingResult->OnPairingFinished(r);
66 }
67 }  // namespace
68 
69 class PairingHandlerUnitTest : public testing::Test {
70  protected:
SetUp()71   void SetUp() {
72     thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
73     handler_ = new os::Handler(thread_);
74 
75     bidi_queue_ =
76         std::make_unique<common::BidiQueue<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>>(10);
77     up_buffer_ = std::make_unique<os::EnqueueBuffer<packet::BasePacketBuilder>>(bidi_queue_->GetUpEnd());
78 
79     bidi_queue_->GetDownEnd()->RegisterDequeue(
80         handler_, common::Bind(&PairingHandlerUnitTest::L2CAP_SendSmp, common::Unretained(this)));
81 
82     pairingResult.reset(new PairingResultHandlerMock);
83   }
TearDown()84   void TearDown() {
85     pairingResult.reset();
86     bidi_queue_->GetDownEnd()->UnregisterDequeue();
87     handler_->Clear();
88     delete handler_;
89     delete thread_;
90 
91     ::testing::Mock::VerifyAndClearExpectations(&leSecurityMock);
92     ::testing::Mock::VerifyAndClearExpectations(&uiMock);
93   }
94 
L2CAP_SendSmp()95   void L2CAP_SendSmp() {
96     std::unique_ptr<packet::BasePacketBuilder> builder = bidi_queue_->GetDownEnd()->TryDequeue();
97 
98     outgoing_l2cap_packet_ = BuilderToView(std::move(builder));
99     outgoing_l2cap_packet_->IsValid();
100 
101     outgoing_l2cap_blocker_.notify_one();
102   }
103 
WaitForOutgoingL2capPacket()104   std::optional<bluetooth::security::CommandView> WaitForOutgoingL2capPacket() {
105     std::mutex mutex;
106     std::unique_lock<std::mutex> lock(mutex);
107 
108     // It is possible that we lost wakeup from condition_variable, check if data is already waiting to be processed
109     if (outgoing_l2cap_packet_ != std::nullopt) {
110       std::optional<bluetooth::security::CommandView> tmp = std::nullopt;
111       outgoing_l2cap_packet_.swap(tmp);
112       return tmp;
113     }
114 
115     // Data not ready yet, wait for it.
116     if (outgoing_l2cap_blocker_.wait_for(lock, std::chrono::seconds(5)) == std::cv_status::timeout) {
117       return std::nullopt;
118     }
119 
120     std::optional<bluetooth::security::CommandView> tmp = std::nullopt;
121     outgoing_l2cap_packet_.swap(tmp);
122     return tmp;
123   }
124 
125  public:
126   os::Thread* thread_;
127   os::Handler* handler_;
128   std::unique_ptr<common::BidiQueue<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>> bidi_queue_;
129   std::unique_ptr<os::EnqueueBuffer<packet::BasePacketBuilder>> up_buffer_;
130   std::condition_variable outgoing_l2cap_blocker_;
131   std::optional<bluetooth::security::CommandView> outgoing_l2cap_packet_ = std::nullopt;
132 };
133 
134 InitialInformations initial_informations{
135     .my_role = hci::Role::CENTRAL,
136     .my_connection_address = {{}, hci::AddressType::PUBLIC_DEVICE_ADDRESS},
137     .my_identity_address = {{}, hci::AddressType::PUBLIC_DEVICE_ADDRESS},
138     .my_identity_resolving_key =
139         {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
140 
141     .myPairingCapabilities = {.io_capability = IoCapability::NO_INPUT_NO_OUTPUT,
142                               .oob_data_flag = OobDataFlag::NOT_PRESENT,
143                               .auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
144                               .maximum_encryption_key_size = 16,
145                               .initiator_key_distribution = 0x03,
146                               .responder_key_distribution = 0x03},
147 
148     .remotely_initiated = false,
149     .remote_connection_address = {{}, hci::AddressType::RANDOM_DEVICE_ADDRESS},
150     .user_interface = &uiMock,
151     .le_security_interface = &leSecurityMock,
152     .OnPairingFinished = OnPairingFinished,
153 };
154 
TEST_F(PairingHandlerUnitTest,test_phase_1_failure)155 TEST_F(PairingHandlerUnitTest, test_phase_1_failure) {
156   initial_informations.proper_l2cap_interface = up_buffer_.get();
157   initial_informations.l2cap_handler = handler_;
158   initial_informations.user_interface_handler = handler_;
159 
160   std::unique_ptr<PairingHandlerLe> pairing_handler =
161       std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, initial_informations);
162 
163   std::optional<bluetooth::security::CommandView> pairing_request = WaitForOutgoingL2capPacket();
164   EXPECT_TRUE(pairing_request.has_value());
165   EXPECT_EQ(pairing_request->GetCode(), Code::PAIRING_REQUEST);
166 
167   EXPECT_CALL(*pairingResult, OnPairingFinished(VariantWith<PairingFailure>(_))).Times(1);
168 
169   // SMP will waith for Pairing Response, once bad packet is received, it should stop the Pairing
170   CommandView bad_pairing_response = BuilderToView(PairingRandomBuilder::Create({}));
171   bad_pairing_response.IsValid();
172   pairing_handler->OnCommandView(bad_pairing_response);
173 
174   std::optional<bluetooth::security::CommandView> pairing_failure = WaitForOutgoingL2capPacket();
175   EXPECT_TRUE(pairing_failure.has_value());
176   EXPECT_EQ(pairing_failure->GetCode(), Code::PAIRING_FAILED);
177 }
178 
TEST_F(PairingHandlerUnitTest,test_secure_connections_just_works)179 TEST_F(PairingHandlerUnitTest, test_secure_connections_just_works) {
180   initial_informations.proper_l2cap_interface = up_buffer_.get();
181   initial_informations.l2cap_handler = handler_;
182   initial_informations.user_interface_handler = handler_;
183 
184   // we keep the pairing_handler as unique_ptr to better mimick how it's used
185   // in the real world
186   std::unique_ptr<PairingHandlerLe> pairing_handler =
187       std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, initial_informations);
188 
189   std::optional<bluetooth::security::CommandView> pairing_request_pkt = WaitForOutgoingL2capPacket();
190   EXPECT_TRUE(pairing_request_pkt.has_value());
191   EXPECT_EQ(pairing_request_pkt->GetCode(), Code::PAIRING_REQUEST);
192   CommandView pairing_request = pairing_request_pkt.value();
193 
194   auto pairing_response = BuilderToView(
195       PairingResponseBuilder::Create(IoCapability::KEYBOARD_DISPLAY, OobDataFlag::NOT_PRESENT,
196                                      AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc, 16, 0x03, 0x03));
197   pairing_handler->OnCommandView(pairing_response);
198   // Phase 1 finished.
199 
200   // pairing public key
201   std::optional<bluetooth::security::CommandView> public_key_pkt = WaitForOutgoingL2capPacket();
202   EXPECT_TRUE(public_key_pkt.has_value());
203   EXPECT_EQ(Code::PAIRING_PUBLIC_KEY, public_key_pkt->GetCode());
204   EcdhPublicKey my_public_key;
205   auto ppkv = PairingPublicKeyView::Create(public_key_pkt.value());
206   ppkv.IsValid();
207   my_public_key.x = ppkv.GetPublicKeyX();
208   my_public_key.y = ppkv.GetPublicKeyY();
209 
210   const auto [private_key, public_key] = GenerateECDHKeyPair();
211 
212   pairing_handler->OnCommandView(BuilderToView(PairingPublicKeyBuilder::Create(public_key.x, public_key.y)));
213   // DHKey exchange finished
214   std::array<uint8_t, 32> dhkey = ComputeDHKey(private_key, my_public_key);
215 
216   // Phasae 2 Stage 1 start
217   Octet16 ra, rb;
218   ra = rb = {0};
219 
220   Octet16 Nb = GenerateRandom<16>();
221 
222   // Compute confirm
223   Octet16 Cb = crypto_toolbox::f4((uint8_t*)public_key.x.data(), (uint8_t*)my_public_key.x.data(), Nb, 0);
224 
225   pairing_handler->OnCommandView(BuilderToView(PairingConfirmBuilder::Create(Cb)));
226 
227   // random
228   std::optional<bluetooth::security::CommandView> random_pkt = WaitForOutgoingL2capPacket();
229   EXPECT_TRUE(random_pkt.has_value());
230   EXPECT_EQ(Code::PAIRING_RANDOM, random_pkt->GetCode());
231   auto prv = PairingRandomView::Create(random_pkt.value());
232   prv.IsValid();
233   Octet16 Na = prv.GetRandomValue();
234 
235   pairing_handler->OnCommandView(BuilderToView(PairingRandomBuilder::Create(Nb)));
236 
237   // Start of authentication stage 2
238   uint8_t a[7];
239   uint8_t b[7];
240   memcpy(b, initial_informations.remote_connection_address.GetAddress().data(), hci::Address::kLength);
241   b[6] = (uint8_t)initial_informations.remote_connection_address.GetAddressType();
242   memcpy(a, initial_informations.my_connection_address.GetAddress().data(), hci::Address::kLength);
243   a[6] = (uint8_t)initial_informations.my_connection_address.GetAddressType();
244 
245   Octet16 ltk, mac_key;
246   crypto_toolbox::f5(dhkey.data(), Na, Nb, a, b, &mac_key, &ltk);
247 
248   PairingRequestView preqv = PairingRequestView::Create(pairing_request);
249   PairingResponseView prspv = PairingResponseView::Create(pairing_response);
250 
251   preqv.IsValid();
252   prspv.IsValid();
253   std::array<uint8_t, 3> iocapA{static_cast<uint8_t>(preqv.GetIoCapability()),
254                                 static_cast<uint8_t>(preqv.GetOobDataFlag()), preqv.GetAuthReq()};
255   std::array<uint8_t, 3> iocapB{static_cast<uint8_t>(prspv.GetIoCapability()),
256                                 static_cast<uint8_t>(prspv.GetOobDataFlag()), prspv.GetAuthReq()};
257 
258   Octet16 Ea = crypto_toolbox::f6(mac_key, Na, Nb, rb, iocapA.data(), a, b);
259   Octet16 Eb = crypto_toolbox::f6(mac_key, Nb, Na, ra, iocapB.data(), b, a);
260 
261   std::optional<bluetooth::security::CommandView> dh_key_pkt = WaitForOutgoingL2capPacket();
262   EXPECT_TRUE(dh_key_pkt.has_value());
263   EXPECT_EQ(Code::PAIRING_DH_KEY_CHECK, dh_key_pkt->GetCode());
264   auto pdhkcv = PairingDhKeyCheckView::Create(dh_key_pkt.value());
265   pdhkcv.IsValid();
266   EXPECT_EQ(pdhkcv.GetDhKeyCheck(), Ea);
267 
268   pairing_handler->OnCommandView(BuilderToView(PairingDhKeyCheckBuilder::Create(Eb)));
269 
270   // Phase 2 finished
271   // We don't care for the rest of the flow, let it die.
272 }
273 
274 InitialInformations initial_informations_trsi{
275     .my_role = hci::Role::CENTRAL,
276     .my_connection_address = hci::AddressWithType(),
277     .my_identity_address = {{}, hci::AddressType::PUBLIC_DEVICE_ADDRESS},
278     .my_identity_resolving_key =
279         {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
280 
281     .myPairingCapabilities = {.io_capability = IoCapability::NO_INPUT_NO_OUTPUT,
282                               .oob_data_flag = OobDataFlag::NOT_PRESENT,
283                               .auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
284                               .maximum_encryption_key_size = 16,
285                               .initiator_key_distribution = 0x03,
286                               .responder_key_distribution = 0x03},
287 
288     .remotely_initiated = true,
289     .remote_connection_address = hci::AddressWithType(),
290     .user_interface = &uiMock,
291     .le_security_interface = &leSecurityMock,
292     .OnPairingFinished = OnPairingFinished,
293 };
294 
295 /* This test verifies that when remote peripheral device sends security request , and user
296  * does accept the prompt, we do send pairing request */
TEST_F(PairingHandlerUnitTest,test_remote_peripheral_initiating)297 TEST_F(PairingHandlerUnitTest, test_remote_peripheral_initiating) {
298   initial_informations_trsi.proper_l2cap_interface = up_buffer_.get();
299   initial_informations_trsi.l2cap_handler = handler_;
300   initial_informations_trsi.user_interface_handler = handler_;
301 
302   std::unique_ptr<PairingHandlerLe> pairing_handler =
303       std::make_unique<PairingHandlerLe>(PairingHandlerLe::ACCEPT_PROMPT, initial_informations_trsi);
304 
305   // Simulate user accepting the pairing in UI
306   pairing_handler->OnUiAction(PairingEvent::PAIRING_ACCEPTED, 0x01 /* Non-zero value means success */);
307 
308   std::optional<bluetooth::security::CommandView> pairing_request_pkt = WaitForOutgoingL2capPacket();
309   EXPECT_TRUE(pairing_request_pkt.has_value());
310   EXPECT_EQ(Code::PAIRING_REQUEST, pairing_request_pkt->GetCode());
311 
312   // We don't care for the rest of the flow, let it die.
313   pairing_handler.reset();
314 }
315 
316 InitialInformations initial_informations_trmi{
317     .my_role = hci::Role::PERIPHERAL,
318     .my_connection_address = hci::AddressWithType(),
319     .my_identity_address = {{}, hci::AddressType::PUBLIC_DEVICE_ADDRESS},
320     .my_identity_resolving_key =
321         {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
322 
323     .myPairingCapabilities = {.io_capability = IoCapability::NO_INPUT_NO_OUTPUT,
324                               .oob_data_flag = OobDataFlag::NOT_PRESENT,
325                               .auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
326                               .maximum_encryption_key_size = 16,
327                               .initiator_key_distribution = 0x03,
328                               .responder_key_distribution = 0x03},
329 
330     .remotely_initiated = true,
331     .remote_connection_address = hci::AddressWithType(),
332     .pairing_request = PairingRequestView::Create(BuilderToView(PairingRequestBuilder::Create(
333         IoCapability::NO_INPUT_NO_OUTPUT,
334         OobDataFlag::NOT_PRESENT,
335         AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
336         16,
337         0x03,
338         0x03))),
339     .user_interface = &uiMock,
340     .le_security_interface = &leSecurityMock,
341 
342     .OnPairingFinished = OnPairingFinished,
343 };
344 
345 /* This test verifies that when remote device sends pairing request, and user does accept the prompt, we do send proper
346  * reply back */
TEST_F(PairingHandlerUnitTest,test_remote_central_initiating)347 TEST_F(PairingHandlerUnitTest, test_remote_central_initiating) {
348   initial_informations_trmi.proper_l2cap_interface = up_buffer_.get();
349   initial_informations_trmi.l2cap_handler = handler_;
350   initial_informations_trmi.user_interface_handler = handler_;
351 
352   std::unique_ptr<PairingHandlerLe> pairing_handler =
353       std::make_unique<PairingHandlerLe>(PairingHandlerLe::ACCEPT_PROMPT, initial_informations_trmi);
354 
355   // Simulate user accepting the pairing in UI
356   pairing_handler->OnUiAction(PairingEvent::PAIRING_ACCEPTED, 0x01 /* Non-zero value means success */);
357 
358   std::optional<bluetooth::security::CommandView> pairing_response_pkt = WaitForOutgoingL2capPacket();
359   EXPECT_TRUE(pairing_response_pkt.has_value());
360   EXPECT_EQ(Code::PAIRING_RESPONSE, pairing_response_pkt->GetCode());
361   // Phase 1 finished.
362 
363   // We don't care for the rest of the flow, it's handled in in other tests. let it die.
364   pairing_handler.reset();
365 }
366 
367 }  // namespace security
368 }  // namespace bluetooth
369