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