Jakub Pawlowski | 72c8dcc | 2019-09-06 16:33:21 +0200 | [diff] [blame] | 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 | |
Jakub Pawlowski | e79714e | 2019-10-14 14:49:55 +0200 | [diff] [blame] | 19 | #include "security/pairing_handler_le.h" |
Jakub Pawlowski | 72c8dcc | 2019-09-06 16:33:21 +0200 | [diff] [blame] | 20 | |
| 21 | namespace bluetooth { |
Jakub Pawlowski | e79714e | 2019-10-14 14:49:55 +0200 | [diff] [blame] | 22 | namespace security { |
Jakub Pawlowski | 72c8dcc | 2019-09-06 16:33:21 +0200 | [diff] [blame] | 23 | |
| 24 | void PairingHandlerLe::PairingMain(InitialInformations i) { |
| 25 | LOG_INFO("Pairing Started"); |
| 26 | |
| 27 | if (i.remotely_initiated) { |
| 28 | LOG_INFO("Was remotely initiated, presenting user with the accept prompt"); |
| 29 | i.ui_handler->DisplayPairingPrompt(i.remote_connection_address, i.remote_name); |
| 30 | |
| 31 | // If pairing was initiated by remote device, wait for the user to accept |
| 32 | // the request from the UI. |
| 33 | LOG_INFO("Waiting for the prompt response"); |
| 34 | std::optional<PairingEvent> pairingAccepted = WaitUiPairingAccept(); |
| 35 | if (!pairingAccepted || pairingAccepted->ui_value == 0) { |
| 36 | LOG_INFO("User either did not accept the remote pairing, or the prompt timed out"); |
| 37 | SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::UNSPECIFIED_REASON)); |
| 38 | i.OnPairingFinished(PairingFailure("User either did not accept the remote pairing, or the prompt timed out")); |
| 39 | return; |
| 40 | } |
| 41 | |
| 42 | LOG_INFO("Pairing prompt accepted"); |
| 43 | } |
| 44 | |
| 45 | /************************************************ PHASE 1 *********************************************************/ |
| 46 | Phase1ResultOrFailure phase_1_result = ExchangePairingFeature(i); |
| 47 | if (std::holds_alternative<PairingFailure>(phase_1_result)) { |
| 48 | LOG_WARN("Pairing failed in phase 1"); |
| 49 | // We already send pairing fialed in lower layer. Which one should do that ? how about disconneciton? |
| 50 | // SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::UNSPECIFIED_REASON)); |
| 51 | // TODO: disconnect? |
| 52 | i.OnPairingFinished(std::get<PairingFailure>(phase_1_result)); |
| 53 | return; |
| 54 | } |
| 55 | |
| 56 | auto [pairing_request, pairing_response] = std::get<Phase1Result>(phase_1_result); |
| 57 | |
| 58 | /************************************************ PHASE 2 *********************************************************/ |
| 59 | if (pairing_request.GetAuthReq() & pairing_response.GetAuthReq() & AuthReqMaskSc) { |
| 60 | // 2.3.5.6 LE Secure Connections pairing phase 2 |
| 61 | LOG_INFO("Pairing Phase 2 LE Secure connections Started"); |
| 62 | |
| 63 | /* |
| 64 | TODO: what to do with this piece of spec ? |
| 65 | If Secure Connections pairing has been initiated over BR/EDR, the |
| 66 | following fields of the SM Pairing Request PDU are reserved for future use: |
| 67 | • the IO Capability field, |
| 68 | • the OOB data flag field, and |
| 69 | • all bits in the Auth Req field except the CT2 bit. |
| 70 | */ |
| 71 | |
| 72 | OobDataFlag remote_have_oob_data = |
| 73 | IAmMaster(i) ? pairing_response.GetOobDataFlag() : pairing_request.GetOobDataFlag(); |
| 74 | |
| 75 | auto key_exchange_result = ExchangePublicKeys(i, remote_have_oob_data); |
| 76 | if (std::holds_alternative<PairingFailure>(key_exchange_result)) { |
| 77 | LOG_ERROR("Public key exchange failed"); |
| 78 | i.OnPairingFinished(std::get<PairingFailure>(key_exchange_result)); |
| 79 | return; |
| 80 | } |
| 81 | auto [PKa, PKb, dhkey] = std::get<KeyExchangeResult>(key_exchange_result); |
| 82 | |
| 83 | // Public key exchange finished, Diffie-Hellman key computed. |
| 84 | |
| 85 | Stage1ResultOrFailure stage1result = DoSecureConnectionsStage1(i, PKa, PKb, pairing_request, pairing_response); |
| 86 | if (std::holds_alternative<PairingFailure>(stage1result)) { |
| 87 | i.OnPairingFinished(std::get<PairingFailure>(stage1result)); |
| 88 | return; |
| 89 | } |
| 90 | |
| 91 | Stage2ResultOrFailure stage_2_result = DoSecureConnectionsStage2(i, PKa, PKb, pairing_request, pairing_response, |
| 92 | std::get<Stage1Result>(stage1result), dhkey); |
| 93 | if (std::holds_alternative<PairingFailure>(stage_2_result)) { |
| 94 | i.OnPairingFinished(std::get<PairingFailure>(stage_2_result)); |
| 95 | return; |
| 96 | } |
| 97 | |
| 98 | Octet16 ltk = std::get<Octet16>(stage_2_result); |
| 99 | if (IAmMaster(i)) { |
| 100 | SendHciLeStartEncryption(i, i.connection_handle, {0}, {0}, ltk); |
| 101 | } |
| 102 | |
| 103 | } else { |
| 104 | // 2.3.5.5 LE legacy pairing phase 2 |
| 105 | LOG_INFO("Pairing Phase 2 LE legacy pairing Started"); |
| 106 | |
| 107 | LegacyStage1ResultOrFailure stage1result = DoLegacyStage1(i, pairing_request, pairing_response); |
| 108 | if (std::holds_alternative<PairingFailure>(stage1result)) { |
| 109 | LOG_ERROR("Phase 1 failed"); |
| 110 | i.OnPairingFinished(std::get<PairingFailure>(stage1result)); |
| 111 | return; |
| 112 | } |
| 113 | |
| 114 | Octet16 tk = std::get<Octet16>(stage1result); |
| 115 | StkOrFailure stage2result = DoLegacyStage2(i, pairing_request, pairing_response, tk); |
| 116 | if (std::holds_alternative<PairingFailure>(stage2result)) { |
| 117 | LOG_ERROR("stage 2 failed"); |
| 118 | i.OnPairingFinished(std::get<PairingFailure>(stage2result)); |
| 119 | return; |
| 120 | } |
| 121 | |
| 122 | Octet16 stk = std::get<Octet16>(stage2result); |
| 123 | if (IAmMaster(i)) { |
| 124 | SendHciLeStartEncryption(i, i.connection_handle, {0}, {0}, stk); |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | /************************************************ PHASE 3 *********************************************************/ |
| 129 | auto encryption_change_result = WaitEncryptionChanged(); |
| 130 | if (std::holds_alternative<PairingFailure>(encryption_change_result)) { |
| 131 | LOG_ERROR("encryption change failed"); |
| 132 | i.OnPairingFinished(std::get<PairingFailure>(encryption_change_result)); |
| 133 | return; |
| 134 | } else if (std::holds_alternative<EncryptionChangeView>(encryption_change_result)) { |
| 135 | EncryptionChangeView encryption_changed = std::get<EncryptionChangeView>(encryption_change_result); |
| 136 | if (encryption_changed.GetStatus() != hci::ErrorCode::SUCCESS || |
| 137 | encryption_changed.GetEncryptionEnabled() != hci::EncryptionEnabled::ON) { |
| 138 | i.OnPairingFinished(PairingFailure("Encryption change failed")); |
| 139 | } |
| 140 | } else if (std::holds_alternative<EncryptionKeyRefreshCompleteView>(encryption_change_result)) { |
| 141 | EncryptionKeyRefreshCompleteView encryption_changed = |
| 142 | std::get<EncryptionKeyRefreshCompleteView>(encryption_change_result); |
| 143 | if (encryption_changed.GetStatus() != hci::ErrorCode::SUCCESS) { |
| 144 | i.OnPairingFinished(PairingFailure("Encryption key refresh failed")); |
| 145 | } |
| 146 | } else { |
| 147 | i.OnPairingFinished(PairingFailure("Unknown case of encryption change result")); |
| 148 | } |
| 149 | |
| 150 | DistributedKeysOrFailure keyExchangeStatus = DistributeKeys(i, pairing_response); |
| 151 | if (std::holds_alternative<PairingFailure>(keyExchangeStatus)) { |
| 152 | i.OnPairingFinished(std::get<PairingFailure>(keyExchangeStatus)); |
| 153 | LOG_ERROR("Key exchange failed"); |
| 154 | return; |
| 155 | } |
| 156 | |
| 157 | i.OnPairingFinished(PairingResult{ |
| 158 | .connection_address = i.remote_connection_address, |
| 159 | .distributed_keys = std::get<DistributedKeys>(keyExchangeStatus), |
| 160 | }); |
| 161 | } |
| 162 | |
| 163 | Phase1ResultOrFailure PairingHandlerLe::ExchangePairingFeature(const InitialInformations& i) { |
| 164 | LOG_INFO("Phase 1 start"); |
| 165 | |
| 166 | if (IAmMaster(i)) { |
| 167 | // Send Pairing Request |
| 168 | const auto& x = i.myPairingCapabilities; |
| 169 | auto pairing_request_builder = |
| 170 | PairingRequestBuilder::Create(x.io_capability, x.oob_data_flag, x.auth_req, x.maximum_encryption_key_size, |
| 171 | x.initiator_key_distribution, x.responder_key_distribution); |
| 172 | // basically pairing_request = myPairingCapabilities; |
| 173 | |
| 174 | // Convert builder to view |
| 175 | std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>(); |
| 176 | BitInserter it(*packet_bytes); |
| 177 | pairing_request_builder->Serialize(it); |
| 178 | PacketView<kLittleEndian> packet_bytes_view(packet_bytes); |
| 179 | auto temp_cmd_view = CommandView::Create(packet_bytes_view); |
| 180 | auto pairing_request = PairingRequestView::Create(temp_cmd_view); |
| 181 | ASSERT(pairing_request.IsValid()); |
| 182 | |
| 183 | LOG_INFO("Sending Pairing Request"); |
| 184 | SendL2capPacket(i, std::move(pairing_request_builder)); |
| 185 | |
| 186 | LOG_INFO("Waiting for Pairing Response"); |
| 187 | auto response = WaitPairingResponse(); |
| 188 | |
| 189 | /* There is a potential collision where the slave initiates the pairing at the same time we initiate it, by sending |
| 190 | * security request. */ |
| 191 | if (std::holds_alternative<PairingFailure>(response) && |
| 192 | std::get<PairingFailure>(response).received_code_ == Code::SECURITY_REQUEST) { |
| 193 | LOG_INFO("Received security request, waiting for Pairing Response again..."); |
| 194 | response = WaitPairingResponse(); |
| 195 | } |
| 196 | |
| 197 | if (std::holds_alternative<PairingFailure>(response)) { |
| 198 | // TODO: should the failure reason be different in some cases ? How about |
| 199 | // when we lost connection ? Don't send anything at all, or have L2CAP |
| 200 | // layer ignore it? |
| 201 | SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::UNSPECIFIED_REASON)); |
| 202 | return std::get<PairingFailure>(response); |
| 203 | } |
| 204 | |
| 205 | auto pairing_response = std::get<PairingResponseView>(response); |
| 206 | |
| 207 | LOG_INFO("Phase 1 finish"); |
| 208 | return Phase1Result{pairing_request, pairing_response}; |
| 209 | } else { |
| 210 | std::optional<PairingRequestView> pairing_request; |
| 211 | |
| 212 | if (i.remotely_initiated) { |
| 213 | if (!i.pairing_request.has_value()) { |
| 214 | return PairingFailure("You must pass PairingRequest as a initial information to slave!"); |
| 215 | } |
| 216 | |
| 217 | pairing_request = i.pairing_request.value(); |
| 218 | |
| 219 | if (!pairing_request->IsValid()) return PairingFailure("Malformed PairingRequest"); |
| 220 | } else { |
| 221 | SendL2capPacket(i, SecurityRequestBuilder::Create(i.myPairingCapabilities.auth_req)); |
| 222 | |
| 223 | LOG_INFO("Waiting for Pairing Request"); |
| 224 | auto request = WaitPairingRequest(); |
| 225 | if (std::holds_alternative<PairingFailure>(request)) { |
| 226 | LOG_INFO("%s", std::get<PairingFailure>(request).message.c_str()); |
| 227 | SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::UNSPECIFIED_REASON)); |
| 228 | return std::get<PairingFailure>(request); |
| 229 | } |
| 230 | |
| 231 | pairing_request = std::get<PairingRequestView>(request); |
| 232 | } |
| 233 | |
| 234 | // Send Pairing Request |
| 235 | const auto& x = i.myPairingCapabilities; |
| 236 | // basically pairing_response_builder = my_first_packet; |
| 237 | // We are not allowed to enable bits that the remote did not allow us to set in initiator_key_dist and |
| 238 | // responder_key_distribution |
| 239 | auto pairing_response_builder = |
| 240 | PairingResponseBuilder::Create(x.io_capability, x.oob_data_flag, x.auth_req, x.maximum_encryption_key_size, |
| 241 | x.initiator_key_distribution & pairing_request->GetInitiatorKeyDistribution(), |
| 242 | x.responder_key_distribution & pairing_request->GetResponderKeyDistribution()); |
| 243 | |
| 244 | // Convert builder to view |
| 245 | std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>(); |
| 246 | BitInserter it(*packet_bytes); |
| 247 | pairing_response_builder->Serialize(it); |
| 248 | PacketView<kLittleEndian> packet_bytes_view(packet_bytes); |
| 249 | auto temp_cmd_view = CommandView::Create(packet_bytes_view); |
| 250 | auto pairing_response = PairingResponseView::Create(temp_cmd_view); |
| 251 | ASSERT(pairing_response.IsValid()); |
| 252 | |
| 253 | LOG_INFO("Sending Pairing Response"); |
| 254 | SendL2capPacket(i, std::move(pairing_response_builder)); |
| 255 | |
| 256 | LOG_INFO("Phase 1 finish"); |
| 257 | return Phase1Result{pairing_request.value(), pairing_response}; |
| 258 | } |
| 259 | } |
| 260 | |
| 261 | DistributedKeysOrFailure PairingHandlerLe::DistributeKeys(const InitialInformations& i, |
| 262 | const PairingResponseView& pairing_response) { |
| 263 | LOG_INFO("Key distribution start"); |
| 264 | |
| 265 | const uint8_t& keys_i_receive = |
| 266 | IAmMaster(i) ? pairing_response.GetResponderKeyDistribution() : pairing_response.GetInitiatorKeyDistribution(); |
| 267 | const uint8_t& keys_i_send = |
| 268 | IAmMaster(i) ? pairing_response.GetInitiatorKeyDistribution() : pairing_response.GetResponderKeyDistribution(); |
| 269 | |
| 270 | // TODO: obtain actual values! |
| 271 | |
| 272 | Octet16 my_ltk = {0}; |
| 273 | uint16_t my_ediv{0}; |
| 274 | std::array<uint8_t, 8> my_rand = {0}; |
| 275 | |
| 276 | Octet16 my_irk = {0x01}; |
| 277 | Address my_identity_address; |
| 278 | AddrType my_identity_address_type = AddrType::PUBLIC; |
| 279 | Octet16 my_signature_key{0}; |
| 280 | |
| 281 | if (IAmMaster(i)) { |
| 282 | // EncKey is unused for LE Secure Connections |
| 283 | DistributedKeysOrFailure keys = ReceiveKeys(keys_i_receive); |
| 284 | if (std::holds_alternative<PairingFailure>(keys)) { |
| 285 | return keys; |
| 286 | } |
| 287 | |
| 288 | SendKeys(i, keys_i_send, my_ltk, my_ediv, my_rand, my_irk, my_identity_address, my_identity_address_type, |
| 289 | my_signature_key); |
| 290 | LOG_INFO("Key distribution finish"); |
| 291 | return keys; |
| 292 | } else { |
| 293 | SendKeys(i, keys_i_send, my_ltk, my_ediv, my_rand, my_irk, my_identity_address, my_identity_address_type, |
| 294 | my_signature_key); |
| 295 | |
| 296 | DistributedKeysOrFailure keys = ReceiveKeys(keys_i_receive); |
| 297 | if (std::holds_alternative<PairingFailure>(keys)) { |
| 298 | return keys; |
| 299 | } |
| 300 | LOG_INFO("Key distribution finish"); |
| 301 | return keys; |
| 302 | } |
| 303 | } |
| 304 | |
| 305 | DistributedKeysOrFailure PairingHandlerLe::ReceiveKeys(const uint8_t& keys_i_receive) { |
| 306 | std::optional<Octet16> ltk; /* Legacy only */ |
| 307 | std::optional<uint16_t> ediv; /* Legacy only */ |
| 308 | std::optional<std::array<uint8_t, 8>> rand; /* Legacy only */ |
| 309 | std::optional<Address> identity_address; |
| 310 | AddrType identity_address_type; |
| 311 | std::optional<Octet16> irk; |
| 312 | std::optional<Octet16> signature_key; |
| 313 | |
| 314 | if (keys_i_receive & KeyMaskEnc) { |
| 315 | { |
| 316 | auto packet = WaitEncryptionInformation(); |
| 317 | if (std::holds_alternative<PairingFailure>(packet)) { |
| 318 | LOG_ERROR(" Was expecting Encryption Information but did not receive!"); |
| 319 | return std::get<PairingFailure>(packet); |
| 320 | } |
| 321 | ltk = std::get<EncryptionInformationView>(packet).GetLongTermKey(); |
| 322 | } |
| 323 | |
| 324 | { |
| 325 | auto packet = WaitMasterIdentification(); |
| 326 | if (std::holds_alternative<PairingFailure>(packet)) { |
| 327 | LOG_ERROR(" Was expecting Master Identification but did not receive!"); |
| 328 | return std::get<PairingFailure>(packet); |
| 329 | } |
| 330 | ediv = std::get<MasterIdentificationView>(packet).GetEdiv(); |
| 331 | rand = std::get<MasterIdentificationView>(packet).GetRand(); |
| 332 | } |
| 333 | } |
| 334 | |
| 335 | if (keys_i_receive & KeyMaskId) { |
| 336 | auto packet = WaitIdentityInformation(); |
| 337 | if (std::holds_alternative<PairingFailure>(packet)) { |
| 338 | LOG_ERROR(" Was expecting Identity Information but did not receive!"); |
| 339 | return std::get<PairingFailure>(packet); |
| 340 | } |
| 341 | |
| 342 | LOG_INFO("Received Identity Information"); |
| 343 | irk = std::get<IdentityInformationView>(packet).GetIdentityResolvingKey(); |
| 344 | |
| 345 | auto iapacket = WaitIdentityAddressInformation(); |
| 346 | if (std::holds_alternative<PairingFailure>(iapacket)) { |
| 347 | LOG_ERROR( |
| 348 | "Was expecting Identity Address Information but did " |
| 349 | "not receive!"); |
| 350 | return std::get<PairingFailure>(iapacket); |
| 351 | } |
| 352 | LOG_INFO("Received Identity Address Information"); |
| 353 | identity_address = std::get<IdentityAddressInformationView>(iapacket).GetBdAddr(); |
| 354 | identity_address_type = std::get<IdentityAddressInformationView>(iapacket).GetAddrType(); |
| 355 | } |
| 356 | |
| 357 | if (keys_i_receive & KeyMaskSign) { |
| 358 | auto packet = WaitSigningInformation(); |
| 359 | if (std::holds_alternative<PairingFailure>(packet)) { |
| 360 | LOG_ERROR(" Was expecting Signing Information but did not receive!"); |
| 361 | return std::get<PairingFailure>(packet); |
| 362 | } |
| 363 | |
| 364 | LOG_INFO("Received Signing Information"); |
| 365 | signature_key = std::get<SigningInformationView>(packet).GetSignatureKey(); |
| 366 | } |
| 367 | |
| 368 | return DistributedKeys{ltk, ediv, rand, identity_address, identity_address_type, irk, signature_key}; |
| 369 | } |
| 370 | |
| 371 | void PairingHandlerLe::SendKeys(const InitialInformations& i, const uint8_t& keys_i_send, Octet16 ltk, uint16_t ediv, |
| 372 | std::array<uint8_t, 8> rand, Octet16 irk, Address identity_address, |
| 373 | AddrType identity_addres_type, Octet16 signature_key) { |
| 374 | if (keys_i_send & KeyMaskEnc) { |
| 375 | SendL2capPacket(i, EncryptionInformationBuilder::Create(ltk)); |
| 376 | SendL2capPacket(i, MasterIdentificationBuilder::Create(ediv, rand)); |
| 377 | } |
| 378 | |
| 379 | if (keys_i_send & KeyMaskId) { |
| 380 | SendL2capPacket(i, IdentityInformationBuilder::Create(irk)); |
| 381 | |
| 382 | SendL2capPacket(i, IdentityAddressInformationBuilder::Create(identity_addres_type, identity_address)); |
| 383 | } |
| 384 | |
| 385 | if (keys_i_send & KeyMaskSign) { |
| 386 | SendL2capPacket(i, SigningInformationBuilder::Create(signature_key)); |
| 387 | } |
| 388 | } |
| 389 | |
Jakub Pawlowski | e79714e | 2019-10-14 14:49:55 +0200 | [diff] [blame] | 390 | } // namespace security |
Jakub Pawlowski | 72c8dcc | 2019-09-06 16:33:21 +0200 | [diff] [blame] | 391 | } // namespace bluetooth |