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 <bluetooth/log.h>
20
21 #include "hci/octets.h"
22 #include "os/rand.h"
23 #include "security/pairing_handler_le.h"
24
25 using bluetooth::os::GenerateRandom;
26
27 namespace bluetooth {
28 namespace security {
29
30 using hci::Octet16;
31
DoLegacyStage1(const InitialInformations & i,const PairingRequestView & pairing_request,const PairingResponseView & pairing_response)32 LegacyStage1ResultOrFailure PairingHandlerLe::DoLegacyStage1(const InitialInformations& i,
33 const PairingRequestView& pairing_request,
34 const PairingResponseView& pairing_response) {
35 if (((pairing_request.GetAuthReq() | pairing_response.GetAuthReq()) & AuthReqMaskMitm) == 0) {
36 // If both devices have not set MITM option, Just Works shall be used
37 return LegacyJustWorks();
38 }
39
40 if (pairing_request.GetOobDataFlag() == OobDataFlag::PRESENT &&
41 pairing_response.GetOobDataFlag() == OobDataFlag::PRESENT) {
42 // OobDataFlag remote_oob_flag = IAmCentral(i) ? pairing_response.GetOobDataFlag() :
43 // pairing_request.GetOobDataFlag(); OobDataFlag my_oob_flag = IAmCentral(i) ? pairing_request.GetOobDataFlag() :
44 // pairing_response.GetOobDataFlag();
45 return LegacyOutOfBand(i);
46 }
47
48 const auto& iom = pairing_request.GetIoCapability();
49 const auto& ios = pairing_response.GetIoCapability();
50
51 if (iom == IoCapability::NO_INPUT_NO_OUTPUT || ios == IoCapability::NO_INPUT_NO_OUTPUT) {
52 return LegacyJustWorks();
53 }
54
55 if ((iom == IoCapability::DISPLAY_ONLY || iom == IoCapability::DISPLAY_YES_NO) &&
56 (ios == IoCapability::DISPLAY_ONLY || ios == IoCapability::DISPLAY_YES_NO)) {
57 return LegacyJustWorks();
58 }
59
60 // This if() should not be needed, these are only combinations left.
61 if (iom == IoCapability::KEYBOARD_DISPLAY || iom == IoCapability::KEYBOARD_ONLY ||
62 ios == IoCapability::KEYBOARD_DISPLAY || ios == IoCapability::KEYBOARD_ONLY) {
63 IoCapability my_iocaps = IAmCentral(i) ? iom : ios;
64 IoCapability remote_iocaps = IAmCentral(i) ? ios : iom;
65 return LegacyPasskeyEntry(i, my_iocaps, remote_iocaps);
66 }
67
68 // We went through all possble combinations.
69 log::fatal("This should never happen");
70 return LegacyJustWorks();
71 }
72
LegacyJustWorks()73 LegacyStage1ResultOrFailure PairingHandlerLe::LegacyJustWorks() {
74 log::info("Legacy Just Works start");
75 return Octet16{0};
76 }
77
LegacyPasskeyEntry(const InitialInformations & i,const IoCapability & my_iocaps,const IoCapability & remote_iocaps)78 LegacyStage1ResultOrFailure PairingHandlerLe::LegacyPasskeyEntry(const InitialInformations& i,
79 const IoCapability& my_iocaps,
80 const IoCapability& remote_iocaps) {
81 bool i_am_displaying = false;
82 if (my_iocaps == IoCapability::DISPLAY_ONLY || my_iocaps == IoCapability::DISPLAY_YES_NO) {
83 i_am_displaying = true;
84 } else if (
85 IAmCentral(i) && remote_iocaps == IoCapability::KEYBOARD_DISPLAY && my_iocaps == IoCapability::KEYBOARD_DISPLAY) {
86 i_am_displaying = true;
87 } else if (my_iocaps == IoCapability::KEYBOARD_DISPLAY && remote_iocaps == IoCapability::KEYBOARD_ONLY) {
88 i_am_displaying = true;
89 }
90
91 log::info("Passkey Entry start {}", i_am_displaying ? "displaying" : "accepting");
92
93 uint32_t passkey;
94 if (i_am_displaying) {
95 // generate passkey in a valid range
96 passkey = GenerateRandom();
97 passkey &= 0x0fffff; /* maximum 20 significant bits */
98 constexpr uint32_t PASSKEY_MAX = 999999;
99 if (passkey > PASSKEY_MAX) passkey >>= 1;
100
101 ConfirmationData data(i.remote_connection_address, i.remote_name, passkey);
102 i.user_interface_handler->Post(
103 common::BindOnce(&UI::DisplayConfirmValue, common::Unretained(i.user_interface), data));
104 } else {
105 ConfirmationData data(i.remote_connection_address, i.remote_name);
106 i.user_interface_handler->Post(
107 common::BindOnce(&UI::DisplayEnterPasskeyDialog, common::Unretained(i.user_interface), data));
108 std::optional<PairingEvent> response = WaitUiPasskey();
109 if (!response) return PairingFailure("Passkey did not arrive!");
110
111 passkey = response->ui_value;
112 }
113
114 Octet16 tk{0};
115 tk[0] = (uint8_t)(passkey);
116 tk[1] = (uint8_t)(passkey >> 8);
117 tk[2] = (uint8_t)(passkey >> 16);
118 tk[3] = (uint8_t)(passkey >> 24);
119
120 log::info("Passkey Entry finish");
121 return tk;
122 }
123
LegacyOutOfBand(const InitialInformations & i)124 LegacyStage1ResultOrFailure PairingHandlerLe::LegacyOutOfBand(const InitialInformations& i) {
125 return i.remote_oob_data->security_manager_tk_value;
126 }
127
DoLegacyStage2(const InitialInformations & i,const PairingRequestView & pairing_request,const PairingResponseView & pairing_response,const Octet16 & tk)128 StkOrFailure PairingHandlerLe::DoLegacyStage2(const InitialInformations& i, const PairingRequestView& pairing_request,
129 const PairingResponseView& pairing_response, const Octet16& tk) {
130 log::info("Legacy Step 2 start");
131 std::vector<uint8_t> preq(pairing_request.begin(), pairing_request.end());
132 std::vector<uint8_t> pres(pairing_response.begin(), pairing_response.end());
133
134 Octet16 mrand, srand;
135 if (IAmCentral(i)) {
136 mrand = GenerateRandom<16>();
137
138 // log::info("{} tk = {}", IAmCentral(i), base::HexEncode(tk.data(), tk.size()));
139 // log::info("{} mrand = {}", IAmCentral(i), base::HexEncode(mrand.data(), mrand.size()));
140 // log::info("{} pres = {}", IAmCentral(i), base::HexEncode(pres.data(), pres.size()));
141 // log::info("{} preq = {}", IAmCentral(i), base::HexEncode(preq.data(), preq.size()));
142
143 Octet16 mconfirm = crypto_toolbox::c1(
144 tk,
145 mrand,
146 preq.data(),
147 pres.data(),
148 (uint8_t)i.my_connection_address.GetAddressType(),
149 i.my_connection_address.GetAddress().data(),
150 (uint8_t)i.remote_connection_address.GetAddressType(),
151 i.remote_connection_address.GetAddress().data());
152
153 // log::info("{} mconfirm = {}", IAmCentral(i), base::HexEncode(mconfirm.data(),
154 // mconfirm.size()));
155
156 log::info("Central sends Mconfirm");
157 SendL2capPacket(i, PairingConfirmBuilder::Create(mconfirm));
158
159 log::info("Central waits for the Sconfirm");
160 auto sconfirm_pkt = WaitPairingConfirm();
161 if (std::holds_alternative<PairingFailure>(sconfirm_pkt)) {
162 return std::get<PairingFailure>(sconfirm_pkt);
163 }
164 Octet16 sconfirm = std::get<PairingConfirmView>(sconfirm_pkt).GetConfirmValue();
165
166 log::info("Central sends Mrand");
167 SendL2capPacket(i, PairingRandomBuilder::Create(mrand));
168
169 log::info("Central waits for Srand");
170 auto random_pkt = WaitPairingRandom();
171 if (std::holds_alternative<PairingFailure>(random_pkt)) {
172 return std::get<PairingFailure>(random_pkt);
173 }
174 srand = std::get<PairingRandomView>(random_pkt).GetRandomValue();
175
176 // log::info("{} srand = {}", IAmCentral(i), base::HexEncode(srand.data(), srand.size()));
177
178 Octet16 sconfirm_generated = crypto_toolbox::c1(
179 tk,
180 srand,
181 preq.data(),
182 pres.data(),
183 (uint8_t)i.my_connection_address.GetAddressType(),
184 i.my_connection_address.GetAddress().data(),
185 (uint8_t)i.remote_connection_address.GetAddressType(),
186 i.remote_connection_address.GetAddress().data());
187
188 if (sconfirm != sconfirm_generated) {
189 log::info("sconfirm does not match generated value");
190
191 SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::CONFIRM_VALUE_FAILED));
192 return PairingFailure("sconfirm does not match generated value");
193 }
194 } else {
195 srand = GenerateRandom<16>();
196
197 std::vector<uint8_t> preq(pairing_request.begin(), pairing_request.end());
198 std::vector<uint8_t> pres(pairing_response.begin(), pairing_response.end());
199
200 Octet16 sconfirm = crypto_toolbox::c1(
201 tk,
202 srand,
203 preq.data(),
204 pres.data(),
205 (uint8_t)i.remote_connection_address.GetAddressType(),
206 i.remote_connection_address.GetAddress().data(),
207 (uint8_t)i.my_connection_address.GetAddressType(),
208 i.my_connection_address.GetAddress().data());
209
210 log::info("Peripheral waits for the Mconfirm");
211 auto mconfirm_pkt = WaitPairingConfirm();
212 if (std::holds_alternative<PairingFailure>(mconfirm_pkt)) {
213 return std::get<PairingFailure>(mconfirm_pkt);
214 }
215 Octet16 mconfirm = std::get<PairingConfirmView>(mconfirm_pkt).GetConfirmValue();
216
217 log::info("Peripheral sends Sconfirm");
218 SendL2capPacket(i, PairingConfirmBuilder::Create(sconfirm));
219
220 log::info("Peripheral waits for Mrand");
221 auto random_pkt = WaitPairingRandom();
222 if (std::holds_alternative<PairingFailure>(random_pkt)) {
223 return std::get<PairingFailure>(random_pkt);
224 }
225 mrand = std::get<PairingRandomView>(random_pkt).GetRandomValue();
226
227 Octet16 mconfirm_generated = crypto_toolbox::c1(
228 tk,
229 mrand,
230 preq.data(),
231 pres.data(),
232 (uint8_t)i.remote_connection_address.GetAddressType(),
233 i.remote_connection_address.GetAddress().data(),
234 (uint8_t)i.my_connection_address.GetAddressType(),
235 i.my_connection_address.GetAddress().data());
236
237 if (mconfirm != mconfirm_generated) {
238 log::info("mconfirm does not match generated value");
239 SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::CONFIRM_VALUE_FAILED));
240 return PairingFailure("mconfirm does not match generated value");
241 }
242
243 log::info("Peripheral sends Srand");
244 SendL2capPacket(i, PairingRandomBuilder::Create(srand));
245 }
246
247 log::info("Legacy stage 2 finish");
248
249 /* STK */
250 return crypto_toolbox::s1(tk, mrand, srand);
251 }
252 } // namespace security
253 } // namespace bluetooth
254