v2_authenticator.cc 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161
  1. // Copyright 2020 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/v2_authenticator.h"
  5. #include "base/feature_list.h"
  6. #include "base/memory/raw_ptr.h"
  7. #include "base/memory/weak_ptr.h"
  8. #include "base/sequence_checker.h"
  9. #include "base/strings/string_number_conversions.h"
  10. #include "base/threading/sequenced_task_runner_handle.h"
  11. #include "base/time/time.h"
  12. #include "components/cbor/diagnostic_writer.h"
  13. #include "components/cbor/reader.h"
  14. #include "components/cbor/values.h"
  15. #include "components/cbor/writer.h"
  16. #include "components/device_event_log/device_event_log.h"
  17. #include "crypto/random.h"
  18. #include "device/fido/cable/v2_handshake.h"
  19. #include "device/fido/cable/websocket_adapter.h"
  20. #include "device/fido/cbor_extract.h"
  21. #include "device/fido/features.h"
  22. #include "device/fido/fido_constants.h"
  23. #include "device/fido/fido_parsing_utils.h"
  24. #include "device/fido/public_key_credential_descriptor.h"
  25. #include "device/fido/public_key_credential_params.h"
  26. #include "device/fido/public_key_credential_rp_entity.h"
  27. #include "device/fido/public_key_credential_user_entity.h"
  28. #include "net/base/isolation_info.h"
  29. #include "net/cookies/site_for_cookies.h"
  30. #include "net/traffic_annotation/network_traffic_annotation.h"
  31. #include "services/network/public/mojom/network_context.mojom.h"
  32. #include "third_party/abseil-cpp/absl/types/variant.h"
  33. #include "third_party/blink/public/mojom/webauthn/authenticator.mojom.h"
  34. #include "third_party/boringssl/src/include/openssl/aes.h"
  35. #include "third_party/boringssl/src/include/openssl/ec_key.h"
  36. #include "third_party/boringssl/src/include/openssl/obj.h"
  37. namespace device {
  38. namespace cablev2 {
  39. namespace authenticator {
  40. using device::CtapDeviceResponseCode;
  41. using device::CtapRequestCommand;
  42. using device::cbor_extract::IntKey;
  43. using device::cbor_extract::Is;
  44. using device::cbor_extract::Map;
  45. using device::cbor_extract::StepOrByte;
  46. using device::cbor_extract::Stop;
  47. using device::cbor_extract::StringKey;
  48. namespace {
  49. // kTimeoutSeconds is the timeout that is put into the parameters that are
  50. // passed up to the platform.
  51. const int kTimeoutSeconds = 60;
  52. constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
  53. net::DefineNetworkTrafficAnnotation("cablev2_websocket_from_authenticator",
  54. R"(semantics {
  55. sender: "Phone as a Security Key"
  56. description:
  57. "Chrome on a phone can communicate with other devices for the "
  58. "purpose of using the phone as a security key. This WebSocket "
  59. "connection is made to a Google service that aids in the exchange "
  60. "of data with the other device. The service carries only "
  61. "end-to-end encrypted data where the keys are shared directly "
  62. "between the two devices via QR code and Bluetooth broadcast."
  63. trigger:
  64. "The user scans a QR code, displayed on the other device, and "
  65. "confirms their desire to communicate with it."
  66. data: "Only encrypted data that the service does not have the keys "
  67. "for."
  68. destination: GOOGLE_OWNED_SERVICE
  69. }
  70. policy {
  71. cookies_allowed: NO
  72. setting: "Not controlled by a setting because the operation is "
  73. "triggered by significant user action."
  74. policy_exception_justification:
  75. "No policy provided because the operation is triggered by "
  76. " significant user action. No background activity occurs."
  77. })");
  78. struct MakeCredRequest {
  79. // All fields below are not a raw_ptr<T> because cbor_extract.cc would
  80. // cast the raw_ptr<T> to a void*, skipping an AddRef() call and causing a
  81. // ref-counting mismatch.
  82. RAW_PTR_EXCLUSION const std::vector<uint8_t>* client_data_hash;
  83. RAW_PTR_EXCLUSION const std::string* rp_id;
  84. RAW_PTR_EXCLUSION const std::string* rp_name;
  85. RAW_PTR_EXCLUSION const std::vector<uint8_t>* user_id;
  86. RAW_PTR_EXCLUSION const std::string* user_name;
  87. RAW_PTR_EXCLUSION const std::string* user_display_name;
  88. RAW_PTR_EXCLUSION const cbor::Value::ArrayValue* cred_params;
  89. RAW_PTR_EXCLUSION const cbor::Value::ArrayValue* excluded_credentials;
  90. RAW_PTR_EXCLUSION const bool* resident_key;
  91. };
  92. static constexpr StepOrByte<MakeCredRequest> kMakeCredParseSteps[] = {
  93. // clang-format off
  94. ELEMENT(Is::kRequired, MakeCredRequest, client_data_hash),
  95. IntKey<MakeCredRequest>(1),
  96. Map<MakeCredRequest>(),
  97. IntKey<MakeCredRequest>(2),
  98. ELEMENT(Is::kRequired, MakeCredRequest, rp_id),
  99. StringKey<MakeCredRequest>(), 'i', 'd', '\0',
  100. ELEMENT(Is::kRequired, MakeCredRequest, rp_name),
  101. StringKey<MakeCredRequest>(), 'n', 'a', 'm', 'e', '\0',
  102. Stop<MakeCredRequest>(),
  103. Map<MakeCredRequest>(),
  104. IntKey<MakeCredRequest>(3),
  105. ELEMENT(Is::kRequired, MakeCredRequest, user_id),
  106. StringKey<MakeCredRequest>(), 'i', 'd', '\0',
  107. ELEMENT(Is::kRequired, MakeCredRequest, user_name),
  108. StringKey<MakeCredRequest>(), 'n', 'a', 'm', 'e', '\0',
  109. ELEMENT(Is::kRequired, MakeCredRequest, user_display_name),
  110. StringKey<MakeCredRequest>(), 'd', 'i', 's', 'p', 'l', 'a', 'y',
  111. 'N', 'a', 'm', 'e', '\0',
  112. Stop<MakeCredRequest>(),
  113. ELEMENT(Is::kRequired, MakeCredRequest, cred_params),
  114. IntKey<MakeCredRequest>(4),
  115. ELEMENT(Is::kOptional, MakeCredRequest, excluded_credentials),
  116. IntKey<MakeCredRequest>(5),
  117. Map<MakeCredRequest>(Is::kOptional),
  118. IntKey<MakeCredRequest>(7),
  119. ELEMENT(Is::kOptional, MakeCredRequest, resident_key),
  120. StringKey<MakeCredRequest>(), 'r', 'k', '\0',
  121. Stop<MakeCredRequest>(),
  122. Stop<MakeCredRequest>(),
  123. // clang-format on
  124. };
  125. struct AttestationObject {
  126. // All fields below are not a raw_ptr<T> because cbor_extract.cc would
  127. // cast the raw_ptr<T> to a void*, skipping an AddRef() call and causing a
  128. // ref-counting mismatch.
  129. RAW_PTR_EXCLUSION const std::string* fmt;
  130. RAW_PTR_EXCLUSION const std::vector<uint8_t>* auth_data;
  131. RAW_PTR_EXCLUSION const cbor::Value* statement;
  132. };
  133. static constexpr StepOrByte<AttestationObject> kAttObjParseSteps[] = {
  134. // clang-format off
  135. ELEMENT(Is::kRequired, AttestationObject, fmt),
  136. StringKey<AttestationObject>(), 'f', 'm', 't', '\0',
  137. ELEMENT(Is::kRequired, AttestationObject, auth_data),
  138. StringKey<AttestationObject>(), 'a', 'u', 't', 'h', 'D', 'a', 't', 'a',
  139. '\0',
  140. ELEMENT(Is::kRequired, AttestationObject, statement),
  141. StringKey<AttestationObject>(), 'a', 't', 't', 'S', 't', 'm', 't', '\0',
  142. Stop<AttestationObject>(),
  143. // clang-format on
  144. };
  145. struct GetAssertionRequest {
  146. // All fields below are not a raw_ptr<T> because cbor_extract.cc would
  147. // cast the raw_ptr<T> to a void*, skipping an AddRef() call and causing a
  148. // ref-counting mismatch.
  149. RAW_PTR_EXCLUSION const std::string* rp_id;
  150. RAW_PTR_EXCLUSION const std::vector<uint8_t>* client_data_hash;
  151. RAW_PTR_EXCLUSION const cbor::Value::ArrayValue* allowed_credentials;
  152. };
  153. static constexpr StepOrByte<GetAssertionRequest> kGetAssertionParseSteps[] = {
  154. // clang-format off
  155. ELEMENT(Is::kRequired, GetAssertionRequest, rp_id),
  156. IntKey<GetAssertionRequest>(1),
  157. ELEMENT(Is::kRequired, GetAssertionRequest, client_data_hash),
  158. IntKey<GetAssertionRequest>(2),
  159. ELEMENT(Is::kOptional, GetAssertionRequest, allowed_credentials),
  160. IntKey<GetAssertionRequest>(3),
  161. Stop<GetAssertionRequest>(),
  162. // clang-format on
  163. };
  164. // BuildGetInfoResponse returns a CBOR-encoded getInfo response.
  165. std::vector<uint8_t> BuildGetInfoResponse() {
  166. std::array<uint8_t, device::kAaguidLength> aaguid{};
  167. std::vector<cbor::Value> versions;
  168. versions.emplace_back("FIDO_2_0");
  169. versions.emplace_back("FIDO_2_1");
  170. cbor::Value::MapValue options;
  171. // This code is only invoked if a screen-lock (i.e. user verification) is
  172. // configured on the device. Therefore the 'uv' option is unconditionally
  173. // true.
  174. options.emplace("uv", true);
  175. options.emplace("rk", true);
  176. std::vector<cbor::Value> transports;
  177. transports.emplace_back("cable");
  178. transports.emplace_back("hybrid");
  179. transports.emplace_back("internal");
  180. cbor::Value::MapValue response_map;
  181. response_map.emplace(1, std::move(versions));
  182. response_map.emplace(3, aaguid);
  183. response_map.emplace(4, std::move(options));
  184. response_map.emplace(9, std::move(transports));
  185. return cbor::Writer::Write(cbor::Value(std::move(response_map))).value();
  186. }
  187. std::array<uint8_t, device::cablev2::kNonceSize> RandomNonce() {
  188. std::array<uint8_t, device::cablev2::kNonceSize> ret;
  189. crypto::RandBytes(ret);
  190. return ret;
  191. }
  192. using GeneratePairingDataCallback =
  193. base::OnceCallback<absl::optional<cbor::Value>(
  194. base::span<const uint8_t, device::kP256X962Length> peer_public_key_x962,
  195. device::cablev2::HandshakeHash)>;
  196. // TunnelTransport is a transport that uses WebSockets to talk to a cloud
  197. // service and uses BLE adverts to show proximity.
  198. class TunnelTransport : public Transport {
  199. public:
  200. TunnelTransport(
  201. unsigned protocol_revision,
  202. Platform* platform,
  203. network::mojom::NetworkContext* network_context,
  204. base::span<const uint8_t> secret,
  205. base::span<const uint8_t, device::kP256X962Length> peer_identity,
  206. bool use_new_crypter_construction,
  207. GeneratePairingDataCallback generate_pairing_data)
  208. : protocol_revision_(protocol_revision),
  209. platform_(platform),
  210. tunnel_id_(device::cablev2::Derive<EXTENT(tunnel_id_)>(
  211. secret,
  212. base::span<uint8_t>(),
  213. DerivedValueType::kTunnelID)),
  214. eid_key_(device::cablev2::Derive<EXTENT(eid_key_)>(
  215. secret,
  216. base::span<const uint8_t>(),
  217. device::cablev2::DerivedValueType::kEIDKey)),
  218. network_context_(network_context),
  219. peer_identity_(device::fido_parsing_utils::Materialize(peer_identity)),
  220. generate_pairing_data_(std::move(generate_pairing_data)),
  221. secret_(fido_parsing_utils::Materialize(secret)),
  222. use_new_crypter_construction_(use_new_crypter_construction) {
  223. DCHECK_EQ(state_, State::kNone);
  224. state_ = State::kConnecting;
  225. websocket_client_ = std::make_unique<device::cablev2::WebSocketAdapter>(
  226. base::BindOnce(&TunnelTransport::OnTunnelReady, base::Unretained(this)),
  227. base::BindRepeating(&TunnelTransport::OnTunnelData,
  228. base::Unretained(this)));
  229. target_ = device::cablev2::tunnelserver::GetNewTunnelURL(kTunnelServer,
  230. tunnel_id_);
  231. }
  232. TunnelTransport(
  233. unsigned protocol_revision,
  234. Platform* platform,
  235. network::mojom::NetworkContext* network_context,
  236. base::span<const uint8_t> secret,
  237. base::span<const uint8_t, device::cablev2::kClientNonceSize> client_nonce,
  238. std::array<uint8_t, device::cablev2::kRoutingIdSize> routing_id,
  239. base::span<const uint8_t, 16> tunnel_id,
  240. bssl::UniquePtr<EC_KEY> local_identity)
  241. : protocol_revision_(protocol_revision),
  242. platform_(platform),
  243. tunnel_id_(fido_parsing_utils::Materialize(tunnel_id)),
  244. eid_key_(device::cablev2::Derive<EXTENT(eid_key_)>(
  245. secret,
  246. client_nonce,
  247. device::cablev2::DerivedValueType::kEIDKey)),
  248. network_context_(network_context),
  249. secret_(fido_parsing_utils::Materialize(secret)),
  250. local_identity_(std::move(local_identity)),
  251. use_new_crypter_construction_(protocol_revision_ >= 1) {
  252. DCHECK_EQ(state_, State::kNone);
  253. state_ = State::kConnectingPaired;
  254. websocket_client_ = std::make_unique<device::cablev2::WebSocketAdapter>(
  255. base::BindOnce(&TunnelTransport::OnTunnelReady, base::Unretained(this)),
  256. base::BindRepeating(&TunnelTransport::OnTunnelData,
  257. base::Unretained(this)));
  258. target_ = device::cablev2::tunnelserver::GetConnectURL(
  259. kTunnelServer, routing_id, tunnel_id);
  260. }
  261. // Transport:
  262. void StartReading(
  263. base::RepeatingCallback<void(Update)> update_callback) override {
  264. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  265. DCHECK(!update_callback_);
  266. update_callback_ = std::move(update_callback);
  267. // Delay the WebSocket creation by 250ms. This to measure whether DNS
  268. // errors are reduced in UMA stats. If so, then the network errors that we
  269. // see are probably due to a start-up race.
  270. base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
  271. FROM_HERE,
  272. base::BindOnce(&TunnelTransport::StartWebSocket,
  273. weak_factory_.GetWeakPtr()),
  274. base::Milliseconds(250));
  275. }
  276. void Write(std::vector<uint8_t> data) override {
  277. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  278. DCHECK_EQ(state_, kReady);
  279. if (protocol_revision_ >= 1) {
  280. data.insert(data.begin(), static_cast<uint8_t>(MessageType::kCTAP));
  281. }
  282. if (!crypter_->Encrypt(&data)) {
  283. FIDO_LOG(ERROR) << "Failed to encrypt response";
  284. return;
  285. }
  286. websocket_client_->Write(data);
  287. }
  288. private:
  289. enum State {
  290. kNone,
  291. kConnecting,
  292. kConnectingPaired,
  293. kConnected,
  294. kConnectedPaired,
  295. kReady,
  296. };
  297. void StartWebSocket() {
  298. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  299. network_context_->CreateWebSocket(
  300. target_, {device::kCableWebSocketProtocol}, net::SiteForCookies(),
  301. net::IsolationInfo(), /*additional_headers=*/{},
  302. network::mojom::kBrowserProcessId, url::Origin::Create(target_),
  303. network::mojom::kWebSocketOptionBlockAllCookies,
  304. net::MutableNetworkTrafficAnnotationTag(kTrafficAnnotation),
  305. websocket_client_->BindNewHandshakeClientPipe(),
  306. /*url_loader_network_observer=*/mojo::NullRemote(),
  307. /*auth_handler=*/mojo::NullRemote(),
  308. /*header_client=*/mojo::NullRemote(),
  309. /*throttling_profile_id=*/absl::nullopt);
  310. FIDO_LOG(DEBUG) << "Creating WebSocket to " << target_.spec();
  311. }
  312. void OnTunnelReady(
  313. WebSocketAdapter::Result result,
  314. absl::optional<std::array<uint8_t, device::cablev2::kRoutingIdSize>>
  315. routing_id) {
  316. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  317. DCHECK(state_ == State::kConnecting || state_ == State::kConnectingPaired);
  318. bool ok = (result == WebSocketAdapter::Result::OK);
  319. if (ok && state_ == State::kConnecting && !routing_id) {
  320. FIDO_LOG(ERROR) << "Tunnel server did not specify routing ID";
  321. ok = false;
  322. }
  323. if (!ok) {
  324. FIDO_LOG(ERROR) << "Failed to connect to tunnel server";
  325. update_callback_.Run(Platform::Error::TUNNEL_SERVER_CONNECT_FAILED);
  326. return;
  327. }
  328. FIDO_LOG(DEBUG) << "WebSocket connection established.";
  329. CableEidArray plaintext_eid;
  330. if (state_ == State::kConnecting) {
  331. device::cablev2::eid::Components components;
  332. components.tunnel_server_domain = kTunnelServer;
  333. components.routing_id = *routing_id;
  334. components.nonce = RandomNonce();
  335. plaintext_eid = device::cablev2::eid::FromComponents(components);
  336. state_ = State::kConnected;
  337. } else {
  338. DCHECK_EQ(state_, State::kConnectingPaired);
  339. crypto::RandBytes(plaintext_eid);
  340. // The first byte is reserved to ensure that the format can be changed in
  341. // the future.
  342. plaintext_eid[0] = 0;
  343. state_ = State::kConnectedPaired;
  344. }
  345. ble_advert_ =
  346. platform_->SendBLEAdvert(eid::Encrypt(plaintext_eid, eid_key_));
  347. psk_ = device::cablev2::Derive<EXTENT(psk_)>(
  348. secret_, plaintext_eid, device::cablev2::DerivedValueType::kPSK);
  349. update_callback_.Run(Platform::Status::TUNNEL_SERVER_CONNECT);
  350. }
  351. void OnTunnelData(absl::optional<base::span<const uint8_t>> msg) {
  352. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  353. if (!msg) {
  354. FIDO_LOG(DEBUG) << "WebSocket tunnel closed";
  355. update_callback_.Run(Disconnected::kDisconnected);
  356. return;
  357. }
  358. switch (state_) {
  359. case State::kConnectedPaired:
  360. case State::kConnected: {
  361. std::vector<uint8_t> response;
  362. HandshakeResult result = RespondToHandshake(
  363. psk_, std::move(local_identity_), peer_identity_, *msg, &response);
  364. if (!result) {
  365. FIDO_LOG(ERROR) << "caBLE handshake failure";
  366. update_callback_.Run(Platform::Error::HANDSHAKE_FAILED);
  367. return;
  368. }
  369. FIDO_LOG(DEBUG) << "caBLE handshake complete";
  370. update_callback_.Run(Platform::Status::HANDSHAKE_COMPLETE);
  371. websocket_client_->Write(response);
  372. crypter_ = std::move(result->first);
  373. if (use_new_crypter_construction_) {
  374. crypter_->UseNewConstruction();
  375. }
  376. cbor::Value::MapValue post_handshake_msg;
  377. post_handshake_msg.emplace(1, BuildGetInfoResponse());
  378. if (state_ == State::kConnected && protocol_revision_ < 1) {
  379. // For revision zero, linking information (if any) is included in the
  380. // post-handshake message.
  381. absl::optional<cbor::Value> pairing_data(
  382. std::move(generate_pairing_data_)
  383. .Run(*peer_identity_, result->second));
  384. if (pairing_data) {
  385. post_handshake_msg.emplace(2, std::move(*pairing_data));
  386. }
  387. }
  388. absl::optional<std::vector<uint8_t>> post_handshake_msg_bytes;
  389. if (protocol_revision_ >= 1) {
  390. post_handshake_msg_bytes =
  391. cbor::Writer::Write(cbor::Value(std::move(post_handshake_msg)));
  392. } else {
  393. post_handshake_msg_bytes =
  394. EncodePaddedCBORMap(std::move(post_handshake_msg));
  395. // All post-handshake messages should fit into the same padding
  396. // bucket. It doesn't have to be the smallest one, but that's
  397. // currently true which yields this easy check:
  398. DCHECK_EQ(post_handshake_msg_bytes->size(),
  399. kPostHandshakeMsgPaddingGranularity);
  400. }
  401. if (!post_handshake_msg_bytes) {
  402. FIDO_LOG(ERROR) << "failed to encode post-handshake message";
  403. return;
  404. }
  405. if (!crypter_->Encrypt(&post_handshake_msg_bytes.value())) {
  406. FIDO_LOG(ERROR) << "failed to encrypt post-handshake message";
  407. return;
  408. }
  409. websocket_client_->Write(*post_handshake_msg_bytes);
  410. if (state_ == State::kConnected && protocol_revision_ >= 1) {
  411. // For revision one and greater, linking information can be sent at
  412. // any time. We always send it immediately after the post-handshake
  413. // message.
  414. absl::optional<cbor::Value> pairing_data(
  415. std::move(generate_pairing_data_)
  416. .Run(*peer_identity_, result->second));
  417. // padding_target is the expected size of the plaintext of the update
  418. // message.
  419. constexpr size_t kPaddingTarget = 512;
  420. // padding_length is the length of a bytestring of zeros, included
  421. // just to hit `kPaddingTarget`. `Encrypt` pads to 32 bytes so we can
  422. // be a little sloppy here and use simpler code. Thus we aim at 16
  423. // bytes shy of the target so that it'll be padded up by `Encrypt`.
  424. static_assert(kPaddingTarget % 32 == 0);
  425. size_t padding_length =
  426. kPaddingTarget - 16 -
  427. /* length of CBOR map key */ 1 -
  428. /* length of bytestring overhead, assuming a two-byte length */ 3;
  429. if (pairing_data) {
  430. cbor::Value::MapValue update_msg_for_measurement;
  431. update_msg_for_measurement.emplace(1, pairing_data->Clone());
  432. absl::optional<std::vector<uint8_t>> cbor_bytes =
  433. cbor::Writer::Write(
  434. cbor::Value(std::move(update_msg_for_measurement)));
  435. if (cbor_bytes && cbor_bytes->size() < padding_length) {
  436. padding_length -= cbor_bytes->size();
  437. } else {
  438. DCHECK(false) << cbor_bytes.has_value();
  439. }
  440. }
  441. cbor::Value::MapValue update_msg;
  442. update_msg.emplace(0, std::vector<uint8_t>(padding_length));
  443. if (pairing_data) {
  444. update_msg.emplace(1, std::move(*pairing_data));
  445. }
  446. absl::optional<std::vector<uint8_t>> update_msg_bytes =
  447. cbor::Writer::Write(cbor::Value(std::move(update_msg)));
  448. if (!update_msg_bytes) {
  449. FIDO_LOG(ERROR) << "failed to encode update message";
  450. return;
  451. }
  452. update_msg_bytes->insert(update_msg_bytes->begin(),
  453. static_cast<uint8_t>(MessageType::kUpdate));
  454. if (!crypter_->Encrypt(&update_msg_bytes.value())) {
  455. FIDO_LOG(ERROR) << "failed to encrypt update message";
  456. return;
  457. }
  458. DCHECK_EQ(update_msg_bytes->size(),
  459. kPaddingTarget + /* AES-GCM overhead */ 16);
  460. websocket_client_->Write(*update_msg_bytes);
  461. }
  462. state_ = State::kReady;
  463. break;
  464. }
  465. case State::kReady: {
  466. std::vector<uint8_t> plaintext;
  467. if (!crypter_->Decrypt(*msg, &plaintext)) {
  468. FIDO_LOG(ERROR) << "failed to decrypt caBLE message";
  469. update_callback_.Run(Platform::Error::DECRYPT_FAILURE);
  470. return;
  471. }
  472. if (protocol_revision_ >= 1) {
  473. if (plaintext.empty()) {
  474. FIDO_LOG(ERROR) << "invalid empty message";
  475. update_callback_.Run(Platform::Error::DECRYPT_FAILURE);
  476. return;
  477. }
  478. const uint8_t message_type_byte = plaintext[0];
  479. plaintext.erase(plaintext.begin());
  480. if (message_type_byte >
  481. static_cast<uint8_t>(MessageType::kMaxValue)) {
  482. FIDO_LOG(ERROR) << "unknown message type "
  483. << static_cast<int>(message_type_byte);
  484. update_callback_.Run(Disconnected::kDisconnected);
  485. return;
  486. }
  487. const MessageType message_type =
  488. static_cast<MessageType>(message_type_byte);
  489. switch (message_type) {
  490. case MessageType::kShutdown: {
  491. update_callback_.Run(Disconnected::kDisconnected);
  492. return;
  493. }
  494. case MessageType::kCTAP:
  495. break;
  496. case MessageType::kUpdate:
  497. // The payload is ignored for now. Maybe there will be desktop
  498. // updates defined in the future. But we still check that the
  499. // payload is well-formed.
  500. if (!cbor::Reader::Read(plaintext)) {
  501. FIDO_LOG(ERROR) << "invalid CBOR payload in update message";
  502. update_callback_.Run(Disconnected::kDisconnected);
  503. }
  504. return;
  505. }
  506. }
  507. if (first_message_) {
  508. update_callback_.Run(Platform::Status::REQUEST_RECEIVED);
  509. first_message_ = false;
  510. }
  511. update_callback_.Run(std::move(plaintext));
  512. break;
  513. }
  514. default:
  515. NOTREACHED();
  516. }
  517. }
  518. const unsigned protocol_revision_;
  519. const raw_ptr<Platform> platform_;
  520. State state_ = State::kNone;
  521. const std::array<uint8_t, kTunnelIdSize> tunnel_id_;
  522. const std::array<uint8_t, kEIDKeySize> eid_key_;
  523. std::unique_ptr<WebSocketAdapter> websocket_client_;
  524. std::unique_ptr<Crypter> crypter_;
  525. const raw_ptr<network::mojom::NetworkContext> network_context_;
  526. const absl::optional<std::array<uint8_t, kP256X962Length>> peer_identity_;
  527. std::array<uint8_t, kPSKSize> psk_;
  528. GeneratePairingDataCallback generate_pairing_data_;
  529. const std::vector<uint8_t> secret_;
  530. bssl::UniquePtr<EC_KEY> local_identity_;
  531. const bool use_new_crypter_construction_;
  532. GURL target_;
  533. std::unique_ptr<Platform::BLEAdvert> ble_advert_;
  534. base::RepeatingCallback<void(Update)> update_callback_;
  535. bool first_message_ = true;
  536. SEQUENCE_CHECKER(sequence_checker_);
  537. base::WeakPtrFactory<TunnelTransport> weak_factory_{this};
  538. };
  539. class CTAP2Processor : public Transaction {
  540. public:
  541. CTAP2Processor(std::unique_ptr<Transport> transport,
  542. std::unique_ptr<Platform> platform)
  543. : transport_(std::move(transport)), platform_(std::move(platform)) {
  544. transport_->StartReading(base::BindRepeating(
  545. &CTAP2Processor::OnTransportUpdate, base::Unretained(this)));
  546. }
  547. private:
  548. void OnTransportUpdate(Transport::Update update) {
  549. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  550. if (have_completed_) {
  551. // If the owner of this object doesn't destroy it immediately after an
  552. // error then the transport could continue to send updates. These should
  553. // not be passed through.
  554. return;
  555. }
  556. if (auto* error = absl::get_if<Platform::Error>(&update)) {
  557. have_completed_ = true;
  558. platform_->OnCompleted(*error);
  559. return;
  560. } else if (auto* status = absl::get_if<Platform::Status>(&update)) {
  561. platform_->OnStatus(*status);
  562. return;
  563. } else if (absl::get_if<Transport::Disconnected>(&update)) {
  564. absl::optional<Platform::Error> maybe_error;
  565. if (!transaction_received_) {
  566. maybe_error = Platform::Error::UNEXPECTED_EOF;
  567. } else if (!transaction_done_) {
  568. maybe_error = Platform::Error::EOF_WHILE_PROCESSING;
  569. }
  570. have_completed_ = true;
  571. platform_->OnCompleted(maybe_error);
  572. return;
  573. }
  574. std::vector<uint8_t>& msg = absl::get<std::vector<uint8_t>>(update);
  575. const absl::variant<std::vector<uint8_t>, Platform::Error> result =
  576. ProcessCTAPMessage(msg);
  577. if (const auto* error = absl::get_if<Platform::Error>(&result)) {
  578. have_completed_ = true;
  579. platform_->OnCompleted(*error);
  580. return;
  581. }
  582. const std::vector<uint8_t>& response =
  583. absl::get<std::vector<uint8_t>>(result);
  584. if (response.empty()) {
  585. // Response is pending.
  586. return;
  587. }
  588. transport_->Write(std::move(response));
  589. }
  590. absl::variant<std::vector<uint8_t>, Platform::Error> ProcessCTAPMessage(
  591. base::span<const uint8_t> message_bytes) {
  592. if (message_bytes.empty()) {
  593. return Platform::Error::INVALID_CTAP;
  594. }
  595. const auto command = message_bytes[0];
  596. const auto cbor_bytes = message_bytes.subspan(1);
  597. absl::optional<cbor::Value> payload;
  598. if (!cbor_bytes.empty()) {
  599. payload = cbor::Reader::Read(cbor_bytes);
  600. if (!payload) {
  601. FIDO_LOG(ERROR) << "CBOR decoding failed for "
  602. << base::HexEncode(cbor_bytes);
  603. return Platform::Error::INVALID_CTAP;
  604. }
  605. FIDO_LOG(DEBUG) << "<- (" << base::HexEncode(&command, 1) << ") "
  606. << cbor::DiagnosticWriter::Write(*payload);
  607. } else {
  608. FIDO_LOG(DEBUG) << "<- (" << base::HexEncode(&command, 1)
  609. << ") <no payload>";
  610. }
  611. switch (command) {
  612. case static_cast<uint8_t>(
  613. device::CtapRequestCommand::kAuthenticatorGetInfo): {
  614. if (payload) {
  615. FIDO_LOG(ERROR) << "getInfo command incorrectly contained payload";
  616. return Platform::Error::INVALID_CTAP;
  617. }
  618. absl::optional<std::vector<uint8_t>> response = BuildGetInfoResponse();
  619. if (!response) {
  620. return Platform::Error::INTERNAL_ERROR;
  621. }
  622. response->insert(
  623. response->begin(),
  624. static_cast<uint8_t>(CtapDeviceResponseCode::kSuccess));
  625. return *response;
  626. }
  627. case static_cast<uint8_t>(
  628. device::CtapRequestCommand::kAuthenticatorMakeCredential): {
  629. if (!payload || !payload->is_map()) {
  630. FIDO_LOG(ERROR) << "Invalid makeCredential payload";
  631. return Platform::Error::INVALID_CTAP;
  632. }
  633. MakeCredRequest make_cred_request;
  634. if (!device::cbor_extract::Extract<MakeCredRequest>(
  635. &make_cred_request, kMakeCredParseSteps, payload->GetMap())) {
  636. FIDO_LOG(ERROR) << "Failed to parse makeCredential request: "
  637. << base::HexEncode(cbor_bytes);
  638. return Platform::Error::INVALID_CTAP;
  639. }
  640. auto params = blink::mojom::PublicKeyCredentialCreationOptions::New();
  641. params->challenge = *make_cred_request.client_data_hash;
  642. params->timeout = base::Seconds(kTimeoutSeconds);
  643. params->relying_party.id = *make_cred_request.rp_id;
  644. params->relying_party.name = *make_cred_request.rp_name;
  645. params->user.id = *make_cred_request.user_id;
  646. params->user.name = *make_cred_request.user_name;
  647. params->user.display_name = *make_cred_request.user_display_name;
  648. const bool rk =
  649. make_cred_request.resident_key && *make_cred_request.resident_key;
  650. params->authenticator_selection.emplace(
  651. device::AuthenticatorAttachment::kPlatform,
  652. rk ? device::ResidentKeyRequirement::kRequired
  653. : device::ResidentKeyRequirement::kDiscouraged,
  654. device::UserVerificationRequirement::kRequired);
  655. if (!CopyCredIds(make_cred_request.excluded_credentials,
  656. &params->exclude_credentials)) {
  657. return Platform::Error::INTERNAL_ERROR;
  658. }
  659. if (!device::cbor_extract::ForEachPublicKeyEntry(
  660. *make_cred_request.cred_params, cbor::Value("alg"),
  661. base::BindRepeating(
  662. [](std::vector<
  663. device::PublicKeyCredentialParams::CredentialInfo>*
  664. out,
  665. const cbor::Value& value) -> bool {
  666. if (!value.is_integer()) {
  667. return false;
  668. }
  669. const int64_t alg = value.GetInteger();
  670. if (alg > std::numeric_limits<int32_t>::max() ||
  671. alg < std::numeric_limits<int32_t>::min()) {
  672. // This value cannot be represented in the `int32_t`
  673. // in the Mojo structure and thus is ignored.
  674. return true;
  675. }
  676. device::PublicKeyCredentialParams::CredentialInfo info;
  677. info.algorithm = static_cast<int32_t>(alg);
  678. out->push_back(info);
  679. return true;
  680. },
  681. base::Unretained(&params->public_key_parameters)))) {
  682. return Platform::Error::INVALID_CTAP;
  683. }
  684. transaction_received_ = true;
  685. platform_->MakeCredential(
  686. std::move(params),
  687. base::BindOnce(&CTAP2Processor::OnMakeCredentialResponse,
  688. weak_factory_.GetWeakPtr(), rk));
  689. return std::vector<uint8_t>();
  690. }
  691. case static_cast<uint8_t>(
  692. device::CtapRequestCommand::kAuthenticatorGetAssertion): {
  693. if (!payload || !payload->is_map()) {
  694. FIDO_LOG(ERROR) << "Invalid makeCredential payload";
  695. return Platform::Error::INVALID_CTAP;
  696. }
  697. GetAssertionRequest get_assertion_request;
  698. if (!device::cbor_extract::Extract<GetAssertionRequest>(
  699. &get_assertion_request, kGetAssertionParseSteps,
  700. payload->GetMap())) {
  701. FIDO_LOG(ERROR) << "Failed to parse getAssertion request";
  702. return Platform::Error::INVALID_CTAP;
  703. }
  704. auto params = blink::mojom::PublicKeyCredentialRequestOptions::New();
  705. params->challenge = *get_assertion_request.client_data_hash;
  706. params->relying_party_id = *get_assertion_request.rp_id;
  707. params->user_verification =
  708. device::UserVerificationRequirement::kRequired;
  709. params->timeout = base::Seconds(kTimeoutSeconds);
  710. if (!CopyCredIds(get_assertion_request.allowed_credentials,
  711. &params->allow_credentials)) {
  712. return Platform::Error::INTERNAL_ERROR;
  713. }
  714. transaction_received_ = true;
  715. const bool empty_allowlist = params->allow_credentials.empty();
  716. platform_->GetAssertion(
  717. std::move(params),
  718. base::BindOnce(&CTAP2Processor::OnGetAssertionResponse,
  719. weak_factory_.GetWeakPtr(), empty_allowlist));
  720. return std::vector<uint8_t>();
  721. }
  722. case static_cast<uint8_t>(
  723. device::CtapRequestCommand::kAuthenticatorSelection): {
  724. if (payload) {
  725. FIDO_LOG(ERROR) << "Invalid authenticatorSelection payload";
  726. return Platform::Error::INVALID_CTAP;
  727. }
  728. return Platform::Error::AUTHENTICATOR_SELECTION_RECEIVED;
  729. }
  730. default:
  731. FIDO_LOG(ERROR) << "Received unknown command "
  732. << static_cast<unsigned>(command);
  733. return Platform::Error::INVALID_CTAP;
  734. }
  735. }
  736. void OnMakeCredentialResponse(
  737. bool was_discoverable_credential_request,
  738. uint32_t ctap_status,
  739. base::span<const uint8_t> attestation_object_bytes) {
  740. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  741. DCHECK_LE(ctap_status, 0xFFu);
  742. std::vector<uint8_t> response = {base::checked_cast<uint8_t>(ctap_status)};
  743. if (ctap_status == static_cast<uint8_t>(CtapDeviceResponseCode::kSuccess)) {
  744. // TODO: pass response parameters from the Java side.
  745. absl::optional<cbor::Value> cbor_attestation_object =
  746. cbor::Reader::Read(attestation_object_bytes);
  747. if (!cbor_attestation_object || !cbor_attestation_object->is_map()) {
  748. FIDO_LOG(ERROR) << "invalid CBOR attestation object";
  749. return;
  750. }
  751. AttestationObject attestation_object;
  752. if (!device::cbor_extract::Extract<AttestationObject>(
  753. &attestation_object, kAttObjParseSteps,
  754. cbor_attestation_object->GetMap())) {
  755. FIDO_LOG(ERROR) << "attestation object parse failed";
  756. return;
  757. }
  758. cbor::Value::MapValue response_map;
  759. response_map.emplace(1, base::StringPiece(*attestation_object.fmt));
  760. response_map.emplace(
  761. 2, base::span<const uint8_t>(*attestation_object.auth_data));
  762. response_map.emplace(3, attestation_object.statement->Clone());
  763. absl::optional<std::vector<uint8_t>> response_payload =
  764. cbor::Writer::Write(cbor::Value(std::move(response_map)));
  765. if (!response_payload) {
  766. return;
  767. }
  768. response.insert(response.end(), response_payload->begin(),
  769. response_payload->end());
  770. } else if (was_discoverable_credential_request &&
  771. ctap_status ==
  772. static_cast<uint8_t>(
  773. CtapDeviceResponseCode::kCtap2ErrUnsupportedOption)) {
  774. have_completed_ = true;
  775. platform_->OnCompleted(Platform::Error::DISCOVERABLE_CREDENTIALS_REQUEST);
  776. return;
  777. } else {
  778. platform_->OnStatus(Platform::Status::CTAP_ERROR);
  779. }
  780. if (!transaction_done_) {
  781. platform_->OnStatus(Platform::Status::FIRST_TRANSACTION_DONE);
  782. transaction_done_ = true;
  783. }
  784. transport_->Write(std::move(response));
  785. }
  786. void OnGetAssertionResponse(
  787. bool was_empty_allowlist_request,
  788. uint32_t ctap_status,
  789. blink::mojom::GetAssertionAuthenticatorResponsePtr auth_response) {
  790. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  791. DCHECK_LE(ctap_status, 0xFFu);
  792. if (auth_response && was_empty_allowlist_request &&
  793. !auth_response->user_handle) {
  794. FIDO_LOG(ERROR)
  795. << "missing user id in response to discoverable credential assertion";
  796. ctap_status =
  797. static_cast<uint32_t>(CtapDeviceResponseCode::kCtap2ErrOther);
  798. }
  799. std::vector<uint8_t> response = {base::checked_cast<uint8_t>(ctap_status)};
  800. if (ctap_status == static_cast<uint8_t>(CtapDeviceResponseCode::kSuccess)) {
  801. cbor::Value::MapValue credential_descriptor;
  802. credential_descriptor.emplace("type", device::kPublicKey);
  803. credential_descriptor.emplace("id",
  804. std::move(auth_response->info->raw_id));
  805. cbor::Value::ArrayValue transports;
  806. transports.emplace_back("internal");
  807. transports.emplace_back("cable");
  808. credential_descriptor.emplace("transports", std::move(transports));
  809. cbor::Value::MapValue response_map;
  810. response_map.emplace(1, std::move(credential_descriptor));
  811. response_map.emplace(2,
  812. std::move(auth_response->info->authenticator_data));
  813. response_map.emplace(3, std::move(auth_response->signature));
  814. if (was_empty_allowlist_request) {
  815. cbor::Value::MapValue user_map;
  816. user_map.emplace("id", std::move(*auth_response->user_handle));
  817. // The `name` and `displayName` fields are not present in
  818. // `GetAssertionAuthenticatorResponse` because they aren't returned
  819. // at the WebAuthn level. CTAP 2.1 says that fields other than `id` are
  820. // only applicable "For multiple accounts per RP case, where the
  821. // authenticator does not have a display". But we assume that caBLE
  822. // devices do have a display and don't handle multiple GetAssertion
  823. // responses anyway.
  824. user_map.emplace("name", "");
  825. user_map.emplace("displayName", "");
  826. response_map.emplace(4, std::move(user_map));
  827. // This is the `userSelected` field, which indicates that additional
  828. // confirmation of the account selection isn't needed.
  829. response_map.emplace(6, true);
  830. }
  831. absl::optional<std::vector<uint8_t>> response_payload =
  832. cbor::Writer::Write(cbor::Value(std::move(response_map)));
  833. if (!response_payload) {
  834. return;
  835. }
  836. response.insert(response.end(), response_payload->begin(),
  837. response_payload->end());
  838. } else if (was_empty_allowlist_request &&
  839. ctap_status ==
  840. static_cast<uint8_t>(
  841. CtapDeviceResponseCode::kCtap2ErrNoCredentials)) {
  842. have_completed_ = true;
  843. platform_->OnCompleted(Platform::Error::DISCOVERABLE_CREDENTIALS_REQUEST);
  844. return;
  845. } else {
  846. platform_->OnStatus(Platform::Status::CTAP_ERROR);
  847. }
  848. if (!transaction_done_) {
  849. platform_->OnStatus(Platform::Status::FIRST_TRANSACTION_DONE);
  850. transaction_done_ = true;
  851. }
  852. transport_->Write(std::move(response));
  853. }
  854. // CopyCredIds parses a series of `PublicKeyCredentialDescriptor`s from `in`
  855. // and appends them to `out`, returning true on success or false on error.
  856. static bool CopyCredIds(const cbor::Value::ArrayValue* in,
  857. std::vector<PublicKeyCredentialDescriptor>* out) {
  858. if (!in) {
  859. return true;
  860. }
  861. return device::cbor_extract::ForEachPublicKeyEntry(
  862. *in, cbor::Value("id"),
  863. base::BindRepeating(
  864. [](std::vector<PublicKeyCredentialDescriptor>* out,
  865. const cbor::Value& value) -> bool {
  866. if (!value.is_bytestring()) {
  867. return false;
  868. }
  869. out->emplace_back(device::CredentialType::kPublicKey,
  870. value.GetBytestring(),
  871. base::flat_set<device::FidoTransportProtocol>{
  872. device::FidoTransportProtocol::kInternal});
  873. return true;
  874. },
  875. base::Unretained(out)));
  876. }
  877. bool have_completed_ = false;
  878. bool transaction_received_ = false;
  879. bool transaction_done_ = false;
  880. const std::unique_ptr<Transport> transport_;
  881. const std::unique_ptr<Platform> platform_;
  882. SEQUENCE_CHECKER(sequence_checker_);
  883. base::WeakPtrFactory<CTAP2Processor> weak_factory_{this};
  884. };
  885. static std::array<uint8_t, 32> DerivePairedSecret(
  886. base::span<const uint8_t, kRootSecretSize> root_secret,
  887. const absl::optional<base::span<const uint8_t>>& contact_id,
  888. base::span<const uint8_t, kPairingIDSize> pairing_id) {
  889. base::span<const uint8_t, kRootSecretSize> secret = root_secret;
  890. std::array<uint8_t, kRootSecretSize> per_contact_id_secret;
  891. if (contact_id) {
  892. // The root secret is not used directly to derive the paired secret because
  893. // we want the keys to change after an unlink. Unlinking invalidates and
  894. // replaces the contact ID therefore we derive paired secrets in two steps:
  895. // first using the contact ID to derive a secret from the root secret, and
  896. // then using the pairing ID to generate a secret from that.
  897. per_contact_id_secret =
  898. device::cablev2::Derive<EXTENT(per_contact_id_secret)>(
  899. root_secret, *contact_id,
  900. device::cablev2::DerivedValueType::kPerContactIDSecret);
  901. secret = per_contact_id_secret;
  902. }
  903. std::array<uint8_t, 32> paired_secret;
  904. paired_secret = device::cablev2::Derive<EXTENT(paired_secret)>(
  905. secret, pairing_id, device::cablev2::DerivedValueType::kPairedSecret);
  906. return paired_secret;
  907. }
  908. class PairingDataGenerator {
  909. public:
  910. static GeneratePairingDataCallback GetClosure(
  911. base::span<const uint8_t, kRootSecretSize> root_secret,
  912. const std::string& name,
  913. absl::optional<std::vector<uint8_t>> contact_id) {
  914. auto* generator =
  915. new PairingDataGenerator(root_secret, name, std::move(contact_id));
  916. return base::BindOnce(&PairingDataGenerator::Generate,
  917. base::Owned(generator));
  918. }
  919. private:
  920. PairingDataGenerator(base::span<const uint8_t, kRootSecretSize> root_secret,
  921. const std::string& name,
  922. absl::optional<std::vector<uint8_t>> contact_id)
  923. : root_secret_(fido_parsing_utils::Materialize(root_secret)),
  924. name_(name),
  925. contact_id_(std::move(contact_id)) {}
  926. absl::optional<cbor::Value> Generate(
  927. base::span<const uint8_t, device::kP256X962Length> peer_public_key_x962,
  928. device::cablev2::HandshakeHash handshake_hash) {
  929. if (!contact_id_) {
  930. return absl::nullopt;
  931. }
  932. std::array<uint8_t, kPairingIDSize> pairing_id;
  933. crypto::RandBytes(pairing_id);
  934. const std::array<uint8_t, 32> paired_secret =
  935. DerivePairedSecret(root_secret_, *contact_id_, pairing_id);
  936. cbor::Value::MapValue map;
  937. map.emplace(1, std::move(*contact_id_));
  938. map.emplace(2, pairing_id);
  939. map.emplace(3, paired_secret);
  940. bssl::UniquePtr<EC_KEY> identity_key(IdentityKey(root_secret_));
  941. device::CableAuthenticatorIdentityKey public_key;
  942. CHECK_EQ(
  943. public_key.size(),
  944. EC_POINT_point2oct(EC_KEY_get0_group(identity_key.get()),
  945. EC_KEY_get0_public_key(identity_key.get()),
  946. POINT_CONVERSION_UNCOMPRESSED, public_key.data(),
  947. public_key.size(), /*ctx=*/nullptr));
  948. map.emplace(4, public_key);
  949. map.emplace(5, name_);
  950. map.emplace(6,
  951. device::cablev2::CalculatePairingSignature(
  952. identity_key.get(), peer_public_key_x962, handshake_hash));
  953. return cbor::Value(std::move(map));
  954. }
  955. const std::array<uint8_t, kRootSecretSize> root_secret_;
  956. const std::string name_;
  957. absl::optional<std::vector<uint8_t>> contact_id_;
  958. };
  959. } // namespace
  960. Platform::BLEAdvert::~BLEAdvert() = default;
  961. Platform::~Platform() = default;
  962. Transport::~Transport() = default;
  963. Transaction::~Transaction() = default;
  964. std::unique_ptr<Transaction> TransactWithPlaintextTransport(
  965. std::unique_ptr<Platform> platform,
  966. std::unique_ptr<Transport> transport) {
  967. return std::make_unique<CTAP2Processor>(std::move(transport),
  968. std::move(platform));
  969. }
  970. std::unique_ptr<Transaction> TransactFromQRCode(
  971. unsigned protocol_revision,
  972. std::unique_ptr<Platform> platform,
  973. network::mojom::NetworkContext* network_context,
  974. base::span<const uint8_t, kRootSecretSize> root_secret,
  975. const std::string& authenticator_name,
  976. base::span<const uint8_t, 16> qr_secret,
  977. base::span<const uint8_t, kP256X962Length> peer_identity,
  978. absl::optional<std::vector<uint8_t>> contact_id,
  979. bool use_new_crypter_construction) {
  980. auto generate_pairing_data = PairingDataGenerator::GetClosure(
  981. root_secret, authenticator_name, std::move(contact_id));
  982. Platform* const platform_ptr = platform.get();
  983. return std::make_unique<CTAP2Processor>(
  984. std::make_unique<TunnelTransport>(
  985. protocol_revision, platform_ptr, network_context, qr_secret,
  986. peer_identity, use_new_crypter_construction,
  987. std::move(generate_pairing_data)),
  988. std::move(platform));
  989. }
  990. std::unique_ptr<Transaction> TransactFromFCM(
  991. unsigned protocol_revision,
  992. std::unique_ptr<Platform> platform,
  993. network::mojom::NetworkContext* network_context,
  994. base::span<const uint8_t, kRootSecretSize> root_secret,
  995. std::array<uint8_t, kRoutingIdSize> routing_id,
  996. base::span<const uint8_t, kTunnelIdSize> tunnel_id,
  997. base::span<const uint8_t, kPairingIDSize> pairing_id,
  998. base::span<const uint8_t, kClientNonceSize> client_nonce,
  999. absl::optional<base::span<const uint8_t>> contact_id) {
  1000. const std::array<uint8_t, 32> paired_secret =
  1001. DerivePairedSecret(root_secret, contact_id, pairing_id);
  1002. Platform* const platform_ptr = platform.get();
  1003. return std::make_unique<CTAP2Processor>(
  1004. std::make_unique<TunnelTransport>(
  1005. protocol_revision, platform_ptr, network_context, paired_secret,
  1006. client_nonce, routing_id, tunnel_id, IdentityKey(root_secret)),
  1007. std::move(platform));
  1008. }
  1009. } // namespace authenticator
  1010. } // namespace cablev2
  1011. } // namespace device