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