ctap_get_assertion_request.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "device/fido/ctap_get_assertion_request.h"
  5. #include <algorithm>
  6. #include <limits>
  7. #include <utility>
  8. #include "base/numerics/safe_conversions.h"
  9. #include "components/cbor/writer.h"
  10. #include "device/fido/device_response_converter.h"
  11. #include "device/fido/fido_constants.h"
  12. #include "device/fido/fido_parsing_utils.h"
  13. #include "device/fido/pin.h"
  14. namespace device {
  15. namespace {
  16. bool IsGetAssertionOptionMapFormatCorrect(
  17. const cbor::Value::MapValue& option_map) {
  18. return std::all_of(
  19. option_map.begin(), option_map.end(), [](const auto& param) {
  20. return param.first.is_string() &&
  21. (param.first.GetString() == kUserPresenceMapKey ||
  22. param.first.GetString() == kUserVerificationMapKey) &&
  23. param.second.is_bool();
  24. });
  25. }
  26. bool AreGetAssertionRequestMapKeysCorrect(
  27. const cbor::Value::MapValue& request_map) {
  28. return std::all_of(
  29. request_map.begin(), request_map.end(), [](const auto& param) {
  30. return (param.first.is_integer() && 1u <= param.first.GetInteger() &&
  31. param.first.GetInteger() <= 7u);
  32. });
  33. }
  34. } // namespace
  35. CtapGetAssertionOptions::CtapGetAssertionOptions() = default;
  36. CtapGetAssertionOptions::CtapGetAssertionOptions(
  37. const CtapGetAssertionOptions&) = default;
  38. CtapGetAssertionOptions::CtapGetAssertionOptions(CtapGetAssertionOptions&&) =
  39. default;
  40. CtapGetAssertionOptions::~CtapGetAssertionOptions() = default;
  41. CtapGetAssertionOptions::PRFInput::PRFInput() = default;
  42. CtapGetAssertionOptions::PRFInput::PRFInput(const PRFInput&) = default;
  43. CtapGetAssertionOptions::PRFInput::PRFInput(PRFInput&&) = default;
  44. CtapGetAssertionOptions::PRFInput::~PRFInput() = default;
  45. CtapGetAssertionRequest::HMACSecret::HMACSecret(
  46. base::span<const uint8_t, kP256X962Length> in_public_key_x962,
  47. base::span<const uint8_t> in_encrypted_salts,
  48. base::span<const uint8_t> in_salts_auth)
  49. : public_key_x962(fido_parsing_utils::Materialize(in_public_key_x962)),
  50. encrypted_salts(fido_parsing_utils::Materialize(in_encrypted_salts)),
  51. salts_auth(fido_parsing_utils::Materialize(in_salts_auth)) {}
  52. CtapGetAssertionRequest::HMACSecret::HMACSecret(const HMACSecret&) = default;
  53. CtapGetAssertionRequest::HMACSecret::~HMACSecret() = default;
  54. CtapGetAssertionRequest::HMACSecret&
  55. CtapGetAssertionRequest::HMACSecret::operator=(const HMACSecret&) = default;
  56. // static
  57. absl::optional<CtapGetAssertionRequest> CtapGetAssertionRequest::Parse(
  58. const cbor::Value::MapValue& request_map,
  59. const ParseOpts& opts) {
  60. if (!AreGetAssertionRequestMapKeysCorrect(request_map))
  61. return absl::nullopt;
  62. const auto rp_id_it = request_map.find(cbor::Value(1));
  63. if (rp_id_it == request_map.end() || !rp_id_it->second.is_string())
  64. return absl::nullopt;
  65. const auto client_data_hash_it = request_map.find(cbor::Value(2));
  66. if (client_data_hash_it == request_map.end() ||
  67. !client_data_hash_it->second.is_bytestring() ||
  68. client_data_hash_it->second.GetBytestring().size() !=
  69. kClientDataHashLength) {
  70. return absl::nullopt;
  71. }
  72. base::span<const uint8_t, kClientDataHashLength> client_data_hash(
  73. client_data_hash_it->second.GetBytestring().data(),
  74. kClientDataHashLength);
  75. CtapGetAssertionRequest request(rp_id_it->second.GetString(),
  76. /*client_data_json=*/std::string());
  77. request.client_data_hash = fido_parsing_utils::Materialize(client_data_hash);
  78. const auto allow_list_it = request_map.find(cbor::Value(3));
  79. if (allow_list_it != request_map.end()) {
  80. if (!allow_list_it->second.is_array())
  81. return absl::nullopt;
  82. const auto& credential_descriptors = allow_list_it->second.GetArray();
  83. if (credential_descriptors.empty())
  84. return absl::nullopt;
  85. std::vector<PublicKeyCredentialDescriptor> allow_list;
  86. for (const auto& credential_descriptor : credential_descriptors) {
  87. auto allowed_credential =
  88. PublicKeyCredentialDescriptor::CreateFromCBORValue(
  89. credential_descriptor);
  90. if (!allowed_credential)
  91. return absl::nullopt;
  92. allow_list.push_back(std::move(*allowed_credential));
  93. }
  94. request.allow_list = std::move(allow_list);
  95. }
  96. const auto extensions_it = request_map.find(cbor::Value(4));
  97. if (extensions_it != request_map.end()) {
  98. if (!extensions_it->second.is_map()) {
  99. return absl::nullopt;
  100. }
  101. const cbor::Value::MapValue& extensions = extensions_it->second.GetMap();
  102. if (opts.reject_all_extensions && !extensions.empty()) {
  103. return absl::nullopt;
  104. }
  105. for (const auto& extension : extensions) {
  106. if (!extension.first.is_string()) {
  107. return absl::nullopt;
  108. }
  109. const std::string& extension_id = extension.first.GetString();
  110. if (extension_id == kExtensionHmacSecret) {
  111. if (!extension.second.is_map()) {
  112. return absl::nullopt;
  113. }
  114. const auto& hmac_extension = extension.second.GetMap();
  115. auto hmac_it = hmac_extension.find(cbor::Value(1));
  116. if (hmac_it == hmac_extension.end() || !hmac_it->second.is_map()) {
  117. return absl::nullopt;
  118. }
  119. const absl::optional<pin::KeyAgreementResponse> key(
  120. pin::KeyAgreementResponse::ParseFromCOSE(hmac_it->second.GetMap()));
  121. hmac_it = hmac_extension.find(cbor::Value(2));
  122. if (hmac_it == hmac_extension.end() ||
  123. !hmac_it->second.is_bytestring()) {
  124. return absl::nullopt;
  125. }
  126. const std::vector<uint8_t>& encrypted_salts =
  127. hmac_it->second.GetBytestring();
  128. hmac_it = hmac_extension.find(cbor::Value(3));
  129. if (hmac_it == hmac_extension.end() ||
  130. !hmac_it->second.is_bytestring()) {
  131. return absl::nullopt;
  132. }
  133. const std::vector<uint8_t>& salts_auth =
  134. hmac_it->second.GetBytestring();
  135. if (!key ||
  136. (encrypted_salts.size() != 32 && encrypted_salts.size() != 64) ||
  137. salts_auth.size() != 16) {
  138. return absl::nullopt;
  139. }
  140. request.hmac_secret.emplace(key->X962(), encrypted_salts, salts_auth);
  141. } else if (extension_id == kExtensionLargeBlobKey) {
  142. if (!extension.second.is_bool() || !extension.second.GetBool()) {
  143. return absl::nullopt;
  144. }
  145. request.large_blob_key = true;
  146. } else if (extension_id == kExtensionCredBlob) {
  147. if (!extension.second.is_bool() || !extension.second.GetBool()) {
  148. return absl::nullopt;
  149. }
  150. request.get_cred_blob = true;
  151. }
  152. }
  153. }
  154. const auto option_it = request_map.find(cbor::Value(5));
  155. if (option_it != request_map.end()) {
  156. if (!option_it->second.is_map())
  157. return absl::nullopt;
  158. const auto& option_map = option_it->second.GetMap();
  159. if (!IsGetAssertionOptionMapFormatCorrect(option_map))
  160. return absl::nullopt;
  161. const auto user_presence_option =
  162. option_map.find(cbor::Value(kUserPresenceMapKey));
  163. if (user_presence_option != option_map.end()) {
  164. request.user_presence_required = user_presence_option->second.GetBool();
  165. }
  166. const auto uv_option =
  167. option_map.find(cbor::Value(kUserVerificationMapKey));
  168. if (uv_option != option_map.end()) {
  169. request.user_verification =
  170. uv_option->second.GetBool()
  171. ? UserVerificationRequirement::kRequired
  172. : UserVerificationRequirement::kDiscouraged;
  173. }
  174. }
  175. const auto pin_auth_it = request_map.find(cbor::Value(6));
  176. if (pin_auth_it != request_map.end()) {
  177. if (!pin_auth_it->second.is_bytestring())
  178. return absl::nullopt;
  179. request.pin_auth = pin_auth_it->second.GetBytestring();
  180. }
  181. const auto pin_protocol_it = request_map.find(cbor::Value(7));
  182. if (pin_protocol_it != request_map.end()) {
  183. if (!pin_protocol_it->second.is_unsigned() ||
  184. pin_protocol_it->second.GetUnsigned() >
  185. std::numeric_limits<uint8_t>::max()) {
  186. return absl::nullopt;
  187. }
  188. absl::optional<PINUVAuthProtocol> pin_protocol =
  189. ToPINUVAuthProtocol(pin_protocol_it->second.GetUnsigned());
  190. if (!pin_protocol) {
  191. return absl::nullopt;
  192. }
  193. request.pin_protocol = *pin_protocol;
  194. }
  195. return request;
  196. }
  197. CtapGetAssertionRequest::CtapGetAssertionRequest(
  198. std::string in_rp_id,
  199. std::string in_client_data_json)
  200. : rp_id(std::move(in_rp_id)),
  201. client_data_json(std::move(in_client_data_json)),
  202. client_data_hash(fido_parsing_utils::CreateSHA256Hash(client_data_json)) {
  203. }
  204. CtapGetAssertionRequest::CtapGetAssertionRequest(
  205. const CtapGetAssertionRequest& that) = default;
  206. CtapGetAssertionRequest::CtapGetAssertionRequest(
  207. CtapGetAssertionRequest&& that) = default;
  208. CtapGetAssertionRequest& CtapGetAssertionRequest::operator=(
  209. const CtapGetAssertionRequest& other) = default;
  210. CtapGetAssertionRequest& CtapGetAssertionRequest::operator=(
  211. CtapGetAssertionRequest&& other) = default;
  212. CtapGetAssertionRequest::~CtapGetAssertionRequest() = default;
  213. std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
  214. AsCTAPRequestValuePair(const CtapGetAssertionRequest& request) {
  215. cbor::Value::MapValue cbor_map;
  216. cbor_map[cbor::Value(1)] = cbor::Value(request.rp_id);
  217. cbor_map[cbor::Value(2)] = cbor::Value(request.client_data_hash);
  218. if (!request.allow_list.empty()) {
  219. cbor::Value::ArrayValue allow_list_array;
  220. for (const auto& descriptor : request.allow_list) {
  221. allow_list_array.push_back(AsCBOR(descriptor));
  222. }
  223. cbor_map[cbor::Value(3)] = cbor::Value(std::move(allow_list_array));
  224. }
  225. cbor::Value::MapValue extensions;
  226. if (request.large_blob_key) {
  227. extensions.emplace(kExtensionLargeBlobKey, cbor::Value(true));
  228. }
  229. if (request.hmac_secret) {
  230. const auto& hmac_secret = *request.hmac_secret;
  231. cbor::Value::MapValue hmac_extension;
  232. hmac_extension.emplace(
  233. 1, pin::EncodeCOSEPublicKey(hmac_secret.public_key_x962));
  234. hmac_extension.emplace(2, hmac_secret.encrypted_salts);
  235. hmac_extension.emplace(3, hmac_secret.salts_auth);
  236. extensions.emplace(kExtensionHmacSecret, std::move(hmac_extension));
  237. }
  238. if (request.get_cred_blob) {
  239. extensions.emplace(kExtensionCredBlob, true);
  240. }
  241. if (!extensions.empty()) {
  242. cbor_map[cbor::Value(4)] = cbor::Value(std::move(extensions));
  243. }
  244. if (request.pin_auth) {
  245. cbor_map[cbor::Value(6)] = cbor::Value(*request.pin_auth);
  246. }
  247. if (request.pin_protocol) {
  248. cbor_map[cbor::Value(7)] =
  249. cbor::Value(static_cast<uint8_t>(*request.pin_protocol));
  250. }
  251. cbor::Value::MapValue option_map;
  252. // User presence is required by default.
  253. if (!request.user_presence_required) {
  254. option_map[cbor::Value(kUserPresenceMapKey)] =
  255. cbor::Value(request.user_presence_required);
  256. }
  257. // User verification is not required by default.
  258. if (request.user_verification == UserVerificationRequirement::kRequired) {
  259. option_map[cbor::Value(kUserVerificationMapKey)] = cbor::Value(true);
  260. }
  261. if (!option_map.empty()) {
  262. cbor_map[cbor::Value(5)] = cbor::Value(std::move(option_map));
  263. }
  264. return std::make_pair(CtapRequestCommand::kAuthenticatorGetAssertion,
  265. cbor::Value(std::move(cbor_map)));
  266. }
  267. std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
  268. AsCTAPRequestValuePair(const CtapGetNextAssertionRequest&) {
  269. return std::make_pair(CtapRequestCommand::kAuthenticatorGetNextAssertion,
  270. absl::nullopt);
  271. }
  272. } // namespace device