fido_ble_connection.cc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "device/fido/cable/fido_ble_connection.h"
  5. #include <algorithm>
  6. #include <ostream>
  7. #include <utility>
  8. #include "base/barrier_closure.h"
  9. #include "base/bind.h"
  10. #include "base/callback_helpers.h"
  11. #include "base/logging.h"
  12. #include "base/strings/stringprintf.h"
  13. #include "base/threading/thread_task_runner_handle.h"
  14. #include "build/build_config.h"
  15. #include "components/device_event_log/device_event_log.h"
  16. #include "device/bluetooth/bluetooth_gatt_connection.h"
  17. #include "device/bluetooth/bluetooth_gatt_notify_session.h"
  18. #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
  19. #include "device/bluetooth/bluetooth_remote_gatt_service.h"
  20. #include "device/bluetooth/public/cpp/bluetooth_uuid.h"
  21. #include "device/fido/cable/fido_ble_uuids.h"
  22. namespace device {
  23. namespace {
  24. using ServiceRevisionsCallback =
  25. base::OnceCallback<void(std::vector<FidoBleConnection::ServiceRevision>)>;
  26. constexpr const char* ToString(BluetoothDevice::ConnectErrorCode error_code) {
  27. switch (error_code) {
  28. case BluetoothDevice::ERROR_AUTH_CANCELED:
  29. return "ERROR_AUTH_CANCELED";
  30. case BluetoothDevice::ERROR_AUTH_FAILED:
  31. return "ERROR_AUTH_FAILED";
  32. case BluetoothDevice::ERROR_AUTH_REJECTED:
  33. return "ERROR_AUTH_REJECTED";
  34. case BluetoothDevice::ERROR_AUTH_TIMEOUT:
  35. return "ERROR_AUTH_TIMEOUT";
  36. case BluetoothDevice::ERROR_FAILED:
  37. return "ERROR_FAILED";
  38. case BluetoothDevice::ERROR_INPROGRESS:
  39. return "ERROR_INPROGRESS";
  40. case BluetoothDevice::ERROR_UNKNOWN:
  41. return "ERROR_UNKNOWN";
  42. case BluetoothDevice::ERROR_UNSUPPORTED_DEVICE:
  43. return "ERROR_UNSUPPORTED_DEVICE";
  44. default:
  45. NOTREACHED();
  46. return "";
  47. }
  48. }
  49. constexpr const char* ToString(BluetoothGattService::GattErrorCode error_code) {
  50. switch (error_code) {
  51. case BluetoothGattService::GATT_ERROR_UNKNOWN:
  52. return "GATT_ERROR_UNKNOWN";
  53. case BluetoothGattService::GATT_ERROR_FAILED:
  54. return "GATT_ERROR_FAILED";
  55. case BluetoothGattService::GATT_ERROR_IN_PROGRESS:
  56. return "GATT_ERROR_IN_PROGRESS";
  57. case BluetoothGattService::GATT_ERROR_INVALID_LENGTH:
  58. return "GATT_ERROR_INVALID_LENGTH";
  59. case BluetoothGattService::GATT_ERROR_NOT_PERMITTED:
  60. return "GATT_ERROR_NOT_PERMITTED";
  61. case BluetoothGattService::GATT_ERROR_NOT_AUTHORIZED:
  62. return "GATT_ERROR_NOT_AUTHORIZED";
  63. case BluetoothGattService::GATT_ERROR_NOT_PAIRED:
  64. return "GATT_ERROR_NOT_PAIRED";
  65. case BluetoothGattService::GATT_ERROR_NOT_SUPPORTED:
  66. return "GATT_ERROR_NOT_SUPPORTED";
  67. default:
  68. NOTREACHED();
  69. return "";
  70. }
  71. }
  72. std::ostream& operator<<(std::ostream& os,
  73. FidoBleConnection::ServiceRevision revision) {
  74. switch (revision) {
  75. case FidoBleConnection::ServiceRevision::kU2f11:
  76. return os << "U2F 1.1";
  77. case FidoBleConnection::ServiceRevision::kU2f12:
  78. return os << "U2F 1.2";
  79. case FidoBleConnection::ServiceRevision::kFido2:
  80. return os << "FIDO2";
  81. }
  82. NOTREACHED();
  83. return os;
  84. }
  85. void OnWriteRemoteCharacteristic(FidoBleConnection::WriteCallback callback) {
  86. FIDO_LOG(DEBUG) << "Writing Remote Characteristic Succeeded.";
  87. std::move(callback).Run(true);
  88. }
  89. void OnWriteRemoteCharacteristicError(
  90. FidoBleConnection::WriteCallback callback,
  91. BluetoothGattService::GattErrorCode error_code) {
  92. FIDO_LOG(ERROR) << "Writing Remote Characteristic Failed: "
  93. << ToString(error_code);
  94. std::move(callback).Run(false);
  95. }
  96. void OnReadServiceRevisionBitfield(
  97. ServiceRevisionsCallback callback,
  98. absl::optional<device::BluetoothGattService::GattErrorCode> error_code,
  99. const std::vector<uint8_t>& value) {
  100. if (error_code.has_value()) {
  101. FIDO_LOG(ERROR) << "Error while reading Service Revision Bitfield: "
  102. << ToString(error_code.value());
  103. std::move(callback).Run({});
  104. return;
  105. }
  106. if (value.empty()) {
  107. FIDO_LOG(DEBUG) << "Service Revision Bitfield is empty.";
  108. std::move(callback).Run({});
  109. return;
  110. }
  111. if (value.size() != 1u) {
  112. FIDO_LOG(DEBUG) << "Service Revision Bitfield has unexpected size: "
  113. << value.size() << ". Ignoring all but the first byte.";
  114. }
  115. const uint8_t bitset = value[0];
  116. if (bitset & 0x1F) {
  117. FIDO_LOG(DEBUG) << "Service Revision Bitfield has unexpected bits set: "
  118. << base::StringPrintf("0x%02X", bitset)
  119. << ". Ignoring all but the first three bits.";
  120. }
  121. std::vector<FidoBleConnection::ServiceRevision> service_revisions;
  122. for (auto revision : {FidoBleConnection::ServiceRevision::kU2f11,
  123. FidoBleConnection::ServiceRevision::kU2f12,
  124. FidoBleConnection::ServiceRevision::kFido2}) {
  125. if (bitset & static_cast<uint8_t>(revision)) {
  126. FIDO_LOG(DEBUG) << "Detected Support for " << revision << ".";
  127. service_revisions.push_back(revision);
  128. }
  129. }
  130. std::move(callback).Run(std::move(service_revisions));
  131. }
  132. } // namespace
  133. FidoBleConnection::FidoBleConnection(BluetoothAdapter* adapter,
  134. std::string device_address,
  135. BluetoothUUID service_uuid,
  136. ReadCallback read_callback)
  137. : adapter_(adapter),
  138. address_(std::move(device_address)),
  139. read_callback_(std::move(read_callback)),
  140. service_uuid_(service_uuid) {
  141. DCHECK(adapter_);
  142. adapter_->AddObserver(this);
  143. DCHECK(!address_.empty());
  144. }
  145. FidoBleConnection::~FidoBleConnection() {
  146. adapter_->RemoveObserver(this);
  147. }
  148. BluetoothDevice* FidoBleConnection::GetBleDevice() {
  149. return adapter_->GetDevice(address());
  150. }
  151. const BluetoothDevice* FidoBleConnection::GetBleDevice() const {
  152. return adapter_->GetDevice(address());
  153. }
  154. void FidoBleConnection::Connect(ConnectionCallback callback) {
  155. auto* device = GetBleDevice();
  156. if (!device) {
  157. FIDO_LOG(ERROR) << "Failed to get Device.";
  158. base::ThreadTaskRunnerHandle::Get()->PostTask(
  159. FROM_HERE, base::BindOnce(std::move(callback), false));
  160. return;
  161. }
  162. pending_connection_callback_ = std::move(callback);
  163. FIDO_LOG(DEBUG) << "Creating a GATT connection...";
  164. device->CreateGattConnection(
  165. base::BindOnce(&FidoBleConnection::OnCreateGattConnection,
  166. weak_factory_.GetWeakPtr()),
  167. BluetoothUUID(kGoogleCableUUID128));
  168. }
  169. void FidoBleConnection::ReadControlPointLength(
  170. ControlPointLengthCallback callback) {
  171. const auto* fido_service = GetFidoService();
  172. if (!fido_service) {
  173. base::ThreadTaskRunnerHandle::Get()->PostTask(
  174. FROM_HERE, base::BindOnce(std::move(callback), absl::nullopt));
  175. return;
  176. }
  177. if (!control_point_length_id_) {
  178. FIDO_LOG(ERROR) << "Failed to get Control Point Length.";
  179. base::ThreadTaskRunnerHandle::Get()->PostTask(
  180. FROM_HERE, base::BindOnce(std::move(callback), absl::nullopt));
  181. return;
  182. }
  183. BluetoothRemoteGattCharacteristic* control_point_length =
  184. fido_service->GetCharacteristic(*control_point_length_id_);
  185. if (!control_point_length) {
  186. FIDO_LOG(ERROR) << "No Control Point Length characteristic present.";
  187. base::ThreadTaskRunnerHandle::Get()->PostTask(
  188. FROM_HERE, base::BindOnce(std::move(callback), absl::nullopt));
  189. return;
  190. }
  191. FIDO_LOG(DEBUG) << "Read Control Point Length";
  192. control_point_length->ReadRemoteCharacteristic(
  193. base::BindOnce(OnReadControlPointLength, std::move(callback)));
  194. }
  195. void FidoBleConnection::WriteControlPoint(const std::vector<uint8_t>& data,
  196. WriteCallback callback) {
  197. const auto* fido_service = GetFidoService();
  198. if (!fido_service) {
  199. base::ThreadTaskRunnerHandle::Get()->PostTask(
  200. FROM_HERE, base::BindOnce(std::move(callback), false));
  201. return;
  202. }
  203. if (!control_point_id_) {
  204. FIDO_LOG(ERROR) << "Failed to get Control Point.";
  205. base::ThreadTaskRunnerHandle::Get()->PostTask(
  206. FROM_HERE, base::BindOnce(std::move(callback), false));
  207. return;
  208. }
  209. BluetoothRemoteGattCharacteristic* control_point =
  210. fido_service->GetCharacteristic(*control_point_id_);
  211. if (!control_point) {
  212. FIDO_LOG(ERROR) << "Control Point characteristic not present.";
  213. base::ThreadTaskRunnerHandle::Get()->PostTask(
  214. FROM_HERE, base::BindOnce(std::move(callback), false));
  215. return;
  216. }
  217. // Attempt a write without response for performance reasons. Fall back to a
  218. // confirmed write when the characteristic does not provide the required
  219. // property.
  220. BluetoothRemoteGattCharacteristic::WriteType write_type =
  221. (control_point->GetProperties() &
  222. BluetoothRemoteGattCharacteristic::PROPERTY_WRITE_WITHOUT_RESPONSE)
  223. ? BluetoothRemoteGattCharacteristic::WriteType::kWithoutResponse
  224. : BluetoothRemoteGattCharacteristic::WriteType::kWithResponse;
  225. FIDO_LOG(DEBUG) << "Wrote Control Point.";
  226. auto split_callback = base::SplitOnceCallback(std::move(callback));
  227. control_point->WriteRemoteCharacteristic(
  228. data, write_type,
  229. base::BindOnce(OnWriteRemoteCharacteristic,
  230. std::move(split_callback.first)),
  231. base::BindOnce(OnWriteRemoteCharacteristicError,
  232. std::move(split_callback.second)));
  233. }
  234. void FidoBleConnection::OnCreateGattConnection(
  235. std::unique_ptr<BluetoothGattConnection> connection,
  236. absl::optional<BluetoothDevice::ConnectErrorCode> error_code) {
  237. FIDO_LOG(DEBUG) << "GATT connection created";
  238. DCHECK(pending_connection_callback_);
  239. if (error_code.has_value()) {
  240. FIDO_LOG(ERROR) << "CreateGattConnection() failed: "
  241. << ToString(error_code.value());
  242. base::ThreadTaskRunnerHandle::Get()->PostTask(
  243. FROM_HERE,
  244. base::BindOnce(std::move(pending_connection_callback_), false));
  245. return;
  246. }
  247. connection_ = std::move(connection);
  248. BluetoothDevice* device = adapter_->GetDevice(address_);
  249. if (!device) {
  250. FIDO_LOG(ERROR) << "Failed to get Device.";
  251. base::ThreadTaskRunnerHandle::Get()->PostTask(
  252. FROM_HERE,
  253. base::BindOnce(std::move(pending_connection_callback_), false));
  254. return;
  255. }
  256. if (!device->IsGattServicesDiscoveryComplete()) {
  257. FIDO_LOG(DEBUG) << "Waiting for GATT service discovery to complete";
  258. waiting_for_gatt_discovery_ = true;
  259. return;
  260. }
  261. ConnectToFidoService();
  262. }
  263. void FidoBleConnection::ConnectToFidoService() {
  264. FIDO_LOG(EVENT) << "Attempting to connect to a Fido service.";
  265. DCHECK(pending_connection_callback_);
  266. const auto* fido_service = GetFidoService();
  267. if (!fido_service) {
  268. FIDO_LOG(ERROR) << "Failed to get Fido Service.";
  269. base::ThreadTaskRunnerHandle::Get()->PostTask(
  270. FROM_HERE,
  271. base::BindOnce(std::move(pending_connection_callback_), false));
  272. return;
  273. }
  274. for (const auto* characteristic : fido_service->GetCharacteristics()) {
  275. std::string uuid = characteristic->GetUUID().canonical_value();
  276. if (uuid == kFidoControlPointLengthUUID) {
  277. control_point_length_id_ = characteristic->GetIdentifier();
  278. FIDO_LOG(DEBUG) << "Got Fido Control Point Length: "
  279. << *control_point_length_id_;
  280. continue;
  281. }
  282. if (uuid == kFidoControlPointUUID) {
  283. control_point_id_ = characteristic->GetIdentifier();
  284. FIDO_LOG(DEBUG) << "Got Fido Control Point: " << *control_point_id_;
  285. continue;
  286. }
  287. if (uuid == kFidoStatusUUID) {
  288. status_id_ = characteristic->GetIdentifier();
  289. FIDO_LOG(DEBUG) << "Got Fido Status: " << *status_id_;
  290. continue;
  291. }
  292. if (uuid == kFidoServiceRevisionUUID) {
  293. service_revision_id_ = characteristic->GetIdentifier();
  294. FIDO_LOG(DEBUG) << "Got Fido Service Revision: " << *service_revision_id_;
  295. continue;
  296. }
  297. if (uuid == kFidoServiceRevisionBitfieldUUID) {
  298. service_revision_bitfield_id_ = characteristic->GetIdentifier();
  299. FIDO_LOG(DEBUG) << "Got Fido Service Revision Bitfield: "
  300. << *service_revision_bitfield_id_;
  301. continue;
  302. }
  303. FIDO_LOG(DEBUG) << "Unknown FIDO service characteristic: " << uuid;
  304. }
  305. if (!control_point_length_id_ || !control_point_id_ || !status_id_ ||
  306. (!service_revision_id_ && !service_revision_bitfield_id_)) {
  307. FIDO_LOG(ERROR) << "Fido Characteristics missing.";
  308. base::ThreadTaskRunnerHandle::Get()->PostTask(
  309. FROM_HERE,
  310. base::BindOnce(std::move(pending_connection_callback_), false));
  311. return;
  312. }
  313. // In case the bitfield characteristic is present, the client has to select a
  314. // supported version by writing the corresponding bit. Reference:
  315. // https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-client-to-authenticator-protocol-v2.0-rd-20180702.html#ble-protocol-overview
  316. if (service_revision_bitfield_id_) {
  317. // This callback is only repeating so that it can be bound to two different
  318. // callbacks.
  319. auto callback = base::BindRepeating(
  320. &FidoBleConnection::OnReadServiceRevisions, weak_factory_.GetWeakPtr());
  321. fido_service->GetCharacteristic(*service_revision_bitfield_id_)
  322. ->ReadRemoteCharacteristic(
  323. base::BindOnce(OnReadServiceRevisionBitfield, callback));
  324. return;
  325. }
  326. StartNotifySession();
  327. }
  328. void FidoBleConnection::OnReadServiceRevisions(
  329. std::vector<ServiceRevision> service_revisions) {
  330. DCHECK(pending_connection_callback_);
  331. if (service_revisions.empty()) {
  332. FIDO_LOG(ERROR) << "Could not obtain Service Revisions.";
  333. std::move(pending_connection_callback_).Run(false);
  334. return;
  335. }
  336. // Write the most recent supported service revision back to the
  337. // characteristic. Note that this information is currently not used in another
  338. // way, as we will still attempt a CTAP GetInfo() command, even if only U2F is
  339. // supported.
  340. // TODO(https://crbug.com/780078): Consider short circuiting to the
  341. // U2F logic if FIDO2 is not supported.
  342. DCHECK_EQ(
  343. *std::min_element(service_revisions.begin(), service_revisions.end()),
  344. service_revisions.back());
  345. WriteServiceRevision(service_revisions.back());
  346. }
  347. void FidoBleConnection::WriteServiceRevision(ServiceRevision service_revision) {
  348. auto callback = base::BindOnce(&FidoBleConnection::OnServiceRevisionWritten,
  349. weak_factory_.GetWeakPtr());
  350. const auto* fido_service = GetFidoService();
  351. if (!fido_service) {
  352. base::ThreadTaskRunnerHandle::Get()->PostTask(
  353. FROM_HERE, base::BindOnce(std::move(callback), false));
  354. return;
  355. }
  356. auto split_callback = base::SplitOnceCallback(std::move(callback));
  357. DCHECK(service_revision_bitfield_id_);
  358. fido_service->GetCharacteristic(*service_revision_bitfield_id_)
  359. ->WriteRemoteCharacteristic(
  360. {static_cast<uint8_t>(service_revision)},
  361. BluetoothRemoteGattCharacteristic::WriteType::kWithResponse,
  362. base::BindOnce(OnWriteRemoteCharacteristic,
  363. std::move(split_callback.first)),
  364. base::BindOnce(OnWriteRemoteCharacteristicError,
  365. std::move(split_callback.second)));
  366. }
  367. void FidoBleConnection::OnServiceRevisionWritten(bool success) {
  368. DCHECK(pending_connection_callback_);
  369. if (success) {
  370. FIDO_LOG(DEBUG) << "Service Revision successfully written.";
  371. StartNotifySession();
  372. return;
  373. }
  374. FIDO_LOG(ERROR) << "Failed to write Service Revision.";
  375. std::move(pending_connection_callback_).Run(false);
  376. }
  377. void FidoBleConnection::StartNotifySession() {
  378. DCHECK(pending_connection_callback_);
  379. const auto* fido_service = GetFidoService();
  380. if (!fido_service) {
  381. base::ThreadTaskRunnerHandle::Get()->PostTask(
  382. FROM_HERE,
  383. base::BindOnce(std::move(pending_connection_callback_), false));
  384. return;
  385. }
  386. DCHECK(status_id_);
  387. fido_service->GetCharacteristic(*status_id_)
  388. ->StartNotifySession(
  389. base::BindOnce(&FidoBleConnection::OnStartNotifySession,
  390. weak_factory_.GetWeakPtr()),
  391. base::BindOnce(&FidoBleConnection::OnStartNotifySessionError,
  392. weak_factory_.GetWeakPtr()));
  393. }
  394. void FidoBleConnection::OnStartNotifySession(
  395. std::unique_ptr<BluetoothGattNotifySession> notify_session) {
  396. notify_session_ = std::move(notify_session);
  397. FIDO_LOG(DEBUG) << "Created notification session. Connection established.";
  398. std::move(pending_connection_callback_).Run(true);
  399. }
  400. void FidoBleConnection::OnStartNotifySessionError(
  401. BluetoothGattService::GattErrorCode error_code) {
  402. FIDO_LOG(ERROR) << "StartNotifySession() failed: " << ToString(error_code);
  403. std::move(pending_connection_callback_).Run(false);
  404. }
  405. void FidoBleConnection::DeviceAddressChanged(BluetoothAdapter* adapter,
  406. BluetoothDevice* device,
  407. const std::string& old_address) {
  408. if (address_ == old_address)
  409. address_ = device->GetAddress();
  410. }
  411. void FidoBleConnection::GattCharacteristicValueChanged(
  412. BluetoothAdapter* adapter,
  413. BluetoothRemoteGattCharacteristic* characteristic,
  414. const std::vector<uint8_t>& value) {
  415. if (characteristic->GetIdentifier() != status_id_)
  416. return;
  417. FIDO_LOG(DEBUG) << "Status characteristic value changed.";
  418. read_callback_.Run(value);
  419. }
  420. void FidoBleConnection::GattServicesDiscovered(BluetoothAdapter* adapter,
  421. BluetoothDevice* device) {
  422. if (adapter != adapter_ || device->GetAddress() != address_) {
  423. return;
  424. }
  425. FIDO_LOG(DEBUG) << "GATT services discovered for " << device->GetAddress();
  426. if (waiting_for_gatt_discovery_) {
  427. waiting_for_gatt_discovery_ = false;
  428. ConnectToFidoService();
  429. }
  430. }
  431. const BluetoothRemoteGattService* FidoBleConnection::GetFidoService() {
  432. if (!connection_ || !connection_->IsConnected()) {
  433. FIDO_LOG(ERROR) << "No BLE connection.";
  434. return nullptr;
  435. }
  436. DCHECK_EQ(address_, connection_->GetDeviceAddress());
  437. BluetoothDevice* device = GetBleDevice();
  438. for (const auto* service : device->GetGattServices()) {
  439. if (service->GetUUID() == service_uuid_) {
  440. return service;
  441. }
  442. }
  443. FIDO_LOG(ERROR) << "No Fido service present.";
  444. return nullptr;
  445. }
  446. // static
  447. void FidoBleConnection::OnReadControlPointLength(
  448. ControlPointLengthCallback callback,
  449. absl::optional<device::BluetoothGattService::GattErrorCode> error_code,
  450. const std::vector<uint8_t>& value) {
  451. if (error_code.has_value()) {
  452. FIDO_LOG(ERROR) << "Error reading Control Point Length: "
  453. << ToString(error_code.value());
  454. std::move(callback).Run(absl::nullopt);
  455. return;
  456. }
  457. if (value.size() != 2) {
  458. FIDO_LOG(ERROR) << "Wrong Control Point Length: " << value.size()
  459. << " bytes";
  460. std::move(callback).Run(absl::nullopt);
  461. return;
  462. }
  463. uint16_t length = (value[0] << 8) | value[1];
  464. FIDO_LOG(DEBUG) << "Control Point Length: " << length;
  465. std::move(callback).Run(length);
  466. }
  467. } // namespace device