v2_handshake.cc 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122
  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_handshake.h"
  5. #include <inttypes.h>
  6. #include <array>
  7. #include <type_traits>
  8. #include "base/base64url.h"
  9. #include "base/bits.h"
  10. #include "base/numerics/safe_conversions.h"
  11. #include "base/numerics/safe_math.h"
  12. #include "base/strings/string_number_conversions.h"
  13. #include "base/strings/string_piece.h"
  14. #include "base/strings/string_util.h"
  15. #include "base/sys_byteorder.h"
  16. #include "components/cbor/reader.h"
  17. #include "components/cbor/values.h"
  18. #include "components/cbor/writer.h"
  19. #include "components/device_event_log/device_event_log.h"
  20. #include "crypto/aead.h"
  21. #include "device/fido/cable/v2_constants.h"
  22. #include "device/fido/fido_constants.h"
  23. #include "device/fido/fido_parsing_utils.h"
  24. #include "third_party/boringssl/src/include/openssl/aes.h"
  25. #include "third_party/boringssl/src/include/openssl/bytestring.h"
  26. #include "third_party/boringssl/src/include/openssl/digest.h"
  27. #include "third_party/boringssl/src/include/openssl/ec.h"
  28. #include "third_party/boringssl/src/include/openssl/ec_key.h"
  29. #include "third_party/boringssl/src/include/openssl/ecdh.h"
  30. #include "third_party/boringssl/src/include/openssl/hkdf.h"
  31. #include "third_party/boringssl/src/include/openssl/hmac.h"
  32. #include "third_party/boringssl/src/include/openssl/mem.h"
  33. #include "third_party/boringssl/src/include/openssl/obj.h"
  34. #include "third_party/boringssl/src/include/openssl/sha.h"
  35. #include "url/gurl.h"
  36. namespace device {
  37. namespace cablev2 {
  38. namespace {
  39. // Maximum value of a sequence number. Exceeding this causes all operations to
  40. // return an error. This is assumed to be vastly larger than any caBLE exchange
  41. // will ever reach.
  42. constexpr uint32_t kMaxSequence = (1 << 24) - 1;
  43. bool ConstructNonce(uint32_t counter,
  44. bool big_endian,
  45. base::span<uint8_t, 12> out_nonce) {
  46. if (counter > kMaxSequence) {
  47. return false;
  48. }
  49. std::array<uint8_t, sizeof(counter)> counter_bytes;
  50. if (big_endian) {
  51. std::fill(out_nonce.begin(), out_nonce.end(), 0);
  52. counter = base::ByteSwap(counter);
  53. memcpy(out_nonce.data() + out_nonce.size() - sizeof(counter), &counter,
  54. sizeof(counter));
  55. } else {
  56. memcpy(counter_bytes.data(), &counter, sizeof(counter));
  57. std::copy(counter_bytes.begin(), counter_bytes.end(), out_nonce.begin());
  58. std::fill(out_nonce.begin() + counter_bytes.size(), out_nonce.end(), 0);
  59. }
  60. return true;
  61. }
  62. std::array<uint8_t, 32> PairingSignature(
  63. const EC_KEY* identity_key,
  64. base::span<const uint8_t, kP256X962Length> peer_public_key_x962,
  65. base::span<const uint8_t, std::tuple_size<HandshakeHash>::value>
  66. handshake_hash) {
  67. const EC_GROUP* const p256 = EC_KEY_get0_group(identity_key);
  68. bssl::UniquePtr<EC_POINT> peer_public_key(EC_POINT_new(p256));
  69. CHECK(EC_POINT_oct2point(p256, peer_public_key.get(),
  70. peer_public_key_x962.data(),
  71. peer_public_key_x962.size(),
  72. /*ctx=*/nullptr));
  73. uint8_t shared_secret[32];
  74. CHECK(ECDH_compute_key(shared_secret, sizeof(shared_secret),
  75. peer_public_key.get(), identity_key,
  76. /*kdf=*/nullptr) == sizeof(shared_secret));
  77. std::array<uint8_t, SHA256_DIGEST_LENGTH> expected_signature;
  78. unsigned expected_signature_len = 0;
  79. CHECK(HMAC(EVP_sha256(), /*key=*/shared_secret, sizeof(shared_secret),
  80. handshake_hash.data(), handshake_hash.size(),
  81. expected_signature.data(), &expected_signature_len) != nullptr);
  82. CHECK_EQ(expected_signature_len, EXTENT(expected_signature));
  83. return expected_signature;
  84. }
  85. // ReservedBitsAreZero returns true if the currently unused bits in |eid| are
  86. // all set to zero.
  87. bool ReservedBitsAreZero(const CableEidArray& eid) {
  88. return eid[0] == 0;
  89. }
  90. bssl::UniquePtr<EC_KEY> ECKeyFromSeed(
  91. base::span<const uint8_t, kQRSeedSize> seed) {
  92. bssl::UniquePtr<EC_GROUP> p256(
  93. EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
  94. return bssl::UniquePtr<EC_KEY>(
  95. EC_KEY_derive_from_secret(p256.get(), seed.data(), seed.size()));
  96. }
  97. // kAdditionalDataBytes is the AD input to the AEAD used in caBLEv2. We're
  98. // transitioning away from this towards not supplying an AD in order to better
  99. // match Noise.
  100. const uint8_t kAdditionalDataBytes[1] = {/*version=*/2};
  101. } // namespace
  102. namespace tunnelserver {
  103. // kAssignedDomains is the list of defined tunnel server domains. These map
  104. // to values 0..256.
  105. static const char* kAssignedDomains[] = {"cable.ua5v.com", "cable.auth.com"};
  106. absl::optional<KnownDomainID> ToKnownDomainID(uint16_t domain) {
  107. if (domain >= 256 || domain < std::size(kAssignedDomains)) {
  108. return KnownDomainID(domain);
  109. }
  110. return absl::nullopt;
  111. }
  112. std::string DecodeDomain(KnownDomainID domain_id) {
  113. const uint16_t domain = domain_id.value();
  114. if (domain < 256) {
  115. // The |KnownDomainID| type should only contain valid values for this but,
  116. // just in case, CHECK it too.
  117. CHECK_LT(domain, std::size(kAssignedDomains));
  118. return kAssignedDomains[domain];
  119. }
  120. char templ[] = "caBLEv2 tunnel server domain\x00\x00";
  121. memcpy(&templ[sizeof(templ) - 1 - sizeof(domain)], &domain, sizeof(domain));
  122. uint8_t digest[SHA256_DIGEST_LENGTH];
  123. // The input should be NUL-terminated, thus the trailing NUL in |templ| is
  124. // included here.
  125. SHA256(reinterpret_cast<const uint8_t*>(templ), sizeof(templ), digest);
  126. uint64_t result;
  127. static_assert(sizeof(result) <= sizeof(digest), "");
  128. memcpy(&result, digest, sizeof(result));
  129. static const char kBase32Chars[33] = "abcdefghijklmnopqrstuvwxyz234567";
  130. const int tld_value = result & 3;
  131. result >>= 2;
  132. std::string ret = "cable.";
  133. while (result != 0) {
  134. ret.push_back(kBase32Chars[result & 31]);
  135. result >>= 5;
  136. }
  137. ret.push_back('.');
  138. static const char kTLDs[4][5] = {"com", "org", "net", "info"};
  139. ret += kTLDs[tld_value];
  140. return ret;
  141. }
  142. GURL GetNewTunnelURL(KnownDomainID domain, base::span<const uint8_t, 16> id) {
  143. std::string ret = "wss://" + DecodeDomain(domain) + "/cable/new/";
  144. ret += base::HexEncode(id);
  145. const GURL url(ret);
  146. DCHECK(url.is_valid());
  147. return url;
  148. }
  149. GURL GetConnectURL(KnownDomainID domain,
  150. std::array<uint8_t, kRoutingIdSize> routing_id,
  151. base::span<const uint8_t, 16> id) {
  152. std::string ret = "wss://" + DecodeDomain(domain) + "/cable/connect/";
  153. ret += base::HexEncode(routing_id);
  154. ret += "/";
  155. ret += base::HexEncode(id);
  156. const GURL url(ret);
  157. DCHECK(url.is_valid());
  158. return url;
  159. }
  160. GURL GetContactURL(const std::string& tunnel_server,
  161. base::span<const uint8_t> contact_id) {
  162. std::string contact_id_base64;
  163. base::Base64UrlEncode(
  164. base::StringPiece(reinterpret_cast<const char*>(contact_id.data()),
  165. contact_id.size()),
  166. base::Base64UrlEncodePolicy::OMIT_PADDING, &contact_id_base64);
  167. GURL ret(std::string("wss://") + tunnel_server + "/cable/contact/" +
  168. contact_id_base64);
  169. DCHECK(ret.is_valid());
  170. return ret;
  171. }
  172. } // namespace tunnelserver
  173. namespace eid {
  174. Components::Components() = default;
  175. Components::~Components() = default;
  176. Components::Components(const Components&) = default;
  177. std::array<uint8_t, kAdvertSize> Encrypt(
  178. const CableEidArray& eid,
  179. base::span<const uint8_t, kEIDKeySize> key) {
  180. // |eid| is encrypted as an AES block and a 4-byte HMAC is appended. The |key|
  181. // is a pair of 256-bit keys, concatenated.
  182. DCHECK(ReservedBitsAreZero(eid));
  183. std::array<uint8_t, kAdvertSize> ret;
  184. static_assert(EXTENT(ret) == AES_BLOCK_SIZE + 4, "");
  185. AES_KEY aes_key;
  186. static_assert(EXTENT(key) == 32 + 32, "");
  187. CHECK(AES_set_encrypt_key(key.data(), /*bits=*/8 * 32, &aes_key) == 0);
  188. static_assert(EXTENT(eid) == AES_BLOCK_SIZE, "EIDs are not AES blocks");
  189. AES_encrypt(/*in=*/eid.data(), /*out=*/ret.data(), &aes_key);
  190. uint8_t hmac[SHA256_DIGEST_LENGTH];
  191. unsigned hmac_len;
  192. CHECK(HMAC(EVP_sha256(), key.data() + 32, 32, ret.data(), AES_BLOCK_SIZE,
  193. hmac, &hmac_len) != nullptr);
  194. CHECK_EQ(hmac_len, sizeof(hmac));
  195. static_assert(sizeof(hmac) >= 4, "");
  196. memcpy(ret.data() + AES_BLOCK_SIZE, hmac, 4);
  197. return ret;
  198. }
  199. absl::optional<CableEidArray> Decrypt(
  200. const std::array<uint8_t, kAdvertSize>& advert,
  201. base::span<const uint8_t, kEIDKeySize> key) {
  202. // See |Encrypt| about the format.
  203. static_assert(EXTENT(advert) == AES_BLOCK_SIZE + 4, "");
  204. static_assert(EXTENT(key) == 32 + 32, "");
  205. uint8_t calculated_hmac[SHA256_DIGEST_LENGTH];
  206. unsigned calculated_hmac_len;
  207. CHECK(HMAC(EVP_sha256(), key.data() + 32, 32, advert.data(), AES_BLOCK_SIZE,
  208. calculated_hmac, &calculated_hmac_len) != nullptr);
  209. CHECK_EQ(calculated_hmac_len, sizeof(calculated_hmac));
  210. if (CRYPTO_memcmp(calculated_hmac, advert.data() + AES_BLOCK_SIZE, 4) != 0) {
  211. return absl::nullopt;
  212. }
  213. AES_KEY aes_key;
  214. CHECK(AES_set_decrypt_key(key.data(), /*bits=*/8 * 32, &aes_key) == 0);
  215. CableEidArray plaintext;
  216. static_assert(EXTENT(plaintext) == AES_BLOCK_SIZE, "EIDs are not AES blocks");
  217. AES_decrypt(/*in=*/advert.data(), /*out=*/plaintext.data(), &aes_key);
  218. // Ensure that reserved bits are zero. They might be used for new features in
  219. // the future but support for those features must be advertised in the QR
  220. // code, thus authenticators should not be unilaterally setting any of these
  221. // bits.
  222. if (!ReservedBitsAreZero(plaintext)) {
  223. return absl::nullopt;
  224. }
  225. uint16_t tunnel_server_domain;
  226. static_assert(EXTENT(plaintext) >= sizeof(tunnel_server_domain), "");
  227. memcpy(&tunnel_server_domain,
  228. &plaintext[EXTENT(plaintext) - sizeof(tunnel_server_domain)],
  229. sizeof(tunnel_server_domain));
  230. if (!tunnelserver::ToKnownDomainID(tunnel_server_domain)) {
  231. return absl::nullopt;
  232. }
  233. return plaintext;
  234. }
  235. CableEidArray FromComponents(const Components& components) {
  236. CableEidArray eid;
  237. static_assert(EXTENT(components.nonce) == kNonceSize, "");
  238. static_assert(EXTENT(eid) == 1 + kNonceSize + sizeof(components.routing_id) +
  239. sizeof(components.tunnel_server_domain),
  240. "");
  241. eid[0] = 0;
  242. memcpy(&eid[1], components.nonce.data(), kNonceSize);
  243. memcpy(&eid[1 + kNonceSize], components.routing_id.data(),
  244. sizeof(components.routing_id));
  245. memcpy(&eid[1 + kNonceSize + sizeof(components.routing_id)],
  246. &components.tunnel_server_domain,
  247. sizeof(components.tunnel_server_domain));
  248. return eid;
  249. }
  250. Components ToComponents(const CableEidArray& eid) {
  251. Components ret;
  252. static_assert(EXTENT(ret.nonce) == kNonceSize, "");
  253. static_assert(EXTENT(eid) == 1 + kNonceSize + sizeof(ret.routing_id) +
  254. sizeof(ret.tunnel_server_domain),
  255. "");
  256. memcpy(ret.nonce.data(), &eid[1], kNonceSize);
  257. memcpy(ret.routing_id.data(), &eid[1 + kNonceSize], sizeof(ret.routing_id));
  258. uint16_t tunnel_server_domain;
  259. memcpy(&tunnel_server_domain, &eid[1 + kNonceSize + sizeof(ret.routing_id)],
  260. sizeof(tunnel_server_domain));
  261. // |eid| has been checked by |Decrypt| so the tunnel server domain must be
  262. // valid.
  263. ret.tunnel_server_domain =
  264. *tunnelserver::ToKnownDomainID(tunnel_server_domain);
  265. return ret;
  266. }
  267. } // namespace eid
  268. namespace qr {
  269. constexpr char kPrefix[] = "FIDO:/";
  270. // DecompressPublicKey converts a compressed public key (from a scanned QR
  271. // code) into a standard, uncompressed one.
  272. static absl::optional<std::array<uint8_t, device::kP256X962Length>>
  273. DecompressPublicKey(base::span<const uint8_t> compressed_public_key) {
  274. if (compressed_public_key.size() !=
  275. device::cablev2::kCompressedPublicKeySize) {
  276. return absl::nullopt;
  277. }
  278. bssl::UniquePtr<EC_GROUP> p256(
  279. EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
  280. bssl::UniquePtr<EC_POINT> point(EC_POINT_new(p256.get()));
  281. if (!EC_POINT_oct2point(p256.get(), point.get(), compressed_public_key.data(),
  282. compressed_public_key.size(), /*ctx=*/nullptr)) {
  283. return absl::nullopt;
  284. }
  285. std::array<uint8_t, device::kP256X962Length> ret;
  286. CHECK_EQ(
  287. ret.size(),
  288. EC_POINT_point2oct(p256.get(), point.get(), POINT_CONVERSION_UNCOMPRESSED,
  289. ret.data(), ret.size(), /*ctx=*/nullptr));
  290. return ret;
  291. }
  292. static std::array<uint8_t, device::cablev2::kCompressedPublicKeySize>
  293. SeedToCompressedPublicKey(base::span<const uint8_t, 32> seed) {
  294. bssl::UniquePtr<EC_KEY> key = ECKeyFromSeed(seed);
  295. const EC_POINT* public_key = EC_KEY_get0_public_key(key.get());
  296. std::array<uint8_t, device::cablev2::kCompressedPublicKeySize> ret;
  297. CHECK_EQ(ret.size(),
  298. EC_POINT_point2oct(EC_KEY_get0_group(key.get()), public_key,
  299. POINT_CONVERSION_COMPRESSED, ret.data(),
  300. ret.size(), /*ctx=*/nullptr));
  301. return ret;
  302. }
  303. // static
  304. absl::optional<Components> Parse(const std::string& qr_url) {
  305. if (qr_url.size() < sizeof(kPrefix) - 1 ||
  306. base::CompareCaseInsensitiveASCII(
  307. kPrefix, qr_url.substr(0, sizeof(kPrefix) - 1)) != 0) {
  308. return absl::nullopt;
  309. }
  310. absl::optional<std::vector<uint8_t>> qr_bytes =
  311. DigitsToBytes(qr_url.substr(sizeof(kPrefix) - 1));
  312. if (!qr_bytes) {
  313. return absl::nullopt;
  314. }
  315. absl::optional<cbor::Value> qr_contents = cbor::Reader::Read(*qr_bytes);
  316. if (!qr_contents || !qr_contents->is_map()) {
  317. return absl::nullopt;
  318. }
  319. const cbor::Value::MapValue& qr_contents_map(qr_contents->GetMap());
  320. base::span<const uint8_t> values[2];
  321. for (size_t i = 0; i < std::size(values); i++) {
  322. const cbor::Value::MapValue::const_iterator it =
  323. qr_contents_map.find(cbor::Value(static_cast<int>(i)));
  324. if (it == qr_contents_map.end() || !it->second.is_bytestring()) {
  325. return absl::nullopt;
  326. }
  327. values[i] = it->second.GetBytestring();
  328. }
  329. base::span<const uint8_t> compressed_public_key = values[0];
  330. base::span<const uint8_t> qr_secret = values[1];
  331. Components ret;
  332. if (qr_secret.size() != ret.secret.size()) {
  333. return absl::nullopt;
  334. }
  335. std::copy(qr_secret.begin(), qr_secret.end(), ret.secret.begin());
  336. absl::optional<std::array<uint8_t, device::kP256X962Length>> peer_identity =
  337. DecompressPublicKey(compressed_public_key);
  338. if (!peer_identity) {
  339. FIDO_LOG(ERROR) << "Invalid compressed public key in QR data";
  340. return absl::nullopt;
  341. }
  342. ret.peer_identity = *peer_identity;
  343. auto it = qr_contents_map.find(cbor::Value(2));
  344. if (it != qr_contents_map.end()) {
  345. if (!it->second.is_integer()) {
  346. return absl::nullopt;
  347. }
  348. ret.num_known_domains = it->second.GetInteger();
  349. }
  350. it = qr_contents_map.find(cbor::Value(4));
  351. if (it != qr_contents_map.end()) {
  352. if (!it->second.is_bool()) {
  353. return absl::nullopt;
  354. }
  355. ret.supports_linking = it->second.GetBool();
  356. }
  357. it = qr_contents_map.find(cbor::Value(5));
  358. if (it != qr_contents_map.end()) {
  359. if (!it->second.is_string()) {
  360. return absl::nullopt;
  361. }
  362. ret.request_type = RequestTypeFromString(it->second.GetString());
  363. }
  364. return ret;
  365. }
  366. std::string Encode(base::span<const uint8_t, kQRKeySize> qr_key,
  367. FidoRequestType request_type) {
  368. cbor::Value::MapValue qr_contents;
  369. qr_contents.emplace(
  370. 0, SeedToCompressedPublicKey(
  371. base::span<const uint8_t, device::cablev2::kQRSeedSize>(
  372. qr_key.data(), device::cablev2::kQRSeedSize)));
  373. qr_contents.emplace(1, qr_key.subspan(device::cablev2::kQRSeedSize));
  374. qr_contents.emplace(
  375. 2, static_cast<int64_t>(std::size(tunnelserver::kAssignedDomains)));
  376. qr_contents.emplace(3, static_cast<int64_t>(base::Time::Now().ToTimeT()));
  377. qr_contents.emplace(4, true); // client supports storing linking information.
  378. qr_contents.emplace(5, RequestTypeToString(request_type));
  379. const absl::optional<std::vector<uint8_t>> qr_data =
  380. cbor::Writer::Write(cbor::Value(std::move(qr_contents)));
  381. return std::string(kPrefix) + BytesToDigits(*qr_data);
  382. }
  383. // When converting between bytes and digits, chunks of 7 bytes are turned into
  384. // 17 digits. See https://www.imperialviolet.org/2021/08/26/qrencoding.html.
  385. constexpr size_t kChunkSize = 7;
  386. constexpr size_t kChunkDigits = 17;
  387. std::string BytesToDigits(base::span<const uint8_t> in) {
  388. std::string ret;
  389. ret.reserve(((in.size() + kChunkSize - 1) / kChunkSize) * kChunkDigits);
  390. while (in.size() >= kChunkSize) {
  391. uint64_t v = 0;
  392. static_assert(sizeof(v) >= kChunkSize, "");
  393. memcpy(&v, in.data(), kChunkSize);
  394. char digits[kChunkDigits + 1];
  395. static_assert(kChunkDigits == 17, "Need to change next line");
  396. CHECK_LT(snprintf(digits, sizeof(digits), "%017" PRIu64, v),
  397. static_cast<int>(sizeof(digits)));
  398. ret += digits;
  399. in = in.subspan(kChunkSize);
  400. }
  401. if (in.size()) {
  402. char format[16];
  403. // kPartialChunkDigits is the number of digits needed to encode each length
  404. // of trailing data from 6 bytes down to zero. I.e. it's 15, 13, 10, 8, 5,
  405. // 3, 0 written in hex.
  406. constexpr uint32_t kPartialChunkDigits = 0x0fda8530;
  407. CHECK_LT(snprintf(format, sizeof(format), "%%0%d" PRIu64,
  408. 15 & (kPartialChunkDigits >> (4 * in.size()))),
  409. static_cast<int>(sizeof(format)));
  410. uint64_t v = 0;
  411. CHECK_LE(in.size(), sizeof(v));
  412. memcpy(&v, in.data(), in.size());
  413. char digits[kChunkDigits + 1];
  414. CHECK_LT(snprintf(digits, sizeof(digits), format, v),
  415. static_cast<int>(sizeof(digits)));
  416. ret += digits;
  417. }
  418. return ret;
  419. }
  420. absl::optional<std::vector<uint8_t>> DigitsToBytes(base::StringPiece in) {
  421. std::vector<uint8_t> ret;
  422. ret.reserve(((in.size() + kChunkDigits - 1) / kChunkDigits) * kChunkSize);
  423. while (in.size() >= kChunkDigits) {
  424. uint64_t v;
  425. if (!base::StringToUint64(in.substr(0, kChunkDigits), &v) ||
  426. v >> (kChunkSize * 8) != 0) {
  427. return absl::nullopt;
  428. }
  429. const uint8_t* const v_bytes = reinterpret_cast<uint8_t*>(&v);
  430. ret.insert(ret.end(), v_bytes, v_bytes + kChunkSize);
  431. in = in.substr(kChunkDigits);
  432. }
  433. if (in.size()) {
  434. size_t remaining_bytes;
  435. switch (in.size()) {
  436. case 3:
  437. remaining_bytes = 1;
  438. break;
  439. case 5:
  440. remaining_bytes = 2;
  441. break;
  442. case 8:
  443. remaining_bytes = 3;
  444. break;
  445. case 10:
  446. remaining_bytes = 4;
  447. break;
  448. case 13:
  449. remaining_bytes = 5;
  450. break;
  451. case 15:
  452. remaining_bytes = 6;
  453. break;
  454. default:
  455. return absl::nullopt;
  456. }
  457. uint64_t v;
  458. if (!base::StringToUint64(in, &v) || v >> (remaining_bytes * 8) != 0) {
  459. return absl::nullopt;
  460. }
  461. const uint8_t* const v_bytes = reinterpret_cast<uint8_t*>(&v);
  462. ret.insert(ret.end(), v_bytes, v_bytes + remaining_bytes);
  463. }
  464. return ret;
  465. }
  466. } // namespace qr
  467. namespace sync {
  468. uint32_t IDNow() {
  469. const base::Time now = base::Time::Now();
  470. time_t utc_time = now.ToTimeT();
  471. // The IDs, and thus Sync secret rotation, have a period of one day. These
  472. // are lazily updated by the phone and don't cause additional Sync uploads.
  473. utc_time /= 86400;
  474. // A uint32_t can span about 11 million years.
  475. return static_cast<uint32_t>(utc_time);
  476. }
  477. bool IDIsValid(uint32_t candidate) {
  478. const uint32_t now = IDNow();
  479. // Sync secrets are allowed to be, at most, 21 periods (~21 days) old. This is
  480. // because the desktop accepts DeviceInfo records of phones that are 14 days
  481. // old and the phone should be slightly laxer than that.
  482. return candidate <= now && (now - candidate) < 21;
  483. }
  484. } // namespace sync
  485. namespace internal {
  486. void Derive(uint8_t* out,
  487. size_t out_len,
  488. base::span<const uint8_t> secret,
  489. base::span<const uint8_t> nonce,
  490. DerivedValueType type) {
  491. static_assert(sizeof(DerivedValueType) <= sizeof(uint32_t), "");
  492. const uint32_t type32 = static_cast<uint32_t>(type);
  493. HKDF(out, out_len, EVP_sha256(), secret.data(), secret.size(),
  494. /*salt=*/nonce.data(), nonce.size(),
  495. /*info=*/reinterpret_cast<const uint8_t*>(&type32), sizeof(type32));
  496. }
  497. } // namespace internal
  498. const char* RequestTypeToString(FidoRequestType request_type) {
  499. switch (request_type) {
  500. case FidoRequestType::kMakeCredential:
  501. return "mc";
  502. case FidoRequestType::kGetAssertion:
  503. return "ga";
  504. // If adding a value here, also update `RequestTypeFromString`.
  505. }
  506. }
  507. FidoRequestType RequestTypeFromString(const std::string& s) {
  508. if (s == "mc") {
  509. return FidoRequestType::kMakeCredential;
  510. }
  511. // kGetAssertion is the default if the value is unknown too.
  512. return FidoRequestType::kGetAssertion;
  513. }
  514. bssl::UniquePtr<EC_KEY> IdentityKey(base::span<const uint8_t, 32> root_secret) {
  515. std::array<uint8_t, 32> seed;
  516. seed = device::cablev2::Derive<EXTENT(seed)>(
  517. root_secret, /*nonce=*/base::span<uint8_t>(),
  518. device::cablev2::DerivedValueType::kIdentityKeySeed);
  519. bssl::UniquePtr<EC_GROUP> p256(
  520. EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
  521. return bssl::UniquePtr<EC_KEY>(
  522. EC_KEY_derive_from_secret(p256.get(), seed.data(), seed.size()));
  523. }
  524. absl::optional<std::vector<uint8_t>> EncodePaddedCBORMap(
  525. cbor::Value::MapValue map) {
  526. // The number of padding bytes is a uint16_t, so the granularity cannot be
  527. // larger than that.
  528. static_assert(kPostHandshakeMsgPaddingGranularity > 0, "");
  529. static_assert(kPostHandshakeMsgPaddingGranularity - 1 <=
  530. std::numeric_limits<uint16_t>::max());
  531. // The granularity must also be a power of two.
  532. static_assert((kPostHandshakeMsgPaddingGranularity &
  533. (kPostHandshakeMsgPaddingGranularity - 1)) == 0);
  534. absl::optional<std::vector<uint8_t>> cbor_bytes =
  535. cbor::Writer::Write(cbor::Value(std::move(map)));
  536. if (!cbor_bytes) {
  537. return absl::nullopt;
  538. }
  539. base::CheckedNumeric<size_t> padded_size_checked = cbor_bytes->size();
  540. padded_size_checked += sizeof(uint16_t); // padding-length bytes
  541. padded_size_checked =
  542. (padded_size_checked + kPostHandshakeMsgPaddingGranularity - 1) &
  543. ~(kPostHandshakeMsgPaddingGranularity - 1);
  544. if (!padded_size_checked.IsValid()) {
  545. return absl::nullopt;
  546. }
  547. const size_t padded_size = padded_size_checked.ValueOrDie();
  548. DCHECK_GE(padded_size, cbor_bytes->size() + sizeof(uint16_t));
  549. const size_t extra_bytes = padded_size - cbor_bytes->size();
  550. const size_t num_padding_bytes =
  551. extra_bytes - sizeof(uint16_t) /* length of padding length */;
  552. cbor_bytes->resize(padded_size);
  553. const uint16_t num_padding_bytes16 =
  554. base::checked_cast<uint16_t>(num_padding_bytes);
  555. memcpy(&cbor_bytes.value()[padded_size - sizeof(num_padding_bytes16)],
  556. &num_padding_bytes16, sizeof(num_padding_bytes16));
  557. return *cbor_bytes;
  558. }
  559. namespace {
  560. // DecodePaddedCBORMap8 performs the actions of |DecodePaddedCBORMap| using the
  561. // old padding format. We still support this format for backwards compatibility.
  562. // See comment in |DecodePaddedCBORMap|.
  563. //
  564. // TODO(agl): remove support for this padding format. (Chromium started sending
  565. // the new format with M99.)
  566. absl::optional<cbor::Value> DecodePaddedCBORMap8(
  567. const base::span<const uint8_t> input) {
  568. if (input.empty()) {
  569. return absl::nullopt;
  570. }
  571. const size_t padding_length = input.back();
  572. if (padding_length + 1 > input.size()) {
  573. return absl::nullopt;
  574. }
  575. auto unpadded_input = input.subspan(0, input.size() - padding_length - 1);
  576. absl::optional<cbor::Value> payload = cbor::Reader::Read(unpadded_input);
  577. if (!payload || !payload->is_map()) {
  578. return absl::nullopt;
  579. }
  580. return payload;
  581. }
  582. // DecodePaddedCBORMap16 performs the actions of |DecodePaddedCBORMap| using the
  583. // new padding format. See comment in |DecodePaddedCBORMap|.
  584. absl::optional<cbor::Value> DecodePaddedCBORMap16(
  585. base::span<const uint8_t> input) {
  586. if (input.size() < sizeof(uint16_t)) {
  587. return absl::nullopt;
  588. }
  589. uint16_t padding_length16;
  590. memcpy(&padding_length16, &input[input.size() - sizeof(padding_length16)],
  591. sizeof(padding_length16));
  592. const size_t padding_length = padding_length16;
  593. if (padding_length + sizeof(uint16_t) > input.size()) {
  594. return absl::nullopt;
  595. }
  596. input = input.subspan(0, input.size() - padding_length - sizeof(uint16_t));
  597. absl::optional<cbor::Value> payload = cbor::Reader::Read(input);
  598. if (!payload || !payload->is_map()) {
  599. return absl::nullopt;
  600. }
  601. return payload;
  602. }
  603. } // namespace
  604. absl::optional<cbor::Value> DecodePaddedCBORMap(
  605. base::span<const uint8_t> input) {
  606. // Two padding formats are currently in use. They are unambiguous so we try
  607. // each, new first. Eventually the old format can be removed once enough time
  608. // has passed since M99.
  609. absl::optional<cbor::Value> result = DecodePaddedCBORMap16(input);
  610. if (!result) {
  611. result = DecodePaddedCBORMap8(input);
  612. }
  613. if (!result) {
  614. FIDO_LOG(DEBUG) << "Invalid padding in caBLE handshake message";
  615. }
  616. return result;
  617. }
  618. Crypter::Crypter(base::span<const uint8_t, 32> read_key,
  619. base::span<const uint8_t, 32> write_key)
  620. : read_key_(fido_parsing_utils::Materialize(read_key)),
  621. write_key_(fido_parsing_utils::Materialize(write_key)) {}
  622. Crypter::~Crypter() = default;
  623. bool Crypter::Encrypt(std::vector<uint8_t>* message_to_encrypt) {
  624. // Messages will be padded in order to round their length up to a multiple
  625. // of kPaddingGranularity.
  626. constexpr size_t kPaddingGranularity = 32;
  627. static_assert(kPaddingGranularity < 256, "padding too large");
  628. static_assert(base::bits::IsPowerOfTwo(kPaddingGranularity),
  629. "padding must be a power of two");
  630. // Padding consists of a some number of zero bytes appended to the message
  631. // and the final byte in the message is the number of zeros.
  632. base::CheckedNumeric<size_t> padded_size_checked = message_to_encrypt->size();
  633. padded_size_checked += 1; // padding-length byte.
  634. padded_size_checked = (padded_size_checked + kPaddingGranularity - 1) &
  635. ~(kPaddingGranularity - 1);
  636. if (!padded_size_checked.IsValid()) {
  637. NOTREACHED();
  638. return false;
  639. }
  640. const size_t padded_size = padded_size_checked.ValueOrDie();
  641. CHECK_GT(padded_size, message_to_encrypt->size());
  642. const size_t num_zeros = padded_size - message_to_encrypt->size() - 1;
  643. std::vector<uint8_t> padded_message(padded_size, 0);
  644. memcpy(padded_message.data(), message_to_encrypt->data(),
  645. message_to_encrypt->size());
  646. // The number of added zeros has to fit in a single byte so it has to be
  647. // less than 256.
  648. DCHECK_LT(num_zeros, 256u);
  649. padded_message[padded_message.size() - 1] = static_cast<uint8_t>(num_zeros);
  650. std::array<uint8_t, 12> nonce;
  651. if (!ConstructNonce(write_sequence_num_++, new_construction_, nonce)) {
  652. return false;
  653. }
  654. crypto::Aead aes_key(crypto::Aead::AES_256_GCM);
  655. aes_key.Init(write_key_);
  656. DCHECK_EQ(nonce.size(), aes_key.NonceLength());
  657. base::span<const uint8_t> additional_data;
  658. if (!new_construction_) {
  659. additional_data = kAdditionalDataBytes;
  660. }
  661. std::vector<uint8_t> ciphertext =
  662. aes_key.Seal(padded_message, nonce, additional_data);
  663. message_to_encrypt->swap(ciphertext);
  664. return true;
  665. }
  666. bool Crypter::Decrypt(base::span<const uint8_t> ciphertext,
  667. std::vector<uint8_t>* out_plaintext) {
  668. std::array<uint8_t, 12> nonce;
  669. if (!ConstructNonce(read_sequence_num_, new_construction_, nonce)) {
  670. return false;
  671. }
  672. crypto::Aead aes_key(crypto::Aead::AES_256_GCM);
  673. aes_key.Init(read_key_);
  674. DCHECK_EQ(nonce.size(), aes_key.NonceLength());
  675. base::span<const uint8_t> additional_data;
  676. if (!new_construction_) {
  677. additional_data = kAdditionalDataBytes;
  678. }
  679. absl::optional<std::vector<uint8_t>> plaintext =
  680. aes_key.Open(ciphertext, nonce, additional_data);
  681. if (!plaintext) {
  682. // We're transitioning to a different construction. If we failed to decrypt
  683. // the first message with the old one, try again with the new.
  684. if (!new_construction_ && read_sequence_num_ == 0) {
  685. new_construction_ = true;
  686. return Decrypt(ciphertext, out_plaintext);
  687. }
  688. return false;
  689. }
  690. read_sequence_num_++;
  691. if (plaintext->empty()) {
  692. FIDO_LOG(ERROR) << "Invalid caBLE message.";
  693. return false;
  694. }
  695. const size_t padding_length = (*plaintext)[plaintext->size() - 1];
  696. if (padding_length + 1 > plaintext->size()) {
  697. FIDO_LOG(ERROR) << "Invalid caBLE message.";
  698. return false;
  699. }
  700. plaintext->resize(plaintext->size() - padding_length - 1);
  701. out_plaintext->swap(*plaintext);
  702. return true;
  703. }
  704. void Crypter::UseNewConstruction() {
  705. new_construction_ = true;
  706. }
  707. bool Crypter::IsCounterpartyOfForTesting(const Crypter& other) const {
  708. return read_key_ == other.write_key_ && write_key_ == other.read_key_;
  709. }
  710. bool& Crypter::GetNewConstructionFlagForTesting() {
  711. return new_construction_;
  712. }
  713. HandshakeInitiator::HandshakeInitiator(
  714. base::span<const uint8_t, 32> psk,
  715. absl::optional<base::span<const uint8_t, kP256X962Length>> peer_identity,
  716. absl::optional<base::span<const uint8_t, kQRSeedSize>> identity_seed)
  717. : psk_(fido_parsing_utils::Materialize(psk)),
  718. local_identity_(identity_seed ? ECKeyFromSeed(*identity_seed) : nullptr) {
  719. DCHECK(peer_identity.has_value() ^ static_cast<bool>(local_identity_));
  720. if (peer_identity) {
  721. peer_identity_ =
  722. fido_parsing_utils::Materialize<kP256X962Length>(*peer_identity);
  723. }
  724. }
  725. HandshakeInitiator::~HandshakeInitiator() = default;
  726. std::vector<uint8_t> HandshakeInitiator::BuildInitialMessage() {
  727. uint8_t prologue[1];
  728. if (peer_identity_) {
  729. noise_.Init(Noise::HandshakeType::kNKpsk0);
  730. prologue[0] = 0;
  731. noise_.MixHash(prologue);
  732. noise_.MixHash(*peer_identity_);
  733. } else {
  734. noise_.Init(Noise::HandshakeType::kKNpsk0);
  735. prologue[0] = 1;
  736. noise_.MixHash(prologue);
  737. noise_.MixHashPoint(EC_KEY_get0_public_key(local_identity_.get()));
  738. }
  739. noise_.MixKeyAndHash(psk_);
  740. ephemeral_key_.reset(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
  741. const EC_GROUP* group = EC_KEY_get0_group(ephemeral_key_.get());
  742. CHECK(EC_KEY_generate_key(ephemeral_key_.get()));
  743. uint8_t ephemeral_key_public_bytes[kP256X962Length];
  744. CHECK_EQ(sizeof(ephemeral_key_public_bytes),
  745. EC_POINT_point2oct(
  746. group, EC_KEY_get0_public_key(ephemeral_key_.get()),
  747. POINT_CONVERSION_UNCOMPRESSED, ephemeral_key_public_bytes,
  748. sizeof(ephemeral_key_public_bytes), /*ctx=*/nullptr));
  749. noise_.MixHash(ephemeral_key_public_bytes);
  750. noise_.MixKey(ephemeral_key_public_bytes);
  751. if (peer_identity_) {
  752. // If we know the identity of the peer from a previous interaction, NKpsk0
  753. // is performed to ensure that other browsers, which may also know the PSK,
  754. // cannot impersonate the authenticator.
  755. bssl::UniquePtr<EC_POINT> peer_identity_point(EC_POINT_new(group));
  756. uint8_t es_key[32];
  757. CHECK(EC_POINT_oct2point(group, peer_identity_point.get(),
  758. peer_identity_->data(), peer_identity_->size(),
  759. /*ctx=*/nullptr));
  760. CHECK(ECDH_compute_key(es_key, sizeof(es_key), peer_identity_point.get(),
  761. ephemeral_key_.get(),
  762. /*kdf=*/nullptr) == sizeof(es_key));
  763. noise_.MixKey(es_key);
  764. }
  765. std::vector<uint8_t> ciphertext =
  766. noise_.EncryptAndHash(base::span<const uint8_t>());
  767. std::vector<uint8_t> handshake_message;
  768. handshake_message.reserve(sizeof(ephemeral_key_public_bytes) +
  769. ciphertext.size());
  770. handshake_message.insert(
  771. handshake_message.end(), ephemeral_key_public_bytes,
  772. ephemeral_key_public_bytes + sizeof(ephemeral_key_public_bytes));
  773. handshake_message.insert(handshake_message.end(), ciphertext.begin(),
  774. ciphertext.end());
  775. return handshake_message;
  776. }
  777. HandshakeResult HandshakeInitiator::ProcessResponse(
  778. base::span<const uint8_t> response) {
  779. if (response.size() < kP256X962Length) {
  780. FIDO_LOG(DEBUG) << "Handshake response truncated (" << response.size()
  781. << " bytes)";
  782. return absl::nullopt;
  783. }
  784. auto peer_point_bytes = response.subspan(0, kP256X962Length);
  785. auto ciphertext = response.subspan(kP256X962Length);
  786. bssl::UniquePtr<EC_POINT> peer_point(
  787. EC_POINT_new(EC_KEY_get0_group(ephemeral_key_.get())));
  788. uint8_t shared_key_ee[32];
  789. const EC_GROUP* group = EC_KEY_get0_group(ephemeral_key_.get());
  790. if (!EC_POINT_oct2point(group, peer_point.get(), peer_point_bytes.data(),
  791. peer_point_bytes.size(), /*ctx=*/nullptr) ||
  792. ECDH_compute_key(shared_key_ee, sizeof(shared_key_ee), peer_point.get(),
  793. ephemeral_key_.get(),
  794. /*kdf=*/nullptr) != sizeof(shared_key_ee)) {
  795. FIDO_LOG(DEBUG) << "Peer's P-256 point not on curve.";
  796. return absl::nullopt;
  797. }
  798. noise_.MixHash(peer_point_bytes);
  799. noise_.MixKey(peer_point_bytes);
  800. noise_.MixKey(shared_key_ee);
  801. if (local_identity_) {
  802. uint8_t shared_key_se[32];
  803. if (ECDH_compute_key(shared_key_se, sizeof(shared_key_se), peer_point.get(),
  804. local_identity_.get(),
  805. /*kdf=*/nullptr) != sizeof(shared_key_se)) {
  806. FIDO_LOG(DEBUG) << "ECDH_compute_key failed";
  807. return absl::nullopt;
  808. }
  809. noise_.MixKey(shared_key_se);
  810. }
  811. auto plaintext = noise_.DecryptAndHash(ciphertext);
  812. if (!plaintext || !plaintext->empty()) {
  813. FIDO_LOG(DEBUG) << "Invalid caBLE handshake message";
  814. return absl::nullopt;
  815. }
  816. auto [write_key, read_key] = noise_.traffic_keys();
  817. return std::make_pair(std::make_unique<cablev2::Crypter>(read_key, write_key),
  818. noise_.handshake_hash());
  819. }
  820. HandshakeResult RespondToHandshake(
  821. base::span<const uint8_t, 32> psk,
  822. bssl::UniquePtr<EC_KEY> identity,
  823. absl::optional<base::span<const uint8_t, kP256X962Length>> peer_identity,
  824. base::span<const uint8_t> in,
  825. std::vector<uint8_t>* out_response) {
  826. DCHECK(peer_identity.has_value() ^ static_cast<bool>(identity));
  827. if (in.size() < kP256X962Length) {
  828. FIDO_LOG(DEBUG) << "Handshake truncated (" << in.size() << " bytes)";
  829. return absl::nullopt;
  830. }
  831. auto peer_point_bytes = in.subspan(0, kP256X962Length);
  832. auto ciphertext = in.subspan(kP256X962Length);
  833. Noise noise;
  834. uint8_t prologue[1];
  835. if (identity) {
  836. noise.Init(device::Noise::HandshakeType::kNKpsk0);
  837. prologue[0] = 0;
  838. noise.MixHash(prologue);
  839. noise.MixHashPoint(EC_KEY_get0_public_key(identity.get()));
  840. } else {
  841. noise.Init(device::Noise::HandshakeType::kKNpsk0);
  842. prologue[0] = 1;
  843. noise.MixHash(prologue);
  844. noise.MixHash(*peer_identity);
  845. }
  846. noise.MixKeyAndHash(psk);
  847. noise.MixHash(peer_point_bytes);
  848. noise.MixKey(peer_point_bytes);
  849. bssl::UniquePtr<EC_KEY> ephemeral_key(
  850. EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
  851. const EC_GROUP* group = EC_KEY_get0_group(ephemeral_key.get());
  852. CHECK(EC_KEY_generate_key(ephemeral_key.get()));
  853. bssl::UniquePtr<EC_POINT> peer_point(EC_POINT_new(group));
  854. if (!EC_POINT_oct2point(group, peer_point.get(), peer_point_bytes.data(),
  855. peer_point_bytes.size(),
  856. /*ctx=*/nullptr)) {
  857. FIDO_LOG(DEBUG) << "Peer's P-256 point not on curve.";
  858. return absl::nullopt;
  859. }
  860. if (identity) {
  861. uint8_t es_key[32];
  862. if (ECDH_compute_key(es_key, sizeof(es_key), peer_point.get(),
  863. identity.get(),
  864. /*kdf=*/nullptr) != sizeof(es_key)) {
  865. return absl::nullopt;
  866. }
  867. noise.MixKey(es_key);
  868. }
  869. auto plaintext = noise.DecryptAndHash(ciphertext);
  870. if (!plaintext || !plaintext->empty()) {
  871. FIDO_LOG(DEBUG) << "Failed to decrypt handshake ciphertext.";
  872. return absl::nullopt;
  873. }
  874. uint8_t ephemeral_key_public_bytes[kP256X962Length];
  875. CHECK_EQ(sizeof(ephemeral_key_public_bytes),
  876. EC_POINT_point2oct(
  877. group, EC_KEY_get0_public_key(ephemeral_key.get()),
  878. POINT_CONVERSION_UNCOMPRESSED, ephemeral_key_public_bytes,
  879. sizeof(ephemeral_key_public_bytes),
  880. /*ctx=*/nullptr));
  881. noise.MixHash(ephemeral_key_public_bytes);
  882. noise.MixKey(ephemeral_key_public_bytes);
  883. uint8_t shared_key_ee[32];
  884. if (ECDH_compute_key(shared_key_ee, sizeof(shared_key_ee), peer_point.get(),
  885. ephemeral_key.get(),
  886. /*kdf=*/nullptr) != sizeof(shared_key_ee)) {
  887. return absl::nullopt;
  888. }
  889. noise.MixKey(shared_key_ee);
  890. if (peer_identity) {
  891. bssl::UniquePtr<EC_POINT> peer_identity_point(EC_POINT_new(group));
  892. CHECK(EC_POINT_oct2point(group, peer_identity_point.get(),
  893. peer_identity->data(), peer_identity->size(),
  894. /*ctx=*/nullptr));
  895. uint8_t shared_key_se[32];
  896. if (ECDH_compute_key(shared_key_se, sizeof(shared_key_se),
  897. peer_identity_point.get(), ephemeral_key.get(),
  898. /*kdf=*/nullptr) != sizeof(shared_key_se)) {
  899. return absl::nullopt;
  900. }
  901. noise.MixKey(shared_key_se);
  902. }
  903. const std::vector<uint8_t> my_ciphertext =
  904. noise.EncryptAndHash(base::span<const uint8_t>());
  905. out_response->insert(
  906. out_response->end(), ephemeral_key_public_bytes,
  907. ephemeral_key_public_bytes + sizeof(ephemeral_key_public_bytes));
  908. out_response->insert(out_response->end(), my_ciphertext.begin(),
  909. my_ciphertext.end());
  910. auto [read_key, write_key] = noise.traffic_keys();
  911. return std::make_pair(std::make_unique<cablev2::Crypter>(read_key, write_key),
  912. noise.handshake_hash());
  913. }
  914. bool VerifyPairingSignature(
  915. base::span<const uint8_t, kQRSeedSize> identity_seed,
  916. base::span<const uint8_t, kP256X962Length> peer_public_key_x962,
  917. base::span<const uint8_t, std::tuple_size<HandshakeHash>::value>
  918. handshake_hash,
  919. base::span<const uint8_t> signature) {
  920. bssl::UniquePtr<EC_GROUP> p256(
  921. EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
  922. bssl::UniquePtr<EC_POINT> unused(EC_POINT_new(p256.get()));
  923. if (EC_POINT_oct2point(p256.get(), unused.get(), peer_public_key_x962.data(),
  924. peer_public_key_x962.size(),
  925. /*ctx=*/nullptr) != 1) {
  926. return false;
  927. }
  928. bssl::UniquePtr<EC_KEY> identity_key = ECKeyFromSeed(identity_seed);
  929. std::array<uint8_t, SHA256_DIGEST_LENGTH> expected_signature =
  930. PairingSignature(identity_key.get(), peer_public_key_x962,
  931. handshake_hash);
  932. return signature.size() == EXTENT(expected_signature) &&
  933. CRYPTO_memcmp(expected_signature.data(), signature.data(),
  934. EXTENT(expected_signature)) == 0;
  935. }
  936. std::vector<uint8_t> CalculatePairingSignature(
  937. const EC_KEY* identity_key,
  938. base::span<const uint8_t, kP256X962Length> peer_public_key_x962,
  939. base::span<const uint8_t, std::tuple_size<HandshakeHash>::value>
  940. handshake_hash) {
  941. std::array<uint8_t, SHA256_DIGEST_LENGTH> expected_signature =
  942. PairingSignature(identity_key, peer_public_key_x962, handshake_hash);
  943. return std::vector<uint8_t>(expected_signature.begin(),
  944. expected_signature.end());
  945. }
  946. } // namespace cablev2
  947. } // namespace device