v2_handshake.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  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. #ifndef DEVICE_FIDO_CABLE_V2_HANDSHAKE_H_
  5. #define DEVICE_FIDO_CABLE_V2_HANDSHAKE_H_
  6. #include <stdint.h>
  7. #include <array>
  8. #include <memory>
  9. #include "base/component_export.h"
  10. #include "base/containers/span.h"
  11. #include "base/strings/string_piece.h"
  12. #include "components/cbor/values.h"
  13. #include "device/fido/cable/cable_discovery_data.h"
  14. #include "device/fido/cable/noise.h"
  15. #include "device/fido/cable/v2_constants.h"
  16. #include "device/fido/fido_constants.h"
  17. #include "third_party/abseil-cpp/absl/types/optional.h"
  18. #include "third_party/boringssl/src/include/openssl/base.h"
  19. class GURL;
  20. namespace device {
  21. namespace cablev2 {
  22. namespace tunnelserver {
  23. // ToKnownDomainID creates a KnownDomainID from a raw 16-bit value, or returns
  24. // |nullopt| if the value maps to an assigned, but unknown, domain.
  25. COMPONENT_EXPORT(DEVICE_FIDO)
  26. absl::optional<KnownDomainID> ToKnownDomainID(uint16_t domain);
  27. // DecodeDomain converts a 16-bit tunnel server domain into a string in dotted
  28. // form.
  29. COMPONENT_EXPORT(DEVICE_FIDO)
  30. std::string DecodeDomain(KnownDomainID domain);
  31. // GetNewTunnelURL converts a tunnel server domain and a tunnel ID, into a
  32. // WebSockets-based URL for creating a new tunnel.
  33. COMPONENT_EXPORT(DEVICE_FIDO)
  34. GURL GetNewTunnelURL(KnownDomainID domain, base::span<const uint8_t, 16> id);
  35. // GetConnectURL converts a tunnel server domain, a routing-ID, and a tunnel ID,
  36. // into a WebSockets-based URL for connecting to an existing tunnel.
  37. COMPONENT_EXPORT(DEVICE_FIDO)
  38. GURL GetConnectURL(KnownDomainID domain,
  39. std::array<uint8_t, kRoutingIdSize> routing_id,
  40. base::span<const uint8_t, 16> id);
  41. // GetContactURL gets a URL for contacting a previously-paired authenticator.
  42. // The |tunnel_server| is assumed to be a valid domain name and should have been
  43. // taken from a previous call to |DecodeDomain|.
  44. COMPONENT_EXPORT(DEVICE_FIDO)
  45. GURL GetContactURL(const std::string& tunnel_server,
  46. base::span<const uint8_t> contact_id);
  47. } // namespace tunnelserver
  48. namespace eid {
  49. // Encrypt turns an EID into a BLE advert payload by encrypting and
  50. // authenticating with |key|.
  51. COMPONENT_EXPORT(DEVICE_FIDO)
  52. std::array<uint8_t, kAdvertSize> Encrypt(
  53. const CableEidArray& eid,
  54. base::span<const uint8_t, kEIDKeySize> key);
  55. // Decrypt turns a BLE advert payload into a plaintext EID (suitable for passing
  56. // to |ToComponents|) by decrypting with |key|. It ensures that the encoded
  57. // tunnel server domain is recognised.
  58. COMPONENT_EXPORT(DEVICE_FIDO)
  59. absl::optional<CableEidArray> Decrypt(
  60. const std::array<uint8_t, kAdvertSize>& advert,
  61. base::span<const uint8_t, kEIDKeySize> key);
  62. // TODO(agl): this could probably be a class.
  63. // Components contains the parts of a decrypted EID.
  64. struct COMPONENT_EXPORT(DEVICE_FIDO) Components {
  65. Components();
  66. Components(const Components&);
  67. ~Components();
  68. tunnelserver::KnownDomainID tunnel_server_domain;
  69. std::array<uint8_t, kRoutingIdSize> routing_id;
  70. std::array<uint8_t, kNonceSize> nonce;
  71. };
  72. // FromComponents constructs a valid EID from the given components. The result
  73. // will produce a non-nullopt value if given to |ToComponents|.
  74. COMPONENT_EXPORT(DEVICE_FIDO)
  75. CableEidArray FromComponents(const Components& components);
  76. // ToComponents explodes a decrypted EID into its components. It's the
  77. // inverse of |FromComponents|. This will CHECK if the |eid| array is invalid;
  78. // eids from |Decrypt| are always valid.
  79. COMPONENT_EXPORT(DEVICE_FIDO)
  80. Components ToComponents(const CableEidArray& eid);
  81. } // namespace eid
  82. namespace qr {
  83. // Components contains the parsed elements of a QR code.
  84. struct COMPONENT_EXPORT(DEVICE_FIDO) Components {
  85. std::array<uint8_t, device::kP256X962Length> peer_identity;
  86. std::array<uint8_t, 16> secret;
  87. // num_known_domains is the number of registered tunnel server domains known
  88. // to the device showing the QR code. Authenticators can use this to fallback
  89. // to a hashed domain if their registered domain isn't going to work with this
  90. // client.
  91. int64_t num_known_domains = 0;
  92. // supports_linking is true if the device showing the QR code supports storing
  93. // and later using linking information. If this is false or absent, an
  94. // authenticator may wish to avoid bothering the user about linking.
  95. absl::optional<bool> supports_linking;
  96. // request_type contains the hinted type of the request. This can
  97. // be used to guide UI ahead of receiving the actual request. This defaults to
  98. // `kGetAssertion` if not present or if the value in the QR code is unknown.
  99. FidoRequestType request_type = FidoRequestType::kGetAssertion;
  100. };
  101. COMPONENT_EXPORT(DEVICE_FIDO)
  102. absl::optional<Components> Parse(const std::string& qr_url);
  103. // Encode returns the contents of a QR code that represents |qr_key|.
  104. COMPONENT_EXPORT(DEVICE_FIDO)
  105. std::string Encode(base::span<const uint8_t, kQRKeySize> qr_key,
  106. FidoRequestType request_type);
  107. // BytesToDigits returns a base-10 encoding of |in|.
  108. COMPONENT_EXPORT(DEVICE_FIDO)
  109. std::string BytesToDigits(base::span<const uint8_t> in);
  110. // DigitsToBytes reverses the actions of |BytesToDigits|.
  111. COMPONENT_EXPORT(DEVICE_FIDO)
  112. absl::optional<std::vector<uint8_t>> DigitsToBytes(base::StringPiece in);
  113. } // namespace qr
  114. namespace sync {
  115. // IDNow returns the current pairing ID for Sync. This is a very rough
  116. // timestamp.
  117. COMPONENT_EXPORT(DEVICE_FIDO) uint32_t IDNow();
  118. // IDIsValid returns true iff |candidate| is an acceptable pairing ID. This
  119. // determination is based on the current time since Sync pairing IDs are
  120. // timestamps in disguise.
  121. COMPONENT_EXPORT(DEVICE_FIDO) bool IDIsValid(uint32_t candidate);
  122. } // namespace sync
  123. // DerivedValueType enumerates the different types of values that might be
  124. // derived in caBLEv2 from some secret. The values this this enum are protocol
  125. // constants and thus must not change over time.
  126. enum class DerivedValueType : uint32_t {
  127. kEIDKey = 1,
  128. kTunnelID = 2,
  129. kPSK = 3,
  130. kPairedSecret = 4,
  131. kIdentityKeySeed = 5,
  132. kPerContactIDSecret = 6,
  133. };
  134. namespace internal {
  135. COMPONENT_EXPORT(DEVICE_FIDO)
  136. void Derive(uint8_t* out,
  137. size_t out_len,
  138. base::span<const uint8_t> secret,
  139. base::span<const uint8_t> nonce,
  140. DerivedValueType type);
  141. } // namespace internal
  142. // RequestTypeToString maps |request_type| to either "ga" (for getAssertion) or
  143. // "mc" (for makeCredential). These strings are encoded in the QR code and
  144. // client payload to give the phone an early hint about the type of request.
  145. // This lets it craft better UI.
  146. COMPONENT_EXPORT(DEVICE_FIDO)
  147. const char* RequestTypeToString(FidoRequestType request_type);
  148. // RequestTypeFromString performs the inverse of `RequestTypeToString`. If the
  149. // value of `s` is unknown, `kGetAssertion` is returned.
  150. COMPONENT_EXPORT(DEVICE_FIDO)
  151. FidoRequestType RequestTypeFromString(const std::string& s);
  152. // Derive derives a sub-secret from a secret and nonce. It is not possible to
  153. // learn anything about |secret| from the value of the sub-secret, assuming that
  154. // |secret| has sufficient size to prevent full enumeration of the
  155. // possibilities.
  156. template <size_t N>
  157. std::array<uint8_t, N> Derive(base::span<const uint8_t> secret,
  158. base::span<const uint8_t> nonce,
  159. DerivedValueType type) {
  160. std::array<uint8_t, N> ret;
  161. internal::Derive(ret.data(), N, secret, nonce, type);
  162. return ret;
  163. }
  164. // IdentityKey returns a P-256 private key derived from |root_secret|.
  165. COMPONENT_EXPORT(DEVICE_FIDO)
  166. bssl::UniquePtr<EC_KEY> IdentityKey(base::span<const uint8_t, 32> root_secret);
  167. // EncodePaddedCBORMap encodes the given map and pads it to
  168. // |kPostHandshakeMsgPaddingGranularity| bytes in such a way that
  169. // |DecodePaddedCBORMap| can decode it. The padding is done on the assumption
  170. // that the returned bytes will be encrypted and the encoded size of the map
  171. // should be hidden. The function can fail if the CBOR encoding fails or,
  172. // somehow, the size overflows.
  173. COMPONENT_EXPORT(DEVICE_FIDO)
  174. absl::optional<std::vector<uint8_t>> EncodePaddedCBORMap(
  175. cbor::Value::MapValue map);
  176. // DecodePaddedCBORMap unpads and decodes a CBOR map as produced by
  177. // |EncodePaddedCBORMap|.
  178. COMPONENT_EXPORT(DEVICE_FIDO)
  179. absl::optional<cbor::Value> DecodePaddedCBORMap(
  180. base::span<const uint8_t> input);
  181. // Crypter handles the post-handshake encryption of CTAP2 messages.
  182. class COMPONENT_EXPORT(DEVICE_FIDO) Crypter {
  183. public:
  184. Crypter(base::span<const uint8_t, 32> read_key,
  185. base::span<const uint8_t, 32> write_key);
  186. ~Crypter();
  187. // Encrypt encrypts |message_to_encrypt| and overrides it with the
  188. // ciphertext. It returns true on success and false on error.
  189. bool Encrypt(std::vector<uint8_t>* message_to_encrypt);
  190. // Decrypt decrypts |ciphertext|, which was received as the payload of a
  191. // message with the given command, and writes the plaintext to
  192. // |out_plaintext|. It returns true on success and false on error.
  193. //
  194. // (In practice, command must always be |kMsg|. But passing it here makes it
  195. // less likely that other code will forget to check that.)
  196. bool Decrypt(base::span<const uint8_t> ciphertext,
  197. std::vector<uint8_t>* out_plaintext);
  198. // Encrypt and decrypt with big-endian nonces and no additional data. This
  199. // is the format in the spec and that we want to transition to.
  200. void UseNewConstruction();
  201. // IsCounterpartyOfForTesting returns true if |other| is the mirror-image of
  202. // this object. (I.e. read/write keys are equal but swapped.)
  203. bool IsCounterpartyOfForTesting(const Crypter& other) const;
  204. bool& GetNewConstructionFlagForTesting();
  205. private:
  206. const std::array<uint8_t, 32> read_key_, write_key_;
  207. uint32_t read_sequence_num_ = 0;
  208. uint32_t write_sequence_num_ = 0;
  209. bool new_construction_ = false;
  210. };
  211. // HandshakeHash is the hashed transcript of a handshake. This can be used as a
  212. // channel-binding value. See
  213. // http://www.noiseprotocol.org/noise.html#channel-binding.
  214. using HandshakeHash = std::array<uint8_t, 32>;
  215. // HandshakeResult is the output of the handshaking process on both sides: a
  216. // |Crypter| that can encrypt and decrypt future messages on the connection, and
  217. // the handshake hash that can be used to tie signatures to the connection.
  218. using HandshakeResult =
  219. absl::optional<std::pair<std::unique_ptr<Crypter>, HandshakeHash>>;
  220. // HandshakeInitiator starts a caBLE v2 handshake and processes the single
  221. // response message from the other party. The handshake is always initiated from
  222. // the desktop.
  223. class COMPONENT_EXPORT(DEVICE_FIDO) HandshakeInitiator {
  224. public:
  225. HandshakeInitiator(
  226. // psk is derived from the connection nonce and either QR-code secrets
  227. // pairing secrets.
  228. base::span<const uint8_t, 32> psk,
  229. // peer_identity, if not nullopt, specifies that this is a paired
  230. // handshake and then contains a P-256 public key for the peer. Otherwise
  231. // this is a QR handshake.
  232. absl::optional<base::span<const uint8_t, kP256X962Length>> peer_identity,
  233. // identity_seed, if not nullopt, specifies that this is a QR handshake
  234. // and contains the seed for QR key for this client. identity_seed must be
  235. // provided iff |peer_identity| is not.
  236. absl::optional<base::span<const uint8_t, kQRSeedSize>> identity_seed);
  237. ~HandshakeInitiator();
  238. // BuildInitialMessage returns the handshake message to send to the peer to
  239. // start a handshake.
  240. std::vector<uint8_t> BuildInitialMessage();
  241. // ProcessResponse processes the handshake response from the peer. If
  242. // successful it returns a |Crypter| for protecting future messages on the
  243. // connection and a handshake transcript for signing over if needed.
  244. HandshakeResult ProcessResponse(base::span<const uint8_t> response);
  245. private:
  246. Noise noise_;
  247. std::array<uint8_t, 32> psk_;
  248. absl::optional<std::array<uint8_t, kP256X962Length>> peer_identity_;
  249. bssl::UniquePtr<EC_KEY> local_identity_;
  250. bssl::UniquePtr<EC_KEY> ephemeral_key_;
  251. };
  252. // RespondToHandshake responds to a caBLE v2 handshake started by a peer. Since
  253. // the desktop speaks first in caBLE, this is called by the phone.
  254. COMPONENT_EXPORT(DEVICE_FIDO)
  255. HandshakeResult RespondToHandshake(
  256. // psk is derived from the connection nonce and either QR-code secrets or
  257. // pairing secrets.
  258. base::span<const uint8_t, 32> psk,
  259. // identity, if not nullptr, specifies that this is a paired handshake and
  260. // contains the phone's private key.
  261. bssl::UniquePtr<EC_KEY> identity,
  262. // peer_identity, which must be non-nullopt iff |identity| is nullptr,
  263. // contains the peer's public key as taken from the QR code.
  264. absl::optional<base::span<const uint8_t, kP256X962Length>> peer_identity,
  265. // in contains the initial handshake message from the peer.
  266. base::span<const uint8_t> in,
  267. // out_response is set to the response handshake message, if successful.
  268. std::vector<uint8_t>* out_response);
  269. // VerifyPairingSignature checks that |signature| is a valid signature of
  270. // |handshake_hash| by |peer_public_key_x962|. This is used by a phone to prove
  271. // possession of |peer_public_key_x962| since the |handshake_hash| encloses
  272. // random values generated by the desktop and thus is a fresh value.
  273. COMPONENT_EXPORT(DEVICE_FIDO)
  274. bool VerifyPairingSignature(
  275. base::span<const uint8_t, kQRSeedSize> identity_seed,
  276. base::span<const uint8_t, kP256X962Length> peer_public_key_x962,
  277. base::span<const uint8_t, std::tuple_size<HandshakeHash>::value>
  278. handshake_hash,
  279. base::span<const uint8_t> signature);
  280. // CalculatePairingSignature generates a value that will satisfy
  281. // |VerifyPairingSignature|.
  282. COMPONENT_EXPORT(DEVICE_FIDO)
  283. std::vector<uint8_t> CalculatePairingSignature(
  284. const EC_KEY* identity_key,
  285. base::span<const uint8_t, kP256X962Length> peer_public_key_x962,
  286. base::span<const uint8_t, std::tuple_size<HandshakeHash>::value>
  287. handshake_hash);
  288. } // namespace cablev2
  289. } // namespace device
  290. #endif // DEVICE_FIDO_CABLE_V2_HANDSHAKE_H_