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