123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 |
- // Copyright 2019 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "device/fido/credential_management.h"
- #include "base/check_op.h"
- #include "components/cbor/reader.h"
- #include "components/cbor/values.h"
- #include "components/cbor/writer.h"
- #include "device/fido/fido_parsing_utils.h"
- #include "device/fido/pin.h"
- #include "third_party/boringssl/src/include/openssl/hmac.h"
- #include "third_party/boringssl/src/include/openssl/sha.h"
- namespace device {
- CredentialManagementRequest::CredentialManagementRequest(
- Version version_,
- CredentialManagementSubCommand subcommand_,
- absl::optional<cbor::Value::MapValue> params_)
- : version(version_), subcommand(subcommand_), params(std::move(params_)) {}
- CredentialManagementRequest::CredentialManagementRequest(
- CredentialManagementRequest&&) = default;
- CredentialManagementRequest& CredentialManagementRequest::operator=(
- CredentialManagementRequest&&) = default;
- CredentialManagementRequest::~CredentialManagementRequest() = default;
- // static
- CredentialManagementRequest CredentialManagementRequest::ForGetCredsMetadata(
- Version version,
- const pin::TokenResponse& token) {
- CredentialManagementRequest request(
- version, CredentialManagementSubCommand::kGetCredsMetadata,
- /*params=*/absl::nullopt);
- std::tie(request.pin_protocol, request.pin_auth) =
- token.PinAuth({{static_cast<uint8_t>(
- CredentialManagementSubCommand::kGetCredsMetadata)}});
- return request;
- }
- // static
- CredentialManagementRequest CredentialManagementRequest::ForEnumerateRPsBegin(
- Version version,
- const pin::TokenResponse& token) {
- CredentialManagementRequest request(
- version, CredentialManagementSubCommand::kEnumerateRPsBegin,
- /*params=*/absl::nullopt);
- std::tie(request.pin_protocol, request.pin_auth) =
- token.PinAuth({{static_cast<uint8_t>(
- CredentialManagementSubCommand::kEnumerateRPsBegin)}});
- return request;
- }
- // static
- CredentialManagementRequest CredentialManagementRequest::ForEnumerateRPsGetNext(
- Version version) {
- return CredentialManagementRequest(
- version, CredentialManagementSubCommand::kEnumerateRPsGetNextRP,
- /*params=*/absl::nullopt);
- }
- // static
- CredentialManagementRequest
- CredentialManagementRequest::ForEnumerateCredentialsBegin(
- Version version,
- const pin::TokenResponse& token,
- std::array<uint8_t, kRpIdHashLength> rp_id_hash) {
- cbor::Value::MapValue params_map;
- params_map.emplace(
- static_cast<int>(CredentialManagementRequestParamKey::kRPIDHash),
- std::move(rp_id_hash));
- std::vector<uint8_t> pin_auth_bytes =
- *cbor::Writer::Write(cbor::Value(params_map));
- CredentialManagementRequest request(
- version, CredentialManagementSubCommand::kEnumerateCredentialsBegin,
- std::move(params_map));
- pin_auth_bytes.insert(
- pin_auth_bytes.begin(),
- static_cast<uint8_t>(
- CredentialManagementSubCommand::kEnumerateCredentialsBegin));
- std::tie(request.pin_protocol, request.pin_auth) =
- token.PinAuth(pin_auth_bytes);
- return request;
- }
- // static
- CredentialManagementRequest
- CredentialManagementRequest::ForEnumerateCredentialsGetNext(Version version) {
- return CredentialManagementRequest(
- version,
- CredentialManagementSubCommand::kEnumerateCredentialsGetNextCredential,
- /*params=*/absl::nullopt);
- }
- // static
- CredentialManagementRequest CredentialManagementRequest::ForDeleteCredential(
- Version version,
- const pin::TokenResponse& token,
- const PublicKeyCredentialDescriptor& credential_id) {
- cbor::Value::MapValue params_map;
- params_map.emplace(
- static_cast<int>(CredentialManagementRequestParamKey::kCredentialID),
- AsCBOR(credential_id));
- std::vector<uint8_t> pin_auth_bytes =
- *cbor::Writer::Write(cbor::Value(params_map));
- CredentialManagementRequest request(
- version, CredentialManagementSubCommand::kDeleteCredential,
- std::move(params_map));
- pin_auth_bytes.insert(
- pin_auth_bytes.begin(),
- static_cast<uint8_t>(CredentialManagementSubCommand::kDeleteCredential));
- std::tie(request.pin_protocol, request.pin_auth) =
- token.PinAuth(pin_auth_bytes);
- return request;
- }
- // static
- CredentialManagementRequest
- CredentialManagementRequest::ForUpdateUserInformation(
- Version version,
- const pin::TokenResponse& token,
- const PublicKeyCredentialDescriptor& credential_id,
- const PublicKeyCredentialUserEntity& updated_user) {
- cbor::Value::MapValue params_map;
- params_map.emplace(
- static_cast<int>(CredentialManagementRequestParamKey::kCredentialID),
- AsCBOR(credential_id));
- params_map.emplace(
- static_cast<int>(CredentialManagementRequestParamKey::kUser),
- AsCBOR(updated_user));
- std::vector<uint8_t> pin_auth_bytes =
- *cbor::Writer::Write(cbor::Value(params_map));
- CredentialManagementRequest request(
- version, CredentialManagementSubCommand::kUpdateUserInformation,
- std::move(params_map));
- pin_auth_bytes.insert(
- pin_auth_bytes.begin(),
- static_cast<uint8_t>(
- CredentialManagementSubCommand::kUpdateUserInformation));
- std::tie(request.pin_protocol, request.pin_auth) =
- token.PinAuth(pin_auth_bytes);
- return request;
- }
- // static
- absl::optional<CredentialsMetadataResponse> CredentialsMetadataResponse::Parse(
- const absl::optional<cbor::Value>& cbor_response) {
- CredentialsMetadataResponse response;
- if (!cbor_response || !cbor_response->is_map()) {
- return absl::nullopt;
- }
- const cbor::Value::MapValue& response_map = cbor_response->GetMap();
- auto it = response_map.find(cbor::Value(static_cast<int>(
- CredentialManagementResponseKey::kExistingResidentCredentialsCount)));
- if (it == response_map.end() || !it->second.is_unsigned()) {
- return absl::nullopt;
- }
- const int64_t existing_count = it->second.GetUnsigned();
- if (existing_count > std::numeric_limits<size_t>::max()) {
- return absl::nullopt;
- }
- response.num_existing_credentials = static_cast<size_t>(existing_count);
- it = response_map.find(cbor::Value(
- static_cast<int>(CredentialManagementResponseKey::
- kMaxPossibleRemainingResidentCredentialsCount)));
- if (it == response_map.end() || !it->second.is_unsigned()) {
- return absl::nullopt;
- }
- const int64_t remaining_count = it->second.GetUnsigned();
- if (remaining_count > std::numeric_limits<size_t>::max()) {
- return absl::nullopt;
- }
- response.num_estimated_remaining_credentials =
- static_cast<size_t>(remaining_count);
- return response;
- }
- // static
- absl::optional<EnumerateRPsResponse> EnumerateRPsResponse::Parse(
- bool expect_rp_count,
- const absl::optional<cbor::Value>& cbor_response) {
- if (!cbor_response) {
- // Some authenticators send an empty response if there are no RPs (though
- // the spec doesn't say that).
- return EnumerateRPsResponse(absl::nullopt, absl::nullopt, 0);
- }
- if (!cbor_response->is_map() || cbor_response->GetMap().empty()) {
- return absl::nullopt;
- }
- const cbor::Value::MapValue& response_map = cbor_response->GetMap();
- size_t rp_count = 0;
- auto it = response_map.find(cbor::Value(
- static_cast<int>(CredentialManagementResponseKey::kTotalRPs)));
- if (!expect_rp_count && it != response_map.end()) {
- return absl::nullopt;
- }
- if (expect_rp_count) {
- if (it == response_map.end() || !it->second.is_unsigned() ||
- it->second.GetUnsigned() > std::numeric_limits<size_t>::max()) {
- return absl::nullopt;
- }
- rp_count = static_cast<size_t>(it->second.GetUnsigned());
- if (rp_count == 0) {
- if (response_map.size() != 1) {
- return absl::nullopt;
- }
- return EnumerateRPsResponse(absl::nullopt, absl::nullopt, 0);
- }
- }
- it = response_map.find(
- cbor::Value(static_cast<int>(CredentialManagementResponseKey::kRP)));
- if (it == response_map.end()) {
- return absl::nullopt;
- }
- auto opt_rp = PublicKeyCredentialRpEntity::CreateFromCBORValue(it->second);
- if (!opt_rp) {
- return absl::nullopt;
- }
- it = response_map.find(cbor::Value(
- static_cast<int>(CredentialManagementResponseKey::kRPIDHash)));
- if (it == response_map.end() || !it->second.is_bytestring()) {
- return absl::nullopt;
- }
- const std::vector<uint8_t>& rp_id_hash_bytes = it->second.GetBytestring();
- if (rp_id_hash_bytes.size() != kRpIdHashLength) {
- return absl::nullopt;
- }
- std::array<uint8_t, kRpIdHashLength> rp_id_hash;
- std::copy_n(rp_id_hash_bytes.begin(), kRpIdHashLength, rp_id_hash.begin());
- return EnumerateRPsResponse(std::move(*opt_rp), std::move(rp_id_hash),
- rp_count);
- }
- // static
- bool EnumerateRPsResponse::StringFixupPredicate(
- const std::vector<const cbor::Value*>& path) {
- // In the rp field (0x04), "name" may be truncated.
- if (path.size() != 2 || !path[0]->is_unsigned() ||
- path[0]->GetUnsigned() !=
- static_cast<int>(CredentialManagementResponseKey::kRP) ||
- !path[1]->is_string()) {
- return false;
- }
- return path[1]->GetString() == "name";
- }
- EnumerateRPsResponse::EnumerateRPsResponse(EnumerateRPsResponse&&) = default;
- EnumerateRPsResponse& EnumerateRPsResponse::operator=(EnumerateRPsResponse&&) =
- default;
- EnumerateRPsResponse::~EnumerateRPsResponse() = default;
- EnumerateRPsResponse::EnumerateRPsResponse(
- absl::optional<PublicKeyCredentialRpEntity> rp_,
- absl::optional<std::array<uint8_t, kRpIdHashLength>> rp_id_hash_,
- size_t rp_count_)
- : rp(std::move(rp_)),
- rp_id_hash(std::move(rp_id_hash_)),
- rp_count(rp_count_) {}
- // static
- absl::optional<EnumerateCredentialsResponse>
- EnumerateCredentialsResponse::Parse(
- bool expect_credential_count,
- const absl::optional<cbor::Value>& cbor_response) {
- if (!cbor_response || !cbor_response->is_map()) {
- // Note that some authenticators may send an empty response if they don't
- // have a credential for a given RP ID hash (though the spec doesn't say
- // that). However, that case should not be reached from
- // CredentialManagementHandler.
- return absl::nullopt;
- }
- const cbor::Value::MapValue& response_map = cbor_response->GetMap();
- auto it = response_map.find(
- cbor::Value(static_cast<int>(CredentialManagementResponseKey::kUser)));
- if (it == response_map.end()) {
- return absl::nullopt;
- }
- auto opt_user =
- PublicKeyCredentialUserEntity::CreateFromCBORValue(it->second);
- if (!opt_user) {
- return absl::nullopt;
- }
- it = response_map.find(cbor::Value(
- static_cast<int>(CredentialManagementResponseKey::kCredentialID)));
- if (it == response_map.end()) {
- return absl::nullopt;
- }
- auto opt_credential_id =
- PublicKeyCredentialDescriptor::CreateFromCBORValue(it->second);
- if (!opt_credential_id) {
- return absl::nullopt;
- }
- // Ignore the public key's value.
- it = response_map.find(cbor::Value(
- static_cast<int>(CredentialManagementResponseKey::kPublicKey)));
- if (it == response_map.end() || !it->second.is_map()) {
- return absl::nullopt;
- }
- size_t credential_count = 0;
- if (!expect_credential_count) {
- if (response_map.find(cbor::Value(static_cast<int>(
- CredentialManagementResponseKey::kTotalCredentials))) !=
- response_map.end()) {
- return absl::nullopt;
- }
- } else {
- it = response_map.find(cbor::Value(
- static_cast<int>(CredentialManagementResponseKey::kTotalCredentials)));
- if (it == response_map.end() || !it->second.is_unsigned() ||
- it->second.GetUnsigned() == 0 ||
- it->second.GetUnsigned() > std::numeric_limits<size_t>::max()) {
- return absl::nullopt;
- }
- credential_count = static_cast<size_t>(it->second.GetUnsigned());
- }
- return EnumerateCredentialsResponse(
- std::move(*opt_user), std::move(*opt_credential_id), credential_count);
- }
- // static
- bool EnumerateCredentialsResponse::StringFixupPredicate(
- const std::vector<const cbor::Value*>& path) {
- // In the user field (0x06), "name" or "displayName" may be truncated.
- if (path.size() != 2 || !path[0]->is_unsigned() ||
- path[0]->GetUnsigned() !=
- static_cast<int>(CredentialManagementResponseKey::kUser) ||
- !path[1]->is_string()) {
- return false;
- }
- const std::string& user_key = path[1]->GetString();
- return user_key == "name" || user_key == "displayName";
- }
- EnumerateCredentialsResponse::EnumerateCredentialsResponse(
- EnumerateCredentialsResponse&&) = default;
- EnumerateCredentialsResponse& EnumerateCredentialsResponse::operator=(
- EnumerateCredentialsResponse&&) = default;
- EnumerateCredentialsResponse::~EnumerateCredentialsResponse() = default;
- EnumerateCredentialsResponse::EnumerateCredentialsResponse(
- PublicKeyCredentialUserEntity user_,
- PublicKeyCredentialDescriptor credential_id_,
- size_t credential_count_)
- : user(std::move(user_)),
- credential_id(std::move(credential_id_)),
- credential_count(credential_count_) {}
- AggregatedEnumerateCredentialsResponse::AggregatedEnumerateCredentialsResponse(
- PublicKeyCredentialRpEntity rp_)
- : rp(std::move(rp_)), credentials() {}
- AggregatedEnumerateCredentialsResponse::AggregatedEnumerateCredentialsResponse(
- AggregatedEnumerateCredentialsResponse&&) = default;
- AggregatedEnumerateCredentialsResponse&
- AggregatedEnumerateCredentialsResponse::operator=(
- AggregatedEnumerateCredentialsResponse&&) = default;
- AggregatedEnumerateCredentialsResponse::
- ~AggregatedEnumerateCredentialsResponse() = default;
- std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
- AsCTAPRequestValuePair(const CredentialManagementRequest& request) {
- cbor::Value::MapValue request_map;
- request_map.emplace(
- static_cast<int>(CredentialManagementRequestKey::kSubCommand),
- static_cast<int>(request.subcommand));
- if (request.params) {
- request_map.emplace(
- static_cast<int>(CredentialManagementRequestKey::kSubCommandParams),
- *request.params);
- }
- DCHECK_EQ(request.pin_protocol.has_value(), request.pin_auth.has_value());
- if (request.pin_auth) {
- request_map.emplace(
- static_cast<int>(CredentialManagementRequestKey::kPinProtocol),
- static_cast<uint8_t>(*request.pin_protocol));
- request_map.emplace(
- static_cast<int>(CredentialManagementRequestKey::kPinAuth),
- *request.pin_auth);
- }
- return {request.version == CredentialManagementRequest::kPreview
- ? CtapRequestCommand::kAuthenticatorCredentialManagementPreview
- : CtapRequestCommand::kAuthenticatorCredentialManagement,
- cbor::Value(std::move(request_map))};
- }
- } // namespace device
|