--- /dev/null
+// 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 "content/browser/webauthn/authenticator_common_tizen.h"
+
+#include <cstring>
+#include <iostream>
+#include <mutex>
+#include <optional>
+#include <string>
+#include <string_view>
+#include <typeinfo>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include "base/base64url.h"
+#include "base/bind.h"
+#include "base/check.h"
+#include "base/command_line.h"
+#include "base/containers/contains.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/notreached.h"
+#include "base/rand_util.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversion_utils.h"
+#include "base/timer/timer.h"
+#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
+#include "content/browser/bad_message.h"
+#include "content/browser/renderer_host/back_forward_cache_disable.h"
+#include "content/browser/webauth/authenticator_environment_impl.h"
+#include "content/browser/webauth/client_data_json.h"
+#include "content/browser/webauth/is_uvpaa.h"
+#include "content/browser/webauth/virtual_authenticator_request_delegate.h"
+#include "content/browser/webauth/virtual_fido_discovery_factory.h"
+#include "content/browser/webauth/webauth_request_security_checker.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/device_service.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_client.h"
+#include "crypto/sha2.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "net/cert/asn1_util.h"
+#include "net/der/input.h"
+#include "net/der/parse_values.h"
+#include "net/der/parser.h"
+#include "services/network/public/cpp/is_potentially_trustworthy.h"
+#include "url/url_constants.h"
+#include "url/url_util.h"
+
+#if defined(OS_MAC)
+#include "device/fido/mac/authenticator.h"
+#include "device/fido/mac/credential_metadata.h"
+#endif
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "device/fido/cros/authenticator.h"
+#endif
+
+namespace content {
+
+// RequestExtension is a type of extension in a WebAuthn request that might
+// yield an extension output in the response.
+enum class RequestExtension {
+ kAppID,
+ kHMACSecret,
+ kPRF,
+ kCredProps,
+ kLargeBlobEnable,
+ kLargeBlobRead,
+ kLargeBlobWrite,
+ kCredBlob,
+ kGetCredBlob,
+};
+
+enum class AttestationErasureOption {
+ kIncludeAttestation,
+ kEraseAttestationButIncludeAaguid,
+ kEraseAttestationAndAaguid,
+};
+
+namespace {
+
+constexpr char kGstaticAppId[] =
+ "https://www.gstatic.com/securitykey/origins.json";
+constexpr char kGstaticCorpAppId[] =
+ "https://www.gstatic.com/securitykey/a/google.com/origins.json";
+
+WebAuthenticationDelegate* GetWebAuthenticationDelegate() {
+ return GetContentClient()->browser()->GetWebAuthenticationDelegate();
+}
+
+std::string Base64UrlEncode(const base::span<const uint8_t> input) {
+ std::string ret;
+ base::Base64UrlEncode(
+ base::StringPiece(reinterpret_cast<const char*>(input.data()),
+ input.size()),
+ base::Base64UrlEncodePolicy::OMIT_PADDING, &ret);
+ return ret;
+}
+
+// Validates whether the given origin is authorized to use the provided App
+// ID value, mostly according to the rules in
+// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-appid-and-facets-v1.2-ps-20170411.html#determining-if-a-caller-s-facetid-is-authorized-for-an-appid.
+//
+// Returns the App ID to use for the request, or absl::nullopt if the origin
+// is not authorized to use the provided value.
+absl::optional<std::string> ProcessAppIdExtension(
+ std::string appid,
+ const url::Origin& caller_origin) {
+ // The CryptoToken U2F extension checks the appid before calling the WebAuthn
+ // API so there is no need to validate it here.
+ if (WebAuthRequestSecurityChecker::OriginIsCryptoTokenExtension(
+ caller_origin)) {
+ if (!GURL(appid).is_valid()) {
+ DCHECK(false) << "cryptotoken request did not set a valid App ID";
+ return absl::nullopt;
+ }
+ return appid;
+ }
+
+ // Step 1: "If the AppID is not an HTTPS URL, and matches the FacetID of the
+ // caller, no additional processing is necessary and the operation may
+ // proceed."
+
+ // Webauthn is only supported on secure origins and |ValidateEffectiveDomain|
+ // has already checked this property of |caller_origin| before this call. Thus
+ // this step is moot.
+ // TODO(https://crbug.com/1158302): Use IsOriginPotentiallyTrustworthy?
+ DCHECK(network::IsUrlPotentiallyTrustworthy(caller_origin.GetURL()));
+
+ // Step 2: "If the AppID is null or empty, the client must set the AppID to be
+ // the FacetID of the caller, and the operation may proceed without additional
+ // processing."
+ if (appid.empty()) {
+ // While the U2F spec says to default the App ID to the Facet ID, which is
+ // the origin plus a trailing forward slash [1], cryptotoken and Firefox
+ // just use the site's Origin without trailing slash. We follow their
+ // implementations rather than the spec.
+ //
+ // [1]https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-appid-and-facets-v2.0-id-20180227.html#determining-the-facetid-of-a-calling-application
+ appid = caller_origin.Serialize();
+ }
+
+ // Step 3: "If the caller's FacetID is an https:// Origin sharing the same
+ // host as the AppID, (e.g. if an application hosted at
+ // https://fido.example.com/myApp set an AppID of
+ // https://fido.example.com/myAppId), no additional processing is necessary
+ // and the operation may proceed."
+ GURL appid_url = GURL(appid);
+ if (!appid_url.is_valid() || appid_url.scheme() != url::kHttpsScheme ||
+ appid_url.scheme_piece() != caller_origin.scheme()) {
+ return absl::nullopt;
+ }
+
+ // This check is repeated inside |SameDomainOrHost|, just after this. However
+ // it's cheap and mirrors the structure of the spec.
+ if (appid_url.host_piece() == caller_origin.host()) {
+ return appid;
+ }
+
+ // At this point we diverge from the specification in order to avoid the
+ // complexity of making a network request which isn't believed to be
+ // necessary in practice. See also
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1244959#c8
+ if (net::registry_controlled_domains::SameDomainOrHost(
+ appid_url, caller_origin,
+ net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)) {
+ return appid;
+ }
+
+ // As a compatibility hack, sites within google.com are allowed to assert two
+ // special-case AppIDs. Firefox also does this:
+ // https://groups.google.com/forum/#!msg/mozilla.dev.platform/Uiu3fwnA2xw/201ynAiPAQAJ
+ const GURL gstatic_appid(kGstaticAppId);
+ const GURL gstatic_corp_appid(kGstaticCorpAppId);
+ DCHECK(gstatic_appid.is_valid() && gstatic_corp_appid.is_valid());
+ if (caller_origin.DomainIs("google.com") && !appid_url.has_ref() &&
+ (appid_url.EqualsIgnoringRef(gstatic_appid) ||
+ appid_url.EqualsIgnoringRef(gstatic_corp_appid))) {
+ return appid;
+ }
+
+ return absl::nullopt;
+}
+
+// Returns an App ID string if a U2F credential must be made for the request
+// with |options|. This is the case for requests that either originate from
+// cryptotoken or have the googleLegacyAppidSupport extension set.
+absl::optional<std::string> MakeCredentialU2fAppIdOverride(
+ const url::Origin& caller_origin,
+ const blink::mojom::PublicKeyCredentialCreationOptionsPtr& options) {
+ // Cryptotoken passes the U2F request's App ID in the RP ID field of the
+ // WebAuthn request.
+ if (WebAuthRequestSecurityChecker::OriginIsCryptoTokenExtension(
+ caller_origin)) {
+ DCHECK(!options->google_legacy_app_id_support);
+ return options->relying_party.id;
+ }
+ if (options->google_legacy_app_id_support &&
+ options->relying_party.id == "google.com") {
+ if (caller_origin.DomainIs("login.corp.google.com")) {
+ return kGstaticCorpAppId;
+ }
+ return kGstaticAppId;
+ }
+ return absl::nullopt;
+}
+
+// The application parameter is the SHA-256 hash of the UTF-8 encoding of
+// the application identity (i.e. relying_party_id) of the application
+// requesting the registration.
+std::array<uint8_t, crypto::kSHA256Length> CreateApplicationParameter(
+ const std::string& relying_party_id) {
+ std::array<uint8_t, crypto::kSHA256Length> application_parameter;
+ crypto::SHA256HashString(relying_party_id, application_parameter.data(),
+ application_parameter.size());
+ return application_parameter;
+}
+
+device::CtapGetAssertionRequest CreateCtapGetAssertionRequest(
+ const std::string& client_data_json,
+ const blink::mojom::PublicKeyCredentialRequestOptionsPtr& options,
+ absl::optional<std::string> app_id,
+ bool is_off_the_record) {
+ device::CtapGetAssertionRequest request_parameter(options->relying_party_id,
+ client_data_json);
+
+ request_parameter.allow_list = options->allow_credentials;
+
+ request_parameter.user_verification = options->user_verification;
+
+ if (app_id) {
+ request_parameter.alternative_application_parameter =
+ CreateApplicationParameter(*app_id);
+ request_parameter.app_id = std::move(*app_id);
+ }
+
+ if (!options->cable_authentication_data.empty()) {
+ request_parameter.cable_extension = options->cable_authentication_data;
+ }
+ if (options->large_blob_read) {
+ request_parameter.large_blob_read = true;
+ request_parameter.large_blob_key = true;
+ }
+ if (options->large_blob_write) {
+ request_parameter.large_blob_key = true;
+ }
+ request_parameter.is_off_the_record_context = is_off_the_record;
+ return request_parameter;
+}
+
+
+base::TimeDelta AdjustTimeout(absl::optional<base::TimeDelta> timeout,
+ RenderFrameHost* render_frame_host) {
+ // Time to wait for an authenticator to successfully complete an operation.
+ static constexpr base::TimeDelta kAdjustedTimeoutLower =
+ base::TimeDelta::FromSeconds(10);
+ static constexpr base::TimeDelta kAdjustedTimeoutUpper =
+ base::TimeDelta::FromMinutes(10);
+
+ if (!timeout) {
+ return kAdjustedTimeoutUpper;
+ }
+ const bool testing_api_enabled =
+ AuthenticatorEnvironmentImpl::GetInstance()
+ ->IsVirtualAuthenticatorEnabledFor(
+ static_cast<RenderFrameHostImpl*>(render_frame_host)
+ ->frame_tree_node());
+ if (testing_api_enabled) {
+ return *timeout;
+ }
+ return std::max(kAdjustedTimeoutLower,
+ std::min(kAdjustedTimeoutUpper, *timeout));
+}
+
+/* Webauthn functions*/
+
+template <class T>
+wauthn_const_buffer_s ToWauthnConstBuff(T& x) noexcept {
+ static_assert(sizeof(decltype(*x.data())) == 1, "for reinterpret_cast below");
+ // reinterpret_cast is for std::string input values
+ return wauthn_const_buffer_s{reinterpret_cast<const uint8_t*>(x.data()),
+ x.size()};
+}
+
+typedef std::vector<uint8_t> Buffer;
+
+Buffer ToBuffer(wauthn_const_buffer_s buff) {
+ return Buffer{buff.data, buff.data + buff.size};
+}
+
+struct LinkedData {
+ Buffer contactId;
+ Buffer linkId;
+ Buffer linkSecret;
+ Buffer authenticatorPubKey;
+ Buffer authenticatorName;
+ Buffer signature;
+ Buffer tunnelServerDomain;
+ Buffer identityKey;
+};
+
+template <class Bytes>
+std::string LowercaseHexStringOf(const Bytes& bytes) {
+ static_assert(sizeof(typename Bytes::value_type) == 1);
+ std::string res;
+ for (uint8_t byte : bytes) {
+ constexpr char digits[] = "0123456789abcdef";
+ res += digits[byte >> 4];
+ res += digits[byte & 15];
+ }
+ return res;
+}
+blink::mojom::AuthenticatorStatus WauthnErrorToAuthStatus(
+ wauthn_error_e result) {
+ switch (result) {
+ case WAUTHN_ERROR_NONE:
+ return blink::mojom::AuthenticatorStatus::SUCCESS;
+ case WAUTHN_ERROR_NONE_AND_WAIT:
+ return blink::mojom::AuthenticatorStatus::PENDING_REQUEST;
+ case WAUTHN_ERROR_PERMISSION_DENIED:
+ case WAUTHN_ERROR_ACCESS_DENIED:
+ case WAUTHN_ERROR_NOT_ALLOWED:
+ case WAUTHN_ERROR_CONNECTION_REFUSED:
+ return blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR;
+ case WAUTHN_ERROR_TIMED_OUT:
+ case WAUTHN_ERROR_SOCKET:
+ case WAUTHN_ERROR_CANCELED:
+ return blink::mojom::AuthenticatorStatus::ABORT_ERROR;
+ case WAUTHN_ERROR_INVALID_STATE:
+ case WAUTHN_ERROR_ENCODING_FAILED:
+ case WAUTHN_ERROR_INVALID_PARAMETER:
+ return blink::mojom::AuthenticatorStatus::INVALID_DOMAIN;
+ case WAUTHN_ERROR_NO_SUCH_SERVICE:
+ case WAUTHN_ERROR_NOT_SUPPORTED:
+ return blink::mojom::AuthenticatorStatus::ANDROID_NOT_SUPPORTED_ERROR;
+ default:
+ return blink::mojom::AuthenticatorStatus::UNKNOWN_ERROR;
+ }
+}
+
+} // namespace
+
+void AuthenticatorCommonTizen::DisplayQRCallback(const char* qr_contents,
+ void* data) {
+ AuthenticatorCommonTizen* thiz =
+ reinterpret_cast<AuthenticatorCommonTizen*>(data);
+ std::string encoded(qr_contents);
+
+ RenderFrameHostImpl* const render_frame_host_impl =
+ static_cast<RenderFrameHostImpl*>(thiz->GetRenderFrameHost());
+
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
+ base::BindOnce(&RenderFrameHostImpl::DisplayQRCode,
+ base::Unretained(render_frame_host_impl), encoded));
+}
+
+void AuthenticatorCommonTizen::MCCallback(
+ const wauthn_pubkey_credential_attestation_s* pubkey_cred,
+ wauthn_error_e result,
+ void* data) {
+ if (result == WAUTHN_ERROR_CANCELED) {
+ return;
+ }
+ AuthenticatorCommonTizen* thiz =
+ reinterpret_cast<AuthenticatorCommonTizen*>(data);
+
+ RenderFrameHostImpl* const render_frame_host_impl =
+ static_cast<RenderFrameHostImpl*>(thiz->GetRenderFrameHost());
+
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE, base::BindOnce(&RenderFrameHostImpl::CloseQRCode,
+ base::Unretained(render_frame_host_impl)));
+
+ if (!thiz->make_credential_response_callback_) {
+ return;
+ }
+
+ if (!pubkey_cred || result != WAUTHN_ERROR_NONE) {
+ thiz->CompleteMakeCredentialRequest(WauthnErrorToAuthStatus(result));
+ return;
+ }
+
+ thiz->CompleteMakeCredentialRequest(
+ blink::mojom::AuthenticatorStatus::SUCCESS,
+ thiz->CreateMakeCredentialResponse(std::move(pubkey_cred),
+ AttestationErasureOption::kEraseAttestationAndAaguid),
+ Focus::kDoCheck);
+}
+
+void AuthenticatorCommonTizen::GACallback(
+ const wauthn_pubkey_credential_assertion_s* pubkey_cred,
+ wauthn_error_e result,
+ void* data) {
+ if (result == WAUTHN_ERROR_CANCELED) {
+ return;
+ }
+ AuthenticatorCommonTizen* thiz =
+ reinterpret_cast<AuthenticatorCommonTizen*>(data);
+
+ RenderFrameHostImpl* const render_frame_host_impl =
+ static_cast<RenderFrameHostImpl*>(thiz->GetRenderFrameHost());
+
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE, base::BindOnce(&RenderFrameHostImpl::CloseQRCode,
+ base::Unretained(render_frame_host_impl)));
+
+ if (!thiz->get_assertion_response_callback_) {
+ return;
+ }
+
+ if (!pubkey_cred || result != WAUTHN_ERROR_NONE) {
+ thiz->CompleteGetAssertionRequest(WauthnErrorToAuthStatus(result));
+ return;
+ }
+
+ thiz->CompleteGetAssertionRequest(
+ blink::mojom::AuthenticatorStatus::SUCCESS,
+ thiz->CreateGetAssertionResponse(std::move(pubkey_cred)));
+}
+void AuthenticatorCommonTizen::MCUpdateLinkedDataCallback(
+ const wauthn_hybrid_linked_data_s* linked_data,
+ wauthn_error_e result,
+ void* data) {
+ NOTIMPLEMENTED();
+}
+
+void AuthenticatorCommonTizen::GAUpdateLinkedDataCallback(
+ const wauthn_hybrid_linked_data_s* linked_data,
+ wauthn_error_e result,
+ void* data) {
+ NOTIMPLEMENTED();
+}
+AuthenticatorCommonTizen::AuthenticatorCommonTizen(
+ RenderFrameHost* render_frame_host)
+ : render_frame_host_id_(render_frame_host->GetGlobalId()),
+ security_checker_(static_cast<RenderFrameHostImpl*>(render_frame_host)
+ ->GetWebAuthRequestSecurityChecker()) {
+ // Disable the back-forward cache for any document that makes WebAuthn
+ // requests. Pages using privacy-sensitive APIs are generally exempt from
+ // back-forward cache for now as a precaution.
+ BackForwardCache::DisableForRenderFrameHost(
+ render_frame_host,
+ BackForwardCacheDisable::DisabledReason(
+ BackForwardCacheDisable::DisabledReasonId::kWebAuthenticationAPI));
+}
+
+AuthenticatorCommonTizen::~AuthenticatorCommonTizen() {
+ // Resolve pending callbacks before disconnecting the receiver.
+ if (make_credential_response_callback_) {
+ CompleteMakeCredentialRequest(
+ blink::mojom::AuthenticatorStatus::UNKNOWN_ERROR);
+ }
+ if (get_assertion_response_callback_) {
+ CompleteGetAssertionRequest(
+ blink::mojom::AuthenticatorStatus::UNKNOWN_ERROR);
+ }
+}
+
+std::unique_ptr<AuthenticatorRequestClientDelegate>
+AuthenticatorCommonTizen::MaybeCreateRequestDelegate() {
+ RenderFrameHostImpl* const render_frame_host_impl =
+ static_cast<RenderFrameHostImpl*>(GetRenderFrameHost());
+ if (AuthenticatorEnvironmentImpl::GetInstance()
+ ->IsVirtualAuthenticatorEnabledFor(
+ render_frame_host_impl->frame_tree_node())) {
+ return std::make_unique<VirtualAuthenticatorRequestDelegate>();
+ }
+ return GetContentClient()->browser()->GetWebAuthenticationRequestDelegate(
+ render_frame_host_impl);
+}
+
+bool AuthenticatorCommonTizen::IsFocused() const {
+ return GetRenderFrameHost()->IsActive() &&
+ GetWebAuthenticationDelegate()->IsFocused(
+ WebContents::FromRenderFrameHost(GetRenderFrameHost()));
+}
+void AuthenticatorCommonTizen::PopulateMCWebauthnArgs(
+ blink::mojom::PublicKeyCredentialCreationOptionsPtr options) {
+ std::memset(&mc_options_, 0, sizeof(mc_options_));
+
+ // Chrome clientData -> Webauthn clientData
+ client_data_json_buff_ = ToWauthnConstBuff(client_data_json_);
+ mc_client_data_.client_data_json = &client_data_json_buff_;
+ mc_client_data_.hash_alg = WAUTHN_HASH_ALGORITHM_SHA_256;
+
+ // Chrome RP -> Webauthn RP
+ rel_party_id_ = options->relying_party.id;
+ rp_.id = rel_party_id_.c_str();
+
+ // options->relying_party.name is of type std::optional(std::string)
+ if (options->relying_party.name) {
+ rel_party_name_ = options->relying_party.name.value();
+ rp_.name = rel_party_name_.c_str();
+ }
+
+ // Chrome User -> Webauthn User
+ user_id_vector_ = options->user.id;
+ user_id_buff_ = ToWauthnConstBuff(user_id_vector_);
+ user_.id = &user_id_buff_;
+
+ user_name_string_ = *options->user.name;
+ user_.name = user_name_string_.c_str();
+
+ user_display_name_string_ = *options->user.display_name;
+ user_.display_name = user_display_name_string_.c_str();
+
+ // Chrome Pubkey Params -> Webauthn Pubkey Params
+ std::unordered_map<int, wauthn_cose_algorithm_e>
+ mapping_identifier_to_algorithm;
+ mapping_identifier_to_algorithm[-7] =
+ WAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256;
+ mapping_identifier_to_algorithm[-35] =
+ WAUTHN_COSE_ALGORITHM_ECDSA_P384_WITH_SHA384;
+ mapping_identifier_to_algorithm[-36] =
+ WAUTHN_COSE_ALGORITHM_ECDSA_P521_WITH_SHA512;
+ mapping_identifier_to_algorithm[-8] = WAUTHN_COSE_ALGORITHM_EDDSA;
+ mapping_identifier_to_algorithm[-37] =
+ WAUTHN_COSE_ALGORITHM_RSA_PSS_WITH_SHA256;
+ mapping_identifier_to_algorithm[-38] =
+ WAUTHN_COSE_ALGORITHM_RSA_PSS_WITH_SHA384;
+ mapping_identifier_to_algorithm[-39] =
+ WAUTHN_COSE_ALGORITHM_RSA_PSS_WITH_SHA512;
+ mapping_identifier_to_algorithm[-257] =
+ WAUTHN_COSE_ALGORITHM_RSASSA_PKCS1_V1_5_WITH_SHA256;
+ mapping_identifier_to_algorithm[-258] =
+ WAUTHN_COSE_ALGORITHM_RSASSA_PKCS1_V1_5_WITH_SHA384;
+ mapping_identifier_to_algorithm[-259] =
+ WAUTHN_COSE_ALGORITHM_RSASSA_PKCS1_V1_5_WITH_SHA512;
+
+ int num_pubkey_params = options->public_key_parameters.size();
+ params_vector_ = std::vector<wauthn_pubkey_cred_param_s>(num_pubkey_params);
+ for (int iter = 0; iter < num_pubkey_params; iter++) {
+ params_vector_[iter].type = WAUTHN_PUBKEY_CRED_TYPE_PUBLIC_KEY;
+ params_vector_[iter].alg =
+ mapping_identifier_to_algorithm[options->public_key_parameters[iter]
+ .algorithm];
+ }
+ pubkey_cred_params_.params = ¶ms_vector_[0];
+ pubkey_cred_params_.size = num_pubkey_params;
+
+ // Chrome Timeout -> Webauthn Timeout
+ if (options->timeout) {
+ mc_options_.timeout = options->timeout->InMilliseconds();
+ }
+
+ // Chrome Excluded Credentials -> Webauthn Excluded Credentials
+ if (!options->exclude_credentials.empty()) {
+ std::unordered_map<device::FidoTransportProtocol, unsigned int>
+ mapping_transport_to_unsigned_int;
+ mapping_transport_to_unsigned_int
+ [device::FidoTransportProtocol::kUsbHumanInterfaceDevice] = 0x00000001;
+ mapping_transport_to_unsigned_int
+ [device::FidoTransportProtocol::kNearFieldCommunication] = 0x00000002;
+ mapping_transport_to_unsigned_int
+ [device::FidoTransportProtocol::kBluetoothLowEnergy] = 0x00000004;
+ // mapping_transport_to_unsigned_int[device::FidoTransportProtocol::kHybrid] =
+ // 0x00000010; check this
+ mapping_transport_to_unsigned_int
+ [device::FidoTransportProtocol::kInternal] = 0x00000020;
+
+ int num_excluded_credentials = options->exclude_credentials.size();
+ excluded_creds_vector_ =
+ std::vector<wauthn_pubkey_cred_descriptor_s>(num_excluded_credentials);
+ excluded_creds_id_buffer_vector_ =
+ std::vector<wauthn_const_buffer_s>(num_excluded_credentials);
+ excluded_creds_id_int8_vector_ =
+ std::vector<std::vector<uint8_t>>(num_excluded_credentials);
+
+ for (int iter = 0; iter < num_excluded_credentials; iter++) {
+ excluded_creds_id_int8_vector_[iter] =
+ options->exclude_credentials[iter].id();
+ excluded_creds_id_buffer_vector_[iter] =
+ ToWauthnConstBuff(excluded_creds_id_int8_vector_[iter]);
+ excluded_creds_vector_[iter].id = &excluded_creds_id_buffer_vector_[iter];
+ excluded_creds_vector_[iter].type = WAUTHN_PUBKEY_CRED_TYPE_PUBLIC_KEY;
+
+ if (!options->exclude_credentials[iter].transports().empty()) {
+ excluded_creds_vector_[iter].transports = 0x00000000;
+ for (auto iter_exclude_credential =
+ options->exclude_credentials[iter].transports().begin();
+ iter_exclude_credential !=
+ options->exclude_credentials[iter].transports().end();
+ iter_exclude_credential++) {
+ excluded_creds_vector_[iter].transports |=
+ mapping_transport_to_unsigned_int[*iter_exclude_credential];
+ }
+ }
+ }
+ excluded_credentials_.descriptors = &excluded_creds_vector_[0];
+ excluded_credentials_.size = num_excluded_credentials;
+ mc_options_.exclude_credentials = &excluded_credentials_;
+ }
+
+ // Chrome Authenticator Selection -> Webauthn Authenticator Selection
+ if (options->authenticator_selection) {
+ if (options->authenticator_selection->authenticator_attachment() !=
+ device::AuthenticatorAttachment::kAny) {
+ mc_authenticator_selection_criteria_.attachment =
+ options->authenticator_selection->authenticator_attachment() ==
+ device::AuthenticatorAttachment::kPlatform
+ ? WAUTHN_AUTHENTICATOR_ATTACHMENT_PLATFORM
+ : WAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM;
+ }
+
+ switch (options->authenticator_selection->resident_key()) {
+ case device::ResidentKeyRequirement::kDiscouraged:
+ mc_authenticator_selection_criteria_.resident_key =
+ WAUTHN_RESIDENT_KEY_REQUIREMENT_DISCOURAGED;
+ break;
+ case device::ResidentKeyRequirement::kPreferred:
+ mc_authenticator_selection_criteria_.resident_key =
+ WAUTHN_RESIDENT_KEY_REQUIREMENT_PREFERRED;
+ break;
+ case device::ResidentKeyRequirement::kRequired:
+ mc_authenticator_selection_criteria_.resident_key =
+ WAUTHN_RESIDENT_KEY_REQUIREMENT_REQUIRED;
+ }
+ mc_authenticator_selection_criteria_.require_resident_key =
+ mc_authenticator_selection_criteria_.resident_key ==
+ WAUTHN_RESIDENT_KEY_REQUIREMENT_REQUIRED;
+
+ switch (options->authenticator_selection->user_verification_requirement()) {
+ case device::UserVerificationRequirement::kRequired:
+ mc_authenticator_selection_criteria_.user_verification =
+ WAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED;
+ break;
+ case device::UserVerificationRequirement::kPreferred:
+ mc_authenticator_selection_criteria_.user_verification =
+ WAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED;
+ break;
+ case device::UserVerificationRequirement::kDiscouraged:
+ mc_authenticator_selection_criteria_.user_verification =
+ WAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED;
+ }
+ mc_options_.authenticator_selection = &mc_authenticator_selection_criteria_;
+ }
+
+
+ // Chrome Attestation Preference -> Webauthn Attestation Preference
+ switch (options->attestation) {
+ case ::device::AttestationConveyancePreference::kIndirect:
+ mc_options_.attestation = WAUTHN_ATTESTATION_PREF_INDIRECT;
+ break;
+ case ::device::AttestationConveyancePreference::kDirect:
+ mc_options_.attestation = WAUTHN_ATTESTATION_PREF_DIRECT;
+ break;
+ case ::device::AttestationConveyancePreference::
+ kEnterpriseIfRPListedOnAuthenticator:
+ case ::device::AttestationConveyancePreference::
+ kEnterpriseApprovedByBrowser:
+ mc_options_.attestation = WAUTHN_ATTESTATION_PREF_ENTERPRISE;
+ break;
+ default:
+ mc_options_.attestation = WAUTHN_ATTESTATION_PREF_NONE;
+ }
+
+ mc_options_.rp = &rp_;
+ mc_options_.user = &user_;
+ mc_options_.pubkey_cred_params = &pubkey_cred_params_;
+
+ // Chrome extensions -> Webauthn Extensions
+ mc_extension_id_buffer_vector_.clear();
+ mc_extension_value_buffer_vector_.clear();
+ mc_extensions_vector_.clear();
+ extension_value_ = std::vector<std::string>(17, "");
+
+ if (options->hmac_create_secret) {
+ extension_value_[12] = "true";
+ }
+
+ switch (options->protection_policy) {
+ case blink::mojom::ProtectionPolicy::NONE:
+ extension_value_[8] = "NONE";
+ break;
+ case blink::mojom::ProtectionPolicy::UV_OR_CRED_ID_REQUIRED:
+ extension_value_[8] = "UV_OR_CRED_ID_REQUIRED";
+ break;
+ case blink::mojom::ProtectionPolicy::UV_REQUIRED:
+ extension_value_[8] = "UV_REQUIRED";
+ break;
+ }
+
+ if (options->appid_exclude) {
+ extension_value_[13] = options->appid_exclude.value();
+ }
+
+ if (options->cred_props) {
+ extension_value_[14] = "true";
+ }
+
+ switch (options->large_blob_enable) {
+ case ::device::LargeBlobSupport::kRequired:
+ extension_value_[15] = "REQUIRED";
+ break;
+ case ::device::LargeBlobSupport::kPreferred:
+ extension_value_[15] = "PREFERRED";
+ break;
+ }
+
+ if (options->is_payment_credential_creation) {
+ extension_value_[16] = "true";
+ }
+
+ if (options->cred_blob) {
+ extension_value_[9].assign(options->cred_blob.value().begin(),
+ options->cred_blob.value().end());
+ }
+
+ for (int iter = 0; iter < 17; iter++) {
+ if (extension_value_[iter].size()) {
+ mc_extension_id_buffer_vector_.push_back(
+ ToWauthnConstBuff(extension_id_[iter]));
+ mc_extension_value_buffer_vector_.push_back(
+ ToWauthnConstBuff(extension_value_[iter]));
+ }
+ }
+ int num_extensions = mc_extension_id_buffer_vector_.size();
+ mc_extensions_vector_ =
+ std::vector<wauthn_authentication_ext_s>(num_extensions);
+ for (int iter = 0; iter < num_extensions; iter++) {
+ mc_extensions_vector_[iter].extension_id =
+ &mc_extension_id_buffer_vector_[iter];
+ mc_extensions_vector_[iter].extension_value =
+ &mc_extension_value_buffer_vector_[iter];
+ }
+ mc_extensions_.extensions = &mc_extensions_vector_[0];
+ mc_extensions_.size = num_extensions;
+ mc_options_.extensions = &mc_extensions_;
+ mc_callbacks_.qrcode_callback = DisplayQRCallback;
+ mc_callbacks_.response_callback = MCCallback;
+ mc_callbacks_.linked_data_callback = MCUpdateLinkedDataCallback;
+ mc_callbacks_.user_data = this;
+}
+
+void AuthenticatorCommonTizen::PopulateGAWebauthnArgs(
+ blink::mojom::PublicKeyCredentialRequestOptionsPtr options) {
+ std::memset(&ga_options_, 0, sizeof(ga_options_));
+
+ client_data_json_buff_ = ToWauthnConstBuff(client_data_json_);
+
+ ga_client_data_.client_data_json = &client_data_json_buff_;
+ ga_client_data_.hash_alg = WAUTHN_HASH_ALGORITHM_SHA_256;
+
+ // Chrome Timeout -> Webauthn Timeout
+ if (options->timeout) {
+ ga_options_.timeout = options->timeout->InMilliseconds();
+ }
+
+ // Chrome RP -> Webauthn RP
+ rp_id_string_ = options->relying_party_id;
+
+ // Chrome Allow Credentials -> Webauthn Allow Credentials
+ if (!options->allow_credentials.empty()) {
+ std::unordered_map<device::FidoTransportProtocol, unsigned int>
+ mapping_transport_to_unsigned_int;
+ mapping_transport_to_unsigned_int
+ [device::FidoTransportProtocol::kUsbHumanInterfaceDevice] = 0x00000001;
+ mapping_transport_to_unsigned_int
+ [device::FidoTransportProtocol::kNearFieldCommunication] = 0x00000002;
+ mapping_transport_to_unsigned_int
+ [device::FidoTransportProtocol::kBluetoothLowEnergy] = 0x00000004;
+ // mapping_transport_to_unsigned_int[device::FidoTransportProtocol::kHybrid] =
+ // 0x00000010;
+ mapping_transport_to_unsigned_int
+ [device::FidoTransportProtocol::kInternal] = 0x00000020;
+
+ int num_allow_credentials = options->allow_credentials.size();
+ pubkey_cred_descriptor_vector_ =
+ std::vector<wauthn_pubkey_cred_descriptor_s>(num_allow_credentials);
+ pubkey_cred_id_int8_vector_ =
+ std::vector<std::vector<uint8_t>>(num_allow_credentials);
+ pubkey_cred_id_buffer_vector_ =
+ std::vector<wauthn_const_buffer_s>(num_allow_credentials);
+
+ for (int iter = 0; iter < num_allow_credentials; iter++) {
+ pubkey_cred_id_int8_vector_[iter] = options->allow_credentials[iter].id();
+ pubkey_cred_id_buffer_vector_[iter] =
+ ToWauthnConstBuff(pubkey_cred_id_int8_vector_[iter]);
+ pubkey_cred_descriptor_vector_[iter].id =
+ &pubkey_cred_id_buffer_vector_[iter];
+ pubkey_cred_descriptor_vector_[iter].type =
+ WAUTHN_PUBKEY_CRED_TYPE_PUBLIC_KEY;
+
+ pubkey_cred_descriptor_vector_[iter].transports = 0x00000000;
+ for (const auto& transport :
+ options->allow_credentials[iter].transports()) {
+ pubkey_cred_descriptor_vector_[iter].transports |=
+ mapping_transport_to_unsigned_int[transport];
+ }
+ }
+ pubkey_cred_descriptors_.descriptors = &pubkey_cred_descriptor_vector_[0];
+ pubkey_cred_descriptors_.size = num_allow_credentials;
+
+ ga_options_.allow_credentials = &pubkey_cred_descriptors_;
+ }
+
+ // Chrome User Verification -> Webauthn User Verification
+ switch (options->user_verification) {
+ case device::UserVerificationRequirement::kRequired:
+ ga_options_.user_verification =
+ WAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED;
+ break;
+ case device::UserVerificationRequirement::kPreferred:
+ ga_options_.user_verification =
+ WAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED;
+ break;
+ case device::UserVerificationRequirement::kDiscouraged:
+ ga_options_.user_verification =
+ WAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED;
+ default:
+ ga_options_.user_verification = WAUTHN_USER_VERIFICATION_REQUIREMENT_NONE;
+ }
+
+ ga_options_.rpId = rp_id_string_.c_str();
+ ga_options_.attestation = device_attestation_;
+
+ // Chrome extensions -> Webauthn Extensions
+ ga_extension_id_buffer_vector_.clear();
+ ga_extension_value_buffer_vector_.clear();
+ ga_extensions_vector_.clear();
+ extension_value_ = std::vector<std::string>(17, "");
+
+ if (options->appid) {
+ extension_value_[0] = options->appid.value();
+ }
+
+ for (int iter = 0; iter < 17; iter++) {
+ if (extension_value_[iter].size()) {
+ ga_extension_id_buffer_vector_.push_back(
+ ToWauthnConstBuff(extension_id_[iter]));
+ ga_extension_value_buffer_vector_.push_back(
+ ToWauthnConstBuff(extension_value_[iter]));
+ }
+ }
+ int num_extensions = ga_extension_id_buffer_vector_.size();
+ ga_extensions_vector_ =
+ std::vector<wauthn_authentication_ext_s>(num_extensions);
+ for (int iter = 0; iter < num_extensions; iter++) {
+ ga_extensions_vector_[iter].extension_id =
+ &ga_extension_id_buffer_vector_[iter];
+ ga_extensions_vector_[iter].extension_value =
+ &ga_extension_value_buffer_vector_[iter];
+ }
+ ga_extensions_.extensions = &ga_extensions_vector_[0];
+ ga_extensions_.size = num_extensions;
+ ga_options_.extensions = &ga_extensions_;
+ ga_callbacks_.qrcode_callback = DisplayQRCallback;
+ ga_callbacks_.response_callback = GACallback;
+ ga_callbacks_.linked_data_callback = GAUpdateLinkedDataCallback;
+ ga_callbacks_.user_data = this;
+}
+
+void AuthenticatorCommonTizen::OnLargeBlobCompressed(
+ data_decoder::DataDecoder::ResultOrError<mojo_base::BigBuffer> result) {
+ // ctap_get_assertion_request_->large_blob_write =
+ // device::fido_parsing_utils::MaterializeOrNull(result.value);
+ // StartGetAssertionRequest(/*allow_skipping_pin_touch=*/true);
+}
+
+void AuthenticatorCommonTizen::OnLargeBlobUncompressed(
+ device::AuthenticatorGetAssertionResponse response,
+ data_decoder::DataDecoder::ResultOrError<mojo_base::BigBuffer> result) {
+ response.large_blob =
+ device::fido_parsing_utils::MaterializeOrNull(result.value);
+ CompleteGetAssertionRequest(
+ blink::mojom::AuthenticatorStatus::SUCCESS, nullptr);
+}
+
+// mojom::Authenticator
+void AuthenticatorCommonTizen::MakeCredential(
+ url::Origin caller_origin,
+ blink::mojom::PublicKeyCredentialCreationOptionsPtr options,
+ blink::mojom::Authenticator::MakeCredentialCallback callback) {
+ if (request_) {
+ if (WebAuthRequestSecurityChecker::OriginIsCryptoTokenExtension(
+ caller_origin)) {
+ // Requests originating from cryptotoken will generally outlive any
+ // navigation events on the tab of the request's sender. Evict pending
+ // requests if cryptotoken sends a new one such that requests from before
+ // a navigation event do not prevent new requests. See
+ // https://crbug.com/935480.
+ CancelWithStatus(blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR);
+ } else {
+ std::move(callback).Run(
+ blink::mojom::AuthenticatorStatus::PENDING_REQUEST, nullptr);
+ return;
+ }
+ }
+ DCHECK(!request_);
+ DCHECK(make_credential_response_callback_.is_null());
+ make_credential_response_callback_ = std::move(callback);
+
+ bool is_cross_origin;
+ blink::mojom::AuthenticatorStatus status =
+ security_checker_->ValidateAncestorOrigins(
+ caller_origin,
+ options->is_payment_credential_creation
+ ? WebAuthRequestSecurityChecker::RequestType::
+ kMakePaymentCredential
+ : WebAuthRequestSecurityChecker::RequestType::kMakeCredential,
+ &is_cross_origin);
+ if (status != blink::mojom::AuthenticatorStatus::SUCCESS) {
+ CompleteMakeCredentialRequest(status);
+ return;
+ }
+
+ request_delegate_ = MaybeCreateRequestDelegate();
+ if (!request_delegate_) {
+ CompleteMakeCredentialRequest(
+ blink::mojom::AuthenticatorStatus::PENDING_REQUEST);
+ return;
+ }
+
+ absl::optional<std::string> rp_id =
+ GetWebAuthenticationDelegate()->MaybeGetRelyingPartyIdOverride(
+ options->relying_party.id, caller_origin);
+
+ if (!rp_id) {
+ // If the delegate didn't override RP ID selection then apply standard
+ // rules.
+ rp_id = std::move(options->relying_party.id);
+ status = security_checker_->ValidateDomainAndRelyingPartyID(caller_origin,
+ *rp_id);
+ if (status != blink::mojom::AuthenticatorStatus::SUCCESS) {
+ CompleteMakeCredentialRequest(status);
+ return;
+ }
+ }
+
+ caller_origin_ = caller_origin;
+ relying_party_id_ = *rp_id;
+ options->relying_party.id = std::move(*rp_id);
+ request_delegate_->SetRelyingPartyId(relying_party_id_);
+
+ absl::optional<std::string> appid_exclude;
+ if (options->appid_exclude) {
+ appid_exclude =
+ ProcessAppIdExtension(*options->appid_exclude, caller_origin);
+ if (!appid_exclude) {
+ CompleteMakeCredentialRequest(
+ blink::mojom::AuthenticatorStatus::INVALID_DOMAIN);
+ return;
+ }
+ }
+
+ if (options->user.icon_url) {
+ status = security_checker_->ValidateAPrioriAuthenticatedUrl(
+ *options->user.icon_url);
+ }
+ if (status == blink::mojom::AuthenticatorStatus::SUCCESS &&
+ options->relying_party.icon_url) {
+ status = security_checker_->ValidateAPrioriAuthenticatedUrl(
+ *options->relying_party.icon_url);
+ }
+ if (status != blink::mojom::AuthenticatorStatus::SUCCESS) {
+ bad_message::ReceivedBadMessage(GetRenderFrameHost()->GetProcess(),
+ bad_message::AUTH_INVALID_ICON_URL);
+ CompleteMakeCredentialRequest(status);
+ return;
+ }
+
+ if (!IsFocused()) {
+ CompleteMakeCredentialRequest(
+ blink::mojom::AuthenticatorStatus::NOT_FOCUSED);
+ return;
+ }
+
+ const device::AuthenticatorSelectionCriteria
+ authenticator_selection_criteria =
+ options->authenticator_selection
+ ? *options->authenticator_selection
+ : device::AuthenticatorSelectionCriteria();
+
+ // Reject any non-sensical credProtect extension values.
+ if ( // Can't require the default policy (or no policy).
+ (options->enforce_protection_policy &&
+ (options->protection_policy ==
+ blink::mojom::ProtectionPolicy::UNSPECIFIED ||
+ options->protection_policy == blink::mojom::ProtectionPolicy::NONE)) ||
+ // For non-resident keys, NONE doesn't make sense. (UV_OR_CRED_ID_REQUIRED
+ // does because, with CTAP 2.0, just because a resident key isn't
+ // _required_ doesn't mean that one won't be created and an RP might want
+ // credProtect to take effect if that happens.)
+ (options->protection_policy == blink::mojom::ProtectionPolicy::NONE) ||
+ // UV_REQUIRED only makes sense if UV is required overall.
+ (options->protection_policy ==
+ blink::mojom::ProtectionPolicy::UV_REQUIRED &&
+ authenticator_selection_criteria.user_verification_requirement() !=
+ device::UserVerificationRequirement::kRequired)) {
+ CompleteMakeCredentialRequest(
+ blink::mojom::AuthenticatorStatus::PROTECTION_POLICY_INCONSISTENT);
+ return;
+ }
+
+ absl::optional<device::CredProtectRequest> cred_protect_request;
+ switch (options->protection_policy) {
+ case blink::mojom::ProtectionPolicy::UNSPECIFIED:
+ break;
+ case blink::mojom::ProtectionPolicy::NONE:
+ cred_protect_request = device::CredProtectRequest::kUVOptional;
+ break;
+ case blink::mojom::ProtectionPolicy::UV_OR_CRED_ID_REQUIRED:
+ cred_protect_request = device::CredProtectRequest::kUVOrCredIDRequired;
+ break;
+ case blink::mojom::ProtectionPolicy::UV_REQUIRED:
+ cred_protect_request = device::CredProtectRequest::kUVRequired;
+ break;
+ }
+
+ timer_->Start(
+ FROM_HERE, AdjustTimeout(options->timeout, GetRenderFrameHost()),
+ base::BindOnce(&AuthenticatorCommonTizen::OnTimeout, base::Unretained(this)));
+
+ // Cryptotoken requests, making payment credentials, and Touch-to-Autofill
+ // should be proxied without UI.
+ const bool origin_is_crypto_token_extension =
+ WebAuthRequestSecurityChecker::OriginIsCryptoTokenExtension(
+ caller_origin);
+ if (origin_is_crypto_token_extension ||
+ (!base::FeatureList::IsEnabled(
+ features::kSecurePaymentConfirmationAPIV3) &&
+ options->is_payment_credential_creation) ||
+ disable_ui_) {
+ request_delegate_->DisableUI();
+ }
+
+ if (origin_is_crypto_token_extension) {
+ // Cryptotoken passes the real caller origin in |relying_party.name|.
+ const url::Origin client_data_origin =
+ url::Origin::Create(GURL(*options->relying_party.name));
+ client_data_json_ = BuildClientDataJson(
+ ClientDataRequestType::kU2fRegister, client_data_origin.Serialize(),
+ options->challenge, is_cross_origin);
+ } else {
+ // Regular WebAuthn request
+ client_data_json_ = BuildClientDataJson(
+ ClientDataRequestType::kWebAuthnCreate, caller_origin_.Serialize(),
+ options->challenge, is_cross_origin);
+ }
+
+ PopulateMCWebauthnArgs(std::move(options));
+ int ret =
+ wauthn_make_credential(&mc_client_data_, &mc_options_, &mc_callbacks_);
+ if (ret != WAUTHN_ERROR_NONE)
+ Cancel();
+}
+
+// mojom:Authenticator
+void AuthenticatorCommonTizen::GetAssertion(
+ url::Origin caller_origin,
+ blink::mojom::PublicKeyCredentialRequestOptionsPtr options,
+ blink::mojom::PaymentOptionsPtr payment,
+ blink::mojom::Authenticator::GetAssertionCallback callback) {
+ if (request_) {
+ if (WebAuthRequestSecurityChecker::OriginIsCryptoTokenExtension(
+ caller_origin)) {
+ // Requests originating from cryptotoken will generally outlive any
+ // navigation events on the tab of the request's sender. Evict pending
+ // requests if cryptotoken sends a new one such that requests from before
+ // a navigation event do not prevent new requests. See
+ // https://crbug.com/935480.
+ CancelWithStatus(blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR);
+ } else {
+ std::move(callback).Run(
+ blink::mojom::AuthenticatorStatus::PENDING_REQUEST, nullptr);
+ return;
+ }
+ }
+ DCHECK(!request_);
+ DCHECK(get_assertion_response_callback_.is_null());
+ get_assertion_response_callback_ = std::move(callback);
+
+ bool is_cross_origin;
+ blink::mojom::AuthenticatorStatus status =
+ security_checker_->ValidateAncestorOrigins(
+ caller_origin,
+ WebAuthRequestSecurityChecker::RequestType::kGetAssertion,
+ &is_cross_origin);
+ if (status != blink::mojom::AuthenticatorStatus::SUCCESS) {
+ CompleteGetAssertionRequest(status);
+ return;
+ }
+
+ request_delegate_ = MaybeCreateRequestDelegate();
+ if (!request_delegate_) {
+ CompleteGetAssertionRequest(
+ blink::mojom::AuthenticatorStatus::PENDING_REQUEST);
+ return;
+ }
+
+ absl::optional<std::string> rp_id =
+ GetWebAuthenticationDelegate()->MaybeGetRelyingPartyIdOverride(
+ options->relying_party_id, caller_origin);
+
+ if (!rp_id) {
+ // If the delegate didn't override RP ID selection then apply standard
+ // rules.
+ status = security_checker_->ValidateDomainAndRelyingPartyID(
+ caller_origin, options->relying_party_id);
+ if (status != blink::mojom::AuthenticatorStatus::SUCCESS) {
+ CompleteGetAssertionRequest(status);
+ return;
+ }
+
+ rp_id = std::move(options->relying_party_id);
+ }
+
+ caller_origin_ = caller_origin;
+ relying_party_id_ = *rp_id;
+ options->relying_party_id = std::move(*rp_id);
+ request_delegate_->SetRelyingPartyId(relying_party_id_);
+
+ const bool origin_is_crypto_token_extension =
+ WebAuthRequestSecurityChecker::OriginIsCryptoTokenExtension(
+ caller_origin_);
+
+ if (origin_is_crypto_token_extension) {
+ // Cryptotoken provides the sender origin for U2F sign requests in the
+ // |relying_party_id| attribute.
+ client_data_json_ = BuildClientDataJson(
+ ClientDataRequestType::kU2fSign, options->relying_party_id,
+ options->challenge, /*is_cross_origin=*/false);
+ } else if (payment) {
+ auto* web_contents = WebContents::FromRenderFrameHost(GetRenderFrameHost());
+ if (!web_contents) {
+ CompleteGetAssertionRequest(
+ blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR);
+ return;
+ }
+ url::Origin top_origin =
+ url::Origin::Create(web_contents->GetLastCommittedURL());
+ client_data_json_ = BuildClientDataJson(
+ ClientDataRequestType::kPaymentGet, caller_origin_.Serialize(),
+ options->challenge, is_cross_origin, std::move(payment),
+ relying_party_id_, top_origin.Serialize());
+ } else {
+ client_data_json_ = BuildClientDataJson(
+ ClientDataRequestType::kWebAuthnGet, caller_origin_.Serialize(),
+ options->challenge, is_cross_origin);
+ }
+
+ // Cryptotoken requests should be proxied without UI.
+ if (origin_is_crypto_token_extension || disable_ui_) {
+ DCHECK(!options->is_conditional);
+ request_delegate_->DisableUI();
+ }
+
+ request_delegate_->SetConditionalRequest(options->is_conditional);
+
+ if (options->allow_credentials.empty()) {
+ if (!GetWebAuthenticationDelegate()->SupportsResidentKeys(
+ GetRenderFrameHost())) {
+ CompleteGetAssertionRequest(
+ blink::mojom::AuthenticatorStatus::RESIDENT_CREDENTIALS_UNSUPPORTED);
+ return;
+ }
+ empty_allow_list_ = true;
+ }
+
+ if (options->appid) {
+ requested_extensions_.insert(RequestExtension::kAppID);
+ app_id_ = ProcessAppIdExtension(*options->appid, caller_origin_);
+ if (!app_id_) {
+ CompleteGetAssertionRequest(
+ blink::mojom::AuthenticatorStatus::INVALID_DOMAIN);
+ return;
+ }
+ }
+
+ if (options->large_blob_read && options->large_blob_write) {
+ CompleteGetAssertionRequest(
+ blink::mojom::AuthenticatorStatus::CANNOT_READ_AND_WRITE_LARGE_BLOB);
+ return;
+ }
+
+ if (options->large_blob_read) {
+ requested_extensions_.insert(RequestExtension::kLargeBlobRead);
+ } else if (options->large_blob_write) {
+ if (options->allow_credentials.size() != 1) {
+ CompleteGetAssertionRequest(blink::mojom::AuthenticatorStatus::
+ INVALID_ALLOW_CREDENTIALS_FOR_LARGE_BLOB);
+ return;
+ }
+ requested_extensions_.insert(RequestExtension::kLargeBlobWrite);
+ }
+
+ timer_->Start(
+ FROM_HERE, AdjustTimeout(options->timeout, GetRenderFrameHost()),
+ base::BindOnce(&AuthenticatorCommonTizen::OnTimeout, base::Unretained(this)));
+
+
+ bool is_first = true;
+ absl::optional<std::vector<uint8_t>> last_id;
+ if (options->prf) {
+ requested_extensions_.insert(RequestExtension::kPRF);
+ for (const auto& prf_input_from_renderer : options->prf_inputs) {
+ device::CtapGetAssertionOptions::PRFInput prf_input;
+
+ // This statement enforces invariants that should be established by the
+ // renderer.
+ if (
+ // Only the first element in the vector may be the default.
+ (!is_first && !prf_input_from_renderer->id) ||
+ // The PRF inputs must be sorted by credential ID to show that there
+ // are no duplicates.
+ (last_id.has_value() && prf_input_from_renderer->id.has_value() &&
+ *last_id >= *prf_input_from_renderer->id) ||
+ // The lengths are specified in authenticator.mojom, so hopefully Mojo
+ // enforces them too.
+ prf_input_from_renderer->first.size() != prf_input.salt1.size() ||
+ (prf_input_from_renderer->second &&
+ prf_input_from_renderer->second->size() != prf_input.salt1.size())) {
+ NOTREACHED();
+
+ CompleteGetAssertionRequest(
+ blink::mojom::AuthenticatorStatus::UNKNOWN_ERROR);
+ return;
+ }
+ is_first = false;
+ last_id = prf_input_from_renderer->id;
+
+ if (prf_input_from_renderer->id) {
+ prf_input.credential_id = std::move(*prf_input_from_renderer->id);
+ }
+
+ memcpy(prf_input.salt1.data(), prf_input_from_renderer->first.data(),
+ prf_input.salt1.size());
+ if (prf_input_from_renderer->second) {
+ prf_input.salt2.emplace();
+ memcpy(prf_input.salt2->data(), prf_input_from_renderer->second->data(),
+ prf_input.salt2->size());
+ }
+ }
+ }
+
+ if (options->large_blob_write) {
+ data_decoder_.GzipCompress(
+ *options->large_blob_write,
+ base::BindOnce(&AuthenticatorCommonTizen::OnLargeBlobCompressed,
+ weak_factory_.GetWeakPtr()));
+ return;
+ }
+
+ ga_options_.attestation_formats =
+ num_attestation_formats_ ? &device_attestation_formats_ : nullptr;
+
+ PopulateGAWebauthnArgs(std::move(options));
+ int ret =
+ wauthn_get_assertion(&ga_client_data_, &ga_options_, &ga_callbacks_);
+ if(ret != WAUTHN_ERROR_NONE)
+ Cancel();
+}
+
+void AuthenticatorCommonTizen::IsUserVerifyingPlatformAuthenticatorAvailable(
+ blink::mojom::Authenticator::
+ IsUserVerifyingPlatformAuthenticatorAvailableCallback callback) {
+ // Check for a delegate override. Chrome overrides IsUVPAA() in Guest mode
+ // and, on Windows only, in Incognito.
+ absl::optional<bool> is_uvpaa_override =
+ GetWebAuthenticationDelegate()
+ ->IsUserVerifyingPlatformAuthenticatorAvailableOverride(
+ GetRenderFrameHost());
+ if (is_uvpaa_override) {
+ std::move(callback).Run(*is_uvpaa_override);
+ return;
+ }
+
+ // Record IsUVPAA result in a UMA metric, but only if they're not the
+ // WebAuthenticationDelegate override value, so that results from the testing
+ // API and disabling in Guest/Off-The-Record profiles aren't counted.
+ auto uma_decorated_callback =
+ base::BindOnce([](bool available) {
+ base::UmaHistogramBoolean(
+ "WebAuthentication.IsUVPlatformAuthenticatorAvailable2", available);
+ return available;
+ }).Then(std::move(callback));
+
+#if defined(OS_MAC)
+ IsUVPlatformAuthenticatorAvailable(GetBrowserContext(),
+ std::move(uma_decorated_callback));
+#elif defined(OS_WIN)
+ IsUVPlatformAuthenticatorAvailable(std::move(uma_decorated_callback));
+#elif BUILDFLAG(IS_CHROMEOS_ASH)
+ IsUVPlatformAuthenticatorAvailable(std::move(uma_decorated_callback));
+#else
+ std::move(uma_decorated_callback).Run(false);
+#endif
+}
+
+void AuthenticatorCommonTizen::Cancel() {
+ // Invoke webauthn cancel
+ wauthn_cancel();
+ CancelWithStatus(blink::mojom::AuthenticatorStatus::ABORT_ERROR);
+}
+
+void AuthenticatorCommonTizen::SignalFailureToRequestDelegate(
+ const ::device::FidoAuthenticator* authenticator,
+ AuthenticatorRequestClientDelegate::InterestingFailureReason reason,
+ blink::mojom::AuthenticatorStatus status) {
+ error_awaiting_user_acknowledgement_ = status;
+
+ // The request has failed, but the UI may delay resolution of the request
+ // callback and cleanup of the FidoRequestHandler and its associated
+ // discoveries and authenticators. Tell them to stop processing the request in
+ // the meantime.
+ request_->StopDiscoveries();
+ request_->CancelActiveAuthenticators();
+
+ // If WebAuthnUi is enabled, this error blocks until after receiving user
+ // acknowledgement. Otherwise, the error is returned right away.
+ if (request_delegate_->DoesBlockRequestOnFailure(reason)) {
+ return;
+ }
+ CancelWithStatus(error_awaiting_user_acknowledgement_);
+} // namespace content
+
+// TODO(crbug.com/814418): Add web tests to verify timeouts are
+// indistinguishable from NOT_ALLOWED_ERROR cases.
+void AuthenticatorCommonTizen::OnTimeout() {
+ DCHECK(request_delegate_);
+ if (awaiting_attestation_response_) {
+ awaiting_attestation_response_ = false;
+ }
+
+ SignalFailureToRequestDelegate(
+ /*authenticator=*/nullptr,
+ AuthenticatorRequestClientDelegate::InterestingFailureReason::kTimeout,
+ blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR);
+}
+
+void AuthenticatorCommonTizen::CancelWithStatus(
+ blink::mojom::AuthenticatorStatus status) {
+ DCHECK(!make_credential_response_callback_ ||
+ !get_assertion_response_callback_);
+ if (make_credential_response_callback_) {
+ CompleteMakeCredentialRequest(status);
+ } else if (get_assertion_response_callback_) {
+ CompleteGetAssertionRequest(status);
+ }
+}
+
+void AuthenticatorCommonTizen::OnCancelFromUI() {
+ CancelWithStatus(error_awaiting_user_acknowledgement_);
+}
+
+blink::mojom::MakeCredentialAuthenticatorResponsePtr
+AuthenticatorCommonTizen::CreateMakeCredentialResponse(
+ const wauthn_pubkey_credential_attestation_s* pubkey_cred,
+ AttestationErasureOption attestation_erasure) {
+ auto response = blink::mojom::MakeCredentialAuthenticatorResponse::New();
+ auto common_info = blink::mojom::CommonCredentialInfo::New();
+common_info->client_data_json =
+ ToBuffer(*pubkey_cred->response->client_data_json);
+ common_info->raw_id = ToBuffer(*pubkey_cred->rawId);
+ common_info->id = Base64UrlEncode(common_info->raw_id);
+ base::flat_set<device::FidoTransportProtocol> transports;
+ if (!pubkey_cred->response->transports) {
+ transports.insert(device::FidoTransportProtocol::kMaxValue);
+ }
+
+ if (pubkey_cred->response->transports & 1) {
+ transports.insert(device::FidoTransportProtocol::kUsbHumanInterfaceDevice);
+ }
+ if (pubkey_cred->response->transports & 2) {
+ transports.insert(device::FidoTransportProtocol::kNearFieldCommunication);
+ }
+ if (pubkey_cred->response->transports & 4) {
+ transports.insert(device::FidoTransportProtocol::kBluetoothLowEnergy);
+ }
+ if (pubkey_cred->response->transports & 8) {
+ transports.insert(device::FidoTransportProtocol::kAndroidAccessory);
+ }
+ // if (pubkey_cred->response->transports & 16) { Need to check
+ // transports.insert(device::FidoTransportProtocol::kHybrid);
+ // }
+ if (pubkey_cred->response->transports & 32) {
+ transports.insert(device::FidoTransportProtocol::kInternal);
+ }
+ response->transports.assign(transports.begin(), transports.end());
+
+
+ response->attestation_object =
+ ToBuffer(*pubkey_cred->response->attestation_object);
+ common_info->authenticator_data =
+ ToBuffer(*pubkey_cred->response->authenticator_data);
+ if (pubkey_cred->response->subject_pubkey_info) {
+ response->public_key_der =
+ ToBuffer(*pubkey_cred->response->subject_pubkey_info);
+ }
+ response->info = std::move(common_info);
+
+ response->public_key_algo = pubkey_cred->response->pubkey_alg;
+
+ return response;
+}
+
+void AuthenticatorCommonTizen::CompleteMakeCredentialRequest(
+ blink::mojom::AuthenticatorStatus status,
+ blink::mojom::MakeCredentialAuthenticatorResponsePtr response,
+ Focus check_focus) {
+ DCHECK(make_credential_response_callback_);
+ if (check_focus != Focus::kDontCheck && !(request_delegate_ && IsFocused())) {
+ std::move(make_credential_response_callback_)
+ .Run(blink::mojom::AuthenticatorStatus::NOT_FOCUSED, nullptr);
+ } else {
+ std::move(make_credential_response_callback_)
+ .Run(status, std::move(response));
+ }
+
+ Cleanup();
+}
+
+blink::mojom::GetAssertionAuthenticatorResponsePtr
+AuthenticatorCommonTizen::CreateGetAssertionResponse(
+ const wauthn_pubkey_credential_assertion_s* pubkey_cred,
+ absl::optional<std::vector<uint8_t>> large_blob) {
+ auto response = blink::mojom::GetAssertionAuthenticatorResponse::New();
+ auto common_info = blink::mojom::CommonCredentialInfo::New();
+
+ common_info->client_data_json =
+ ToBuffer(*pubkey_cred->response->client_data_json);
+ common_info->raw_id = ToBuffer(*pubkey_cred->rawId);
+ common_info->id = Base64UrlEncode(common_info->raw_id);
+ response->info = std::move(common_info);
+ response->info->authenticator_data =
+ ToBuffer(*(pubkey_cred->response->authenticator_data));
+ response->signature = ToBuffer(*pubkey_cred->response->signature);
+
+ if (pubkey_cred->response->user_handle) {
+ pubkey_cred->response->user_handle->size
+ ? response->user_handle.emplace(
+ ToBuffer(*pubkey_cred->response->user_handle))
+ : response->user_handle.emplace();
+ }
+ return response;
+}
+
+void AuthenticatorCommonTizen::CompleteGetAssertionRequest(
+ blink::mojom::AuthenticatorStatus status,
+ blink::mojom::GetAssertionAuthenticatorResponsePtr response) {
+ DCHECK(get_assertion_response_callback_);
+ std::move(get_assertion_response_callback_).Run(status, std::move(response));
+ Cleanup();
+}
+
+void AuthenticatorCommonTizen::Cleanup() {
+ if (awaiting_attestation_response_) {
+ awaiting_attestation_response_ = false;
+ }
+
+ timer_->Stop();
+ request_.reset();
+ discovery_factory_.reset();
+ discovery_factory_testing_override_ = nullptr;
+ request_delegate_.reset();
+ make_credential_response_callback_.Reset();
+ get_assertion_response_callback_.Reset();
+ client_data_json_.clear();
+ app_id_.reset();
+ caller_origin_ = url::Origin();
+ relying_party_id_.clear();
+ empty_allow_list_ = false;
+ error_awaiting_user_acknowledgement_ =
+ blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR;
+ requested_extensions_.clear();
+}
+
+void AuthenticatorCommonTizen::DisableUI() {
+ disable_ui_ = true;
+}
+
+RenderFrameHost* AuthenticatorCommonTizen::GetRenderFrameHost() const {
+ RenderFrameHost* ret = RenderFrameHost::FromID(render_frame_host_id_);
+ DCHECK(ret);
+ return ret;
+}
+
+BrowserContext* AuthenticatorCommonTizen::GetBrowserContext() const {
+ return GetRenderFrameHost()->GetBrowserContext();
+}
+
+} // namespace content
--- /dev/null
+// 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.
+
+#ifndef CONTENT_BROWSER_WEBAUTH_AUTHENTICATOR_COMMON_TIZEN_H_
+#define CONTENT_BROWSER_WEBAUTH_AUTHENTICATOR_COMMON_TIZEN_H_
+
+#include <stdint.h>
+#include <webauthn.h>
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/containers/flat_set.h"
+#include "base/containers/span.h"
+#include "base/macros.h"
+#include "base/timer/timer.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/authenticator_request_client_delegate.h"
+#include "content/public/browser/global_routing_id.h"
+#include "services/data_decoder/public/cpp/data_decoder.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/blink/public/mojom/webauthn/authenticator.mojom.h"
+#include "url/origin.h"
+
+namespace base {
+class OneShotTimer;
+}
+
+namespace device {
+
+class FidoRequestHandlerBase;
+class FidoDiscoveryFactory;
+
+enum class FidoReturnCode : uint8_t;
+
+enum class GetAssertionStatus;
+enum class MakeCredentialStatus;
+
+} // namespace device
+
+namespace url {
+class Origin;
+}
+
+namespace content {
+
+class BrowserContext;
+class RenderFrameHost;
+class WebAuthRequestSecurityChecker;
+
+enum class RequestExtension;
+enum class AttestationErasureOption;
+
+// Common code for any WebAuthn Authenticator interfaces.
+class CONTENT_EXPORT AuthenticatorCommonTizen {
+ public:
+ // Creates a new AuthenticatorCommonTizen. Callers must ensure that this instance
+ // outlives the RenderFrameHost.
+ explicit AuthenticatorCommonTizen(RenderFrameHost* render_frame_host);
+ virtual ~AuthenticatorCommonTizen();
+
+ // This is not-quite an implementation of blink::mojom::Authenticator. The
+ // first two functions take the caller's origin explicitly. This allows the
+ // caller origin to be overridden if needed. `GetAssertion()` also takes the
+ // optional `payment` to add to "clientDataJson" after the browser displays
+ // the payment confirmation dialog to the user.
+ void MakeCredential(
+ url::Origin caller_origin,
+ blink::mojom::PublicKeyCredentialCreationOptionsPtr options,
+ blink::mojom::Authenticator::MakeCredentialCallback callback);
+ void GetAssertion(url::Origin caller_origin,
+ blink::mojom::PublicKeyCredentialRequestOptionsPtr options,
+ blink::mojom::PaymentOptionsPtr payment,
+ blink::mojom::Authenticator::GetAssertionCallback callback);
+ void IsUserVerifyingPlatformAuthenticatorAvailable(
+ blink::mojom::Authenticator::
+ IsUserVerifyingPlatformAuthenticatorAvailableCallback callback);
+ void Cancel();
+
+ void Cleanup();
+
+ void DisableUI();
+
+ // GetRenderFrameHost returns a pointer to the RenderFrameHost that was given
+ // to the constructor. Use this rather than keeping a copy of the
+ // RenderFrameHost* that was passed in.
+ //
+ // This object assumes that the RenderFrameHost overlives it but, in case it
+ // doesn't, this avoids holding a raw pointer and creating a use-after-free.
+ // If the RenderFrameHost has been destroyed then this function will return
+ // nullptr and the process will crash when it tries to use it.
+ RenderFrameHost* GetRenderFrameHost() const;
+
+ protected:
+ // MaybeCreateRequestDelegate returns the embedder-provided implementation of
+ // AuthenticatorRequestClientDelegate, which encapsulates per-request state
+ // relevant to the embedder, e.g. because it is used to display browser UI.
+ //
+ // Chrome may return nullptr here in order to ensure that at most one request
+ // per WebContents is ongoing at once.
+ virtual std::unique_ptr<AuthenticatorRequestClientDelegate>
+ MaybeCreateRequestDelegate();
+
+ std::unique_ptr<AuthenticatorRequestClientDelegate> request_delegate_;
+
+ private:
+
+
+ // Enumerates whether or not to check that the WebContents has focus.
+ enum class Focus {
+ kDoCheck,
+ kDontCheck,
+ };
+
+ // Replaces the current |request_| with a |MakeCredentialRequestHandler|,
+ // effectively restarting the request.
+ void StartMakeCredentialRequest(bool allow_skipping_pin_touch);
+
+ // Replaces the current |request_| with a |GetAssertionRequestHandler|,
+ // effectively restarting the request.
+ void StartGetAssertionRequest(bool allow_skipping_pin_touch);
+
+ bool IsFocused() const;
+
+ // Callback to handle the large blob being compressed before attempting to
+ // start a request.
+ void OnLargeBlobCompressed(
+ data_decoder::DataDecoder::ResultOrError<mojo_base::BigBuffer> result);
+
+ // Callback to handle the large blob being uncompressed before completing a
+ // request.
+ void OnLargeBlobUncompressed(
+ device::AuthenticatorGetAssertionResponse response,
+ data_decoder::DataDecoder::ResultOrError<mojo_base::BigBuffer> result);
+
+ // Runs when timer expires and cancels all issued requests to a U2fDevice.
+ void OnTimeout();
+ // Cancels the currently pending request (if any) with the supplied status.
+ void CancelWithStatus(blink::mojom::AuthenticatorStatus status);
+ // Runs when the user cancels WebAuthN request via UI dialog.
+ void OnCancelFromUI();
+
+
+ // Signals to the request delegate that the request has failed for |reason|.
+ // The request delegate decides whether to present the user with a visual
+ // error before the request is finally resolved with |status|.
+ void SignalFailureToRequestDelegate(
+ const device::FidoAuthenticator* authenticator,
+ AuthenticatorRequestClientDelegate::InterestingFailureReason reason,
+ blink::mojom::AuthenticatorStatus status);
+
+ // Creates a make credential response
+ blink::mojom::MakeCredentialAuthenticatorResponsePtr
+ CreateMakeCredentialResponse(
+ const wauthn_pubkey_credential_attestation_s* pubkey_cred,
+ AttestationErasureOption attestation_erasure);
+
+ // Runs |make_credential_response_callback_| and then Cleanup().
+ void CompleteMakeCredentialRequest(
+ blink::mojom::AuthenticatorStatus status,
+ blink::mojom::MakeCredentialAuthenticatorResponsePtr response = nullptr,
+ Focus focus_check = Focus::kDontCheck);
+
+ // Creates a get assertion response.
+ blink::mojom::GetAssertionAuthenticatorResponsePtr CreateGetAssertionResponse(
+ const wauthn_pubkey_credential_assertion_s* pubkey_cred,
+ absl::optional<std::vector<uint8_t>> large_blob = absl::nullopt);
+
+ // Runs |get_assertion_response_callback_| and then Cleanup().
+ void CompleteGetAssertionRequest(
+ blink::mojom::AuthenticatorStatus status,
+ blink::mojom::GetAssertionAuthenticatorResponsePtr response = nullptr);
+
+ BrowserContext* GetBrowserContext() const;
+ // Webauthn:
+ void PopulateMCWebauthnArgs(
+ blink::mojom::PublicKeyCredentialCreationOptionsPtr options);
+ void PopulateGAWebauthnArgs(
+ blink::mojom::PublicKeyCredentialRequestOptionsPtr options);
+ static void DisplayQRCallback(const char* qr_contents, void* data);
+ static void MCCallback(
+ const wauthn_pubkey_credential_attestation_s* pubkey_cred,
+ wauthn_error_e result,
+ void* data);
+ static void GACallback(
+ const wauthn_pubkey_credential_assertion_s* pubkey_cred,
+ wauthn_error_e result,
+ void* data);
+ static void MCUpdateLinkedDataCallback(
+ const wauthn_hybrid_linked_data_s* linked_data,
+ wauthn_error_e result,
+ void* data);
+ static void GAUpdateLinkedDataCallback(
+ const wauthn_hybrid_linked_data_s* linked_data,
+ wauthn_error_e result,
+ void* data);
+
+ const GlobalRenderFrameHostId render_frame_host_id_;
+ std::unique_ptr<device::FidoRequestHandlerBase> request_;
+ std::unique_ptr<device::FidoDiscoveryFactory> discovery_factory_;
+ device::FidoDiscoveryFactory* discovery_factory_testing_override_ = nullptr;
+ blink::mojom::Authenticator::MakeCredentialCallback
+ make_credential_response_callback_;
+ blink::mojom::Authenticator::GetAssertionCallback
+ get_assertion_response_callback_;
+ std::string client_data_json_;
+ // empty_allow_list_ is true iff a GetAssertion is currently pending and the
+ // request did not list any credential IDs in the allow list.
+ bool empty_allow_list_ = false;
+ bool disable_ui_ = false;
+ url::Origin caller_origin_;
+ std::string relying_party_id_;
+ scoped_refptr<WebAuthRequestSecurityChecker> security_checker_;
+
+ wauthn_client_data_s mc_client_data_ = {0};
+ wauthn_client_data_s ga_client_data_ = {0};
+ wauthn_pubkey_cred_creation_options_s mc_options_ = {0};
+ wauthn_pubkey_cred_request_options_s ga_options_ = {0};
+ wauthn_mc_callbacks_s mc_callbacks_ = {0};
+ wauthn_ga_callbacks_s ga_callbacks_ = {0};
+
+ // Data members for mc_client_data
+ std::vector<unsigned char> client_data_vector_;
+ wauthn_const_buffer_s client_data_json_buff_;
+ const std::string extension_id_[17] = {"appid", // 0
+ "txAuthSimple", // 1
+ "txAuthGeneric", // 2
+ "authnSel", // 3
+ "exts", // 4
+ "uvi", // 5
+ "loc", // 6
+ "uvm", // 7
+ "credProtect", // 8
+ "credBlob", // 9
+ "largeBlobKey", // 10
+ "minPinLength", // 11
+ "hmac-secret", // 12
+ "appidExclude", // 13
+ "credProps", // 14
+ "largeBlob", // 15
+ "payment"}; // 16
+ std::vector<std::string> extension_value_;
+ // Data members for mc_options
+ wauthn_rp_entity_s rp_ = {0};
+ wauthn_user_entity_s user_ = {0};
+ wauthn_pubkey_cred_params_s pubkey_cred_params_ = {0};
+ wauthn_pubkey_cred_descriptors_s excluded_credentials_ = {0};
+ wauthn_attestation_formats_s mc_attestation_formats_ = {0};
+ wauthn_authentication_exts_s mc_extensions_ = {0};
+ wauthn_authenticator_sel_cri_s mc_authenticator_selection_criteria_ = {
+ WAUTHN_AUTHENTICATOR_ATTACHMENT_NONE, WAUTHN_RESIDENT_KEY_REQUIREMENT_NONE,false,WAUTHN_USER_VERIFICATION_REQUIREMENT_NONE
+ };
+ // mc_options.rp
+ std::string rel_party_id_;
+ std::string rel_party_name_;
+
+ // mc_options.user
+ wauthn_const_buffer_s user_id_buff_ = {0};
+ std::vector<uint8_t> user_id_vector_;
+ std::string user_name_string_;
+ std::string user_display_name_string_;
+
+ // mc_options.pubkey_cred_params
+ std::vector<wauthn_pubkey_cred_param_s> params_vector_;
+
+ // mc_options.exclude_credentials
+ std::vector<wauthn_pubkey_cred_descriptor_s> excluded_creds_vector_;
+ std::vector<std::vector<uint8_t>> excluded_creds_id_int8_vector_;
+ std::vector<wauthn_const_buffer_s> excluded_creds_id_buffer_vector_;
+
+ // mc_options.attestation_formats
+ std::vector<std::string> mc_attestation_formats_string_vector_;
+ std::vector<wauthn_const_buffer_s> mc_attestation_formats_vector_;
+
+ // mc_options_.extensions
+ std::vector<wauthn_const_buffer_s> mc_extension_id_buffer_vector_;
+ std::vector<wauthn_const_buffer_s> mc_extension_value_buffer_vector_;
+ std::vector<wauthn_authentication_ext_s> mc_extensions_vector_;
+
+ // Data members for GA
+ std::string rp_id_string_;
+ std::vector<wauthn_pubkey_cred_descriptor_s> pubkey_cred_descriptor_vector_;
+ std::vector<std::vector<uint8_t>> pubkey_cred_id_int8_vector_;
+ std::vector<wauthn_const_buffer_s> pubkey_cred_id_buffer_vector_;
+ wauthn_pubkey_cred_descriptors_s pubkey_cred_descriptors_ = {0};
+
+ wauthn_attestation_pref_e device_attestation_ = WAUTHN_ATTESTATION_PREF_NONE;
+ int num_attestation_formats_ = 0;
+
+ std::vector<std::string> ga_attestation_formats_string_vector_;
+ std::vector<wauthn_const_buffer_s> ga_attestation_formats_vector_;
+ wauthn_attestation_formats_s device_attestation_formats_ = {0};
+ wauthn_authentication_exts_s ga_extensions_ = {0};
+ std::vector<wauthn_const_buffer_s> ga_extension_id_buffer_vector_;
+ std::vector<wauthn_const_buffer_s> ga_extension_value_buffer_vector_;
+ std::vector<wauthn_authentication_ext_s> ga_extensions_vector_;
+
+ wauthn_ga_callbacks_s gaCallbacks;
+ std::unique_ptr<base::OneShotTimer> timer_ =
+ std::make_unique<base::OneShotTimer>();
+ absl::optional<std::string> app_id_;
+ // awaiting_attestation_response_ is true if the embedder has been queried
+ // about an attestsation decision and the response is still pending.
+ bool awaiting_attestation_response_ = false;
+ blink::mojom::AuthenticatorStatus error_awaiting_user_acknowledgement_ =
+ blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR;
+ data_decoder::DataDecoder data_decoder_;
+
+ base::flat_set<RequestExtension> requested_extensions_;
+
+ base::WeakPtrFactory<AuthenticatorCommonTizen> weak_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(AuthenticatorCommonTizen);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_WEBAUTH_AUTHENTICATOR_COMMON_H_