credential_management.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. // Copyright 2019 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/credential_management.h"
  5. #include "base/check_op.h"
  6. #include "components/cbor/reader.h"
  7. #include "components/cbor/values.h"
  8. #include "components/cbor/writer.h"
  9. #include "device/fido/fido_parsing_utils.h"
  10. #include "device/fido/pin.h"
  11. #include "third_party/boringssl/src/include/openssl/hmac.h"
  12. #include "third_party/boringssl/src/include/openssl/sha.h"
  13. namespace device {
  14. CredentialManagementRequest::CredentialManagementRequest(
  15. Version version_,
  16. CredentialManagementSubCommand subcommand_,
  17. absl::optional<cbor::Value::MapValue> params_)
  18. : version(version_), subcommand(subcommand_), params(std::move(params_)) {}
  19. CredentialManagementRequest::CredentialManagementRequest(
  20. CredentialManagementRequest&&) = default;
  21. CredentialManagementRequest& CredentialManagementRequest::operator=(
  22. CredentialManagementRequest&&) = default;
  23. CredentialManagementRequest::~CredentialManagementRequest() = default;
  24. // static
  25. CredentialManagementRequest CredentialManagementRequest::ForGetCredsMetadata(
  26. Version version,
  27. const pin::TokenResponse& token) {
  28. CredentialManagementRequest request(
  29. version, CredentialManagementSubCommand::kGetCredsMetadata,
  30. /*params=*/absl::nullopt);
  31. std::tie(request.pin_protocol, request.pin_auth) =
  32. token.PinAuth({{static_cast<uint8_t>(
  33. CredentialManagementSubCommand::kGetCredsMetadata)}});
  34. return request;
  35. }
  36. // static
  37. CredentialManagementRequest CredentialManagementRequest::ForEnumerateRPsBegin(
  38. Version version,
  39. const pin::TokenResponse& token) {
  40. CredentialManagementRequest request(
  41. version, CredentialManagementSubCommand::kEnumerateRPsBegin,
  42. /*params=*/absl::nullopt);
  43. std::tie(request.pin_protocol, request.pin_auth) =
  44. token.PinAuth({{static_cast<uint8_t>(
  45. CredentialManagementSubCommand::kEnumerateRPsBegin)}});
  46. return request;
  47. }
  48. // static
  49. CredentialManagementRequest CredentialManagementRequest::ForEnumerateRPsGetNext(
  50. Version version) {
  51. return CredentialManagementRequest(
  52. version, CredentialManagementSubCommand::kEnumerateRPsGetNextRP,
  53. /*params=*/absl::nullopt);
  54. }
  55. // static
  56. CredentialManagementRequest
  57. CredentialManagementRequest::ForEnumerateCredentialsBegin(
  58. Version version,
  59. const pin::TokenResponse& token,
  60. std::array<uint8_t, kRpIdHashLength> rp_id_hash) {
  61. cbor::Value::MapValue params_map;
  62. params_map.emplace(
  63. static_cast<int>(CredentialManagementRequestParamKey::kRPIDHash),
  64. std::move(rp_id_hash));
  65. std::vector<uint8_t> pin_auth_bytes =
  66. *cbor::Writer::Write(cbor::Value(params_map));
  67. CredentialManagementRequest request(
  68. version, CredentialManagementSubCommand::kEnumerateCredentialsBegin,
  69. std::move(params_map));
  70. pin_auth_bytes.insert(
  71. pin_auth_bytes.begin(),
  72. static_cast<uint8_t>(
  73. CredentialManagementSubCommand::kEnumerateCredentialsBegin));
  74. std::tie(request.pin_protocol, request.pin_auth) =
  75. token.PinAuth(pin_auth_bytes);
  76. return request;
  77. }
  78. // static
  79. CredentialManagementRequest
  80. CredentialManagementRequest::ForEnumerateCredentialsGetNext(Version version) {
  81. return CredentialManagementRequest(
  82. version,
  83. CredentialManagementSubCommand::kEnumerateCredentialsGetNextCredential,
  84. /*params=*/absl::nullopt);
  85. }
  86. // static
  87. CredentialManagementRequest CredentialManagementRequest::ForDeleteCredential(
  88. Version version,
  89. const pin::TokenResponse& token,
  90. const PublicKeyCredentialDescriptor& credential_id) {
  91. cbor::Value::MapValue params_map;
  92. params_map.emplace(
  93. static_cast<int>(CredentialManagementRequestParamKey::kCredentialID),
  94. AsCBOR(credential_id));
  95. std::vector<uint8_t> pin_auth_bytes =
  96. *cbor::Writer::Write(cbor::Value(params_map));
  97. CredentialManagementRequest request(
  98. version, CredentialManagementSubCommand::kDeleteCredential,
  99. std::move(params_map));
  100. pin_auth_bytes.insert(
  101. pin_auth_bytes.begin(),
  102. static_cast<uint8_t>(CredentialManagementSubCommand::kDeleteCredential));
  103. std::tie(request.pin_protocol, request.pin_auth) =
  104. token.PinAuth(pin_auth_bytes);
  105. return request;
  106. }
  107. // static
  108. CredentialManagementRequest
  109. CredentialManagementRequest::ForUpdateUserInformation(
  110. Version version,
  111. const pin::TokenResponse& token,
  112. const PublicKeyCredentialDescriptor& credential_id,
  113. const PublicKeyCredentialUserEntity& updated_user) {
  114. cbor::Value::MapValue params_map;
  115. params_map.emplace(
  116. static_cast<int>(CredentialManagementRequestParamKey::kCredentialID),
  117. AsCBOR(credential_id));
  118. params_map.emplace(
  119. static_cast<int>(CredentialManagementRequestParamKey::kUser),
  120. AsCBOR(updated_user));
  121. std::vector<uint8_t> pin_auth_bytes =
  122. *cbor::Writer::Write(cbor::Value(params_map));
  123. CredentialManagementRequest request(
  124. version, CredentialManagementSubCommand::kUpdateUserInformation,
  125. std::move(params_map));
  126. pin_auth_bytes.insert(
  127. pin_auth_bytes.begin(),
  128. static_cast<uint8_t>(
  129. CredentialManagementSubCommand::kUpdateUserInformation));
  130. std::tie(request.pin_protocol, request.pin_auth) =
  131. token.PinAuth(pin_auth_bytes);
  132. return request;
  133. }
  134. // static
  135. absl::optional<CredentialsMetadataResponse> CredentialsMetadataResponse::Parse(
  136. const absl::optional<cbor::Value>& cbor_response) {
  137. CredentialsMetadataResponse response;
  138. if (!cbor_response || !cbor_response->is_map()) {
  139. return absl::nullopt;
  140. }
  141. const cbor::Value::MapValue& response_map = cbor_response->GetMap();
  142. auto it = response_map.find(cbor::Value(static_cast<int>(
  143. CredentialManagementResponseKey::kExistingResidentCredentialsCount)));
  144. if (it == response_map.end() || !it->second.is_unsigned()) {
  145. return absl::nullopt;
  146. }
  147. const int64_t existing_count = it->second.GetUnsigned();
  148. if (existing_count > std::numeric_limits<size_t>::max()) {
  149. return absl::nullopt;
  150. }
  151. response.num_existing_credentials = static_cast<size_t>(existing_count);
  152. it = response_map.find(cbor::Value(
  153. static_cast<int>(CredentialManagementResponseKey::
  154. kMaxPossibleRemainingResidentCredentialsCount)));
  155. if (it == response_map.end() || !it->second.is_unsigned()) {
  156. return absl::nullopt;
  157. }
  158. const int64_t remaining_count = it->second.GetUnsigned();
  159. if (remaining_count > std::numeric_limits<size_t>::max()) {
  160. return absl::nullopt;
  161. }
  162. response.num_estimated_remaining_credentials =
  163. static_cast<size_t>(remaining_count);
  164. return response;
  165. }
  166. // static
  167. absl::optional<EnumerateRPsResponse> EnumerateRPsResponse::Parse(
  168. bool expect_rp_count,
  169. const absl::optional<cbor::Value>& cbor_response) {
  170. if (!cbor_response) {
  171. // Some authenticators send an empty response if there are no RPs (though
  172. // the spec doesn't say that).
  173. return EnumerateRPsResponse(absl::nullopt, absl::nullopt, 0);
  174. }
  175. if (!cbor_response->is_map() || cbor_response->GetMap().empty()) {
  176. return absl::nullopt;
  177. }
  178. const cbor::Value::MapValue& response_map = cbor_response->GetMap();
  179. size_t rp_count = 0;
  180. auto it = response_map.find(cbor::Value(
  181. static_cast<int>(CredentialManagementResponseKey::kTotalRPs)));
  182. if (!expect_rp_count && it != response_map.end()) {
  183. return absl::nullopt;
  184. }
  185. if (expect_rp_count) {
  186. if (it == response_map.end() || !it->second.is_unsigned() ||
  187. it->second.GetUnsigned() > std::numeric_limits<size_t>::max()) {
  188. return absl::nullopt;
  189. }
  190. rp_count = static_cast<size_t>(it->second.GetUnsigned());
  191. if (rp_count == 0) {
  192. if (response_map.size() != 1) {
  193. return absl::nullopt;
  194. }
  195. return EnumerateRPsResponse(absl::nullopt, absl::nullopt, 0);
  196. }
  197. }
  198. it = response_map.find(
  199. cbor::Value(static_cast<int>(CredentialManagementResponseKey::kRP)));
  200. if (it == response_map.end()) {
  201. return absl::nullopt;
  202. }
  203. auto opt_rp = PublicKeyCredentialRpEntity::CreateFromCBORValue(it->second);
  204. if (!opt_rp) {
  205. return absl::nullopt;
  206. }
  207. it = response_map.find(cbor::Value(
  208. static_cast<int>(CredentialManagementResponseKey::kRPIDHash)));
  209. if (it == response_map.end() || !it->second.is_bytestring()) {
  210. return absl::nullopt;
  211. }
  212. const std::vector<uint8_t>& rp_id_hash_bytes = it->second.GetBytestring();
  213. if (rp_id_hash_bytes.size() != kRpIdHashLength) {
  214. return absl::nullopt;
  215. }
  216. std::array<uint8_t, kRpIdHashLength> rp_id_hash;
  217. std::copy_n(rp_id_hash_bytes.begin(), kRpIdHashLength, rp_id_hash.begin());
  218. return EnumerateRPsResponse(std::move(*opt_rp), std::move(rp_id_hash),
  219. rp_count);
  220. }
  221. // static
  222. bool EnumerateRPsResponse::StringFixupPredicate(
  223. const std::vector<const cbor::Value*>& path) {
  224. // In the rp field (0x04), "name" may be truncated.
  225. if (path.size() != 2 || !path[0]->is_unsigned() ||
  226. path[0]->GetUnsigned() !=
  227. static_cast<int>(CredentialManagementResponseKey::kRP) ||
  228. !path[1]->is_string()) {
  229. return false;
  230. }
  231. return path[1]->GetString() == "name";
  232. }
  233. EnumerateRPsResponse::EnumerateRPsResponse(EnumerateRPsResponse&&) = default;
  234. EnumerateRPsResponse& EnumerateRPsResponse::operator=(EnumerateRPsResponse&&) =
  235. default;
  236. EnumerateRPsResponse::~EnumerateRPsResponse() = default;
  237. EnumerateRPsResponse::EnumerateRPsResponse(
  238. absl::optional<PublicKeyCredentialRpEntity> rp_,
  239. absl::optional<std::array<uint8_t, kRpIdHashLength>> rp_id_hash_,
  240. size_t rp_count_)
  241. : rp(std::move(rp_)),
  242. rp_id_hash(std::move(rp_id_hash_)),
  243. rp_count(rp_count_) {}
  244. // static
  245. absl::optional<EnumerateCredentialsResponse>
  246. EnumerateCredentialsResponse::Parse(
  247. bool expect_credential_count,
  248. const absl::optional<cbor::Value>& cbor_response) {
  249. if (!cbor_response || !cbor_response->is_map()) {
  250. // Note that some authenticators may send an empty response if they don't
  251. // have a credential for a given RP ID hash (though the spec doesn't say
  252. // that). However, that case should not be reached from
  253. // CredentialManagementHandler.
  254. return absl::nullopt;
  255. }
  256. const cbor::Value::MapValue& response_map = cbor_response->GetMap();
  257. auto it = response_map.find(
  258. cbor::Value(static_cast<int>(CredentialManagementResponseKey::kUser)));
  259. if (it == response_map.end()) {
  260. return absl::nullopt;
  261. }
  262. auto opt_user =
  263. PublicKeyCredentialUserEntity::CreateFromCBORValue(it->second);
  264. if (!opt_user) {
  265. return absl::nullopt;
  266. }
  267. it = response_map.find(cbor::Value(
  268. static_cast<int>(CredentialManagementResponseKey::kCredentialID)));
  269. if (it == response_map.end()) {
  270. return absl::nullopt;
  271. }
  272. auto opt_credential_id =
  273. PublicKeyCredentialDescriptor::CreateFromCBORValue(it->second);
  274. if (!opt_credential_id) {
  275. return absl::nullopt;
  276. }
  277. // Ignore the public key's value.
  278. it = response_map.find(cbor::Value(
  279. static_cast<int>(CredentialManagementResponseKey::kPublicKey)));
  280. if (it == response_map.end() || !it->second.is_map()) {
  281. return absl::nullopt;
  282. }
  283. size_t credential_count = 0;
  284. if (!expect_credential_count) {
  285. if (response_map.find(cbor::Value(static_cast<int>(
  286. CredentialManagementResponseKey::kTotalCredentials))) !=
  287. response_map.end()) {
  288. return absl::nullopt;
  289. }
  290. } else {
  291. it = response_map.find(cbor::Value(
  292. static_cast<int>(CredentialManagementResponseKey::kTotalCredentials)));
  293. if (it == response_map.end() || !it->second.is_unsigned() ||
  294. it->second.GetUnsigned() == 0 ||
  295. it->second.GetUnsigned() > std::numeric_limits<size_t>::max()) {
  296. return absl::nullopt;
  297. }
  298. credential_count = static_cast<size_t>(it->second.GetUnsigned());
  299. }
  300. return EnumerateCredentialsResponse(
  301. std::move(*opt_user), std::move(*opt_credential_id), credential_count);
  302. }
  303. // static
  304. bool EnumerateCredentialsResponse::StringFixupPredicate(
  305. const std::vector<const cbor::Value*>& path) {
  306. // In the user field (0x06), "name" or "displayName" may be truncated.
  307. if (path.size() != 2 || !path[0]->is_unsigned() ||
  308. path[0]->GetUnsigned() !=
  309. static_cast<int>(CredentialManagementResponseKey::kUser) ||
  310. !path[1]->is_string()) {
  311. return false;
  312. }
  313. const std::string& user_key = path[1]->GetString();
  314. return user_key == "name" || user_key == "displayName";
  315. }
  316. EnumerateCredentialsResponse::EnumerateCredentialsResponse(
  317. EnumerateCredentialsResponse&&) = default;
  318. EnumerateCredentialsResponse& EnumerateCredentialsResponse::operator=(
  319. EnumerateCredentialsResponse&&) = default;
  320. EnumerateCredentialsResponse::~EnumerateCredentialsResponse() = default;
  321. EnumerateCredentialsResponse::EnumerateCredentialsResponse(
  322. PublicKeyCredentialUserEntity user_,
  323. PublicKeyCredentialDescriptor credential_id_,
  324. size_t credential_count_)
  325. : user(std::move(user_)),
  326. credential_id(std::move(credential_id_)),
  327. credential_count(credential_count_) {}
  328. AggregatedEnumerateCredentialsResponse::AggregatedEnumerateCredentialsResponse(
  329. PublicKeyCredentialRpEntity rp_)
  330. : rp(std::move(rp_)), credentials() {}
  331. AggregatedEnumerateCredentialsResponse::AggregatedEnumerateCredentialsResponse(
  332. AggregatedEnumerateCredentialsResponse&&) = default;
  333. AggregatedEnumerateCredentialsResponse&
  334. AggregatedEnumerateCredentialsResponse::operator=(
  335. AggregatedEnumerateCredentialsResponse&&) = default;
  336. AggregatedEnumerateCredentialsResponse::
  337. ~AggregatedEnumerateCredentialsResponse() = default;
  338. std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
  339. AsCTAPRequestValuePair(const CredentialManagementRequest& request) {
  340. cbor::Value::MapValue request_map;
  341. request_map.emplace(
  342. static_cast<int>(CredentialManagementRequestKey::kSubCommand),
  343. static_cast<int>(request.subcommand));
  344. if (request.params) {
  345. request_map.emplace(
  346. static_cast<int>(CredentialManagementRequestKey::kSubCommandParams),
  347. *request.params);
  348. }
  349. DCHECK_EQ(request.pin_protocol.has_value(), request.pin_auth.has_value());
  350. if (request.pin_auth) {
  351. request_map.emplace(
  352. static_cast<int>(CredentialManagementRequestKey::kPinProtocol),
  353. static_cast<uint8_t>(*request.pin_protocol));
  354. request_map.emplace(
  355. static_cast<int>(CredentialManagementRequestKey::kPinAuth),
  356. *request.pin_auth);
  357. }
  358. return {request.version == CredentialManagementRequest::kPreview
  359. ? CtapRequestCommand::kAuthenticatorCredentialManagementPreview
  360. : CtapRequestCommand::kAuthenticatorCredentialManagement,
  361. cbor::Value(std::move(request_map))};
  362. }
  363. } // namespace device