#include "content/browser/webauthn/authenticator_common_tizen.h"
#include <cstring>
+#include <iomanip>
#include <iostream>
#include <mutex>
#include <optional>
#include "device/fido/public_key_credential_descriptor.h"
#include "device/fido/public_key_credential_params.h"
#include "services/metrics/public/cpp/ukm_builders.h"
+#include "third_party/abseil-cpp/absl/types/variant.h"
#include "third_party/boringssl/src/include/openssl/sha.h"
+#include "tizen_src/ewk/efl_integration/common/content_switches_efl.h"
namespace content {
namespace {
+bool supportLinkedDevice = false;
WebAuthenticationDelegate* GetWebAuthenticationDelegate() {
return GetContentClient()->browser()->GetWebAuthenticationDelegate();
}
void AuthenticatorCommonTizen::DisplayQRCallback(const char* qr_contents,
void* data) {
- LOG(INFO) << __FUNCTION__;
+ LOG(INFO) << "[Passkey] DisplayQRCallback invoked";
AuthenticatorCommonTizen* thiz =
reinterpret_cast<AuthenticatorCommonTizen*>(data);
static_cast<RenderFrameHostImpl*>(thiz->GetRenderFrameHost());
std::string encoded(qr_contents);
+ if (thiz->mc_options_.linked_device || thiz->ga_options_.linked_device) {
+ LOG(INFO) << "[Passkey] linked_device is not null, do not display QR code";
+ return;
+ }
+
if (encoded.empty()) {
LOG(ERROR) << __FUNCTION__ << " terminated with empty QR URL";
thiz->CompleteMakeCredentialRequest(
const wauthn_pubkey_credential_attestation_s* pubkey_cred,
wauthn_error_e result,
void* data) {
- LOG(INFO) << __FUNCTION__;
-
- if (result == WAUTHN_ERROR_CANCELED) {
- return;
- }
+ LOG(INFO) << "[Passkey] MCCallback invoked, result : " << (int)result;
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)));
+ FROM_HERE,
+ base::BindOnce(&RenderFrameHostImpl::UpdateWAuthnResult,
+ base::Unretained(render_frame_host_impl), result));
+
+ if (result == WAUTHN_ERROR_CANCELED) {
+ LOG(INFO) << "[Passkey] WAUTHN_ERROR_CANCELED, MC failed.";
+ return;
+ }
+ if (result != WAUTHN_ERROR_NONE) {
+ LOG(INFO) << "[Passkey] result is not WAUTHN_ERROR_NONE, MC failed.";
+ return;
+ }
+
+ if (thiz->mc_options_.linked_device) {
+ LOG(INFO) << "[Passkey] Do not need to close QR code";
+ } else {
+ LOG(INFO) << "[Passkey] Need to close QR code";
+ 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 (!pubkey_cred || pubkey_cred->linked_device == nullptr) {
+ LOG(INFO) << "[Passkey] response without linked_device";
+ } else {
+ LOG(INFO) << "[Passkey] response with linked_device, supportLinkedDevice : "
+ << (int)supportLinkedDevice;
+ if (supportLinkedDevice) {
+ LOG(INFO) << "[Passkey] response with linked_device, update info";
+ thiz->UpdateLinkedData(pubkey_cred->linked_device);
+ }
+ }
if (!pubkey_cred || result != WAUTHN_ERROR_NONE) {
LOG(ERROR) << __FUNCTION__ << " terminated with error status: "
const wauthn_pubkey_credential_assertion_s* pubkey_cred,
wauthn_error_e result,
void* data) {
- LOG(INFO) << __FUNCTION__;
+ LOG(INFO) << "[Passkey] GACallback invoked, result : " << (int)result;
+ 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::UpdateWAuthnResult,
+ base::Unretained(render_frame_host_impl), result));
if (result == WAUTHN_ERROR_CANCELED) {
+ LOG(INFO) << "[Passkey] WAUTHN_ERROR_CANCELED, GA failed.";
+ return;
+ }
+ if (result != WAUTHN_ERROR_NONE) {
+ LOG(INFO) << "[Passkey] result is not WAUTHN_ERROR_NONE, GA failed.";
return;
}
- AuthenticatorCommonTizen* thiz =
- reinterpret_cast<AuthenticatorCommonTizen*>(data);
- RenderFrameHostImpl* const render_frame_host_impl =
- static_cast<RenderFrameHostImpl*>(thiz->GetRenderFrameHost());
+ if (thiz->ga_options_.linked_device) {
+ LOG(INFO) << "[Passkey] Do not need to close QR code";
+ } else {
+ LOG(INFO) << "[Passkey] Need to close QR code";
+ 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)));
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE, base::BindOnce(&RenderFrameHostImpl::CloseQRCode,
+ base::Unretained(render_frame_host_impl)));
+ }
+
+ if (!pubkey_cred || pubkey_cred->linked_device == nullptr) {
+ LOG(INFO) << "[Passkey] response without linked_device";
+ } else {
+ LOG(INFO) << "[Passkey] response with linked_device, supportLinkedDevice : "
+ << (int)supportLinkedDevice;
+ if (supportLinkedDevice) {
+ LOG(INFO) << "[Passkey] response with linked_device, update info";
+ thiz->UpdateLinkedData(pubkey_cred->linked_device);
+ }
+ }
if (!pubkey_cred || result != WAUTHN_ERROR_NONE) {
LOG(ERROR) << __FUNCTION__ << " terminated with error status: "
const wauthn_hybrid_linked_data_s* linked_data,
wauthn_error_e result,
void* data) {
- NOTIMPLEMENTED();
+ LOG(INFO) << "[Passkey] MCUpdateLinkedDataCallback invoked, result : "
+ << (int)result;
+ /* When WAUTHN_ERROR_NONE_AND_WAIT arrived, should keep waiting.
+ Also not update linked device info under other error circumstances*/
+ if (result != WAUTHN_ERROR_NONE) {
+ return;
+ }
+ LOG(INFO) << "[Passkey] update linked info";
+ if (supportLinkedDevice) {
+ AuthenticatorCommonTizen* thiz =
+ reinterpret_cast<AuthenticatorCommonTizen*>(data);
+ if (linked_data == nullptr) {
+ LOG(INFO) << "[Passkey] linked data is NULL, do not update";
+ return;
+ }
+ thiz->UpdateLinkedData(linked_data);
+ }
}
void AuthenticatorCommonTizen::GetAssertionUpdateLinkedDataCallback(
const wauthn_hybrid_linked_data_s* linked_data,
wauthn_error_e result,
void* data) {
- NOTIMPLEMENTED();
+ LOG(INFO) << "[Passkey] GAUpdateLinkedDataCallback invoked, result : "
+ << (int)result;
+ /* When WAUTHN_ERROR_NONE_AND_WAIT arrived, should keep waiting.
+ Also not update linked device info under other error circumstances*/
+ if (result != WAUTHN_ERROR_NONE) {
+ return;
+ }
+ LOG(INFO) << "[Passkey] update linked info";
+ if (supportLinkedDevice) {
+ AuthenticatorCommonTizen* thiz =
+ reinterpret_cast<AuthenticatorCommonTizen*>(data);
+ if (linked_data == nullptr) {
+ LOG(INFO) << "[Passkey] linked data is NULL, do not update";
+ return;
+ }
+ thiz->UpdateLinkedData(linked_data);
+ }
}
// RequestState contains all state that is specific to a single WebAuthn call.
remote_rp_id_validation;
};
+std::string to_hex_string(const unsigned char* data, int length) {
+ std::stringstream ss;
+ for (int i = 0; i < length; ++i) {
+ ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(data[i]);
+ }
+ return ss.str();
+}
+
// static
std::unique_ptr<AuthenticatorCommon> AuthenticatorCommon::Create(
RenderFrameHost* render_frame_host) {
render_frame_host,
BackForwardCacheDisable::DisabledReason(
BackForwardCacheDisable::DisabledReasonId::kWebAuthenticationAPI));
+
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kTizenWAuthnLinkedDeviceEnable)) {
+ LOG(INFO) << "[Passkey] browser support LinkedDevice scenario";
+ supportLinkedDevice = true;
+ } else {
+ LOG(INFO) << "[Passkey] browser not support LinkedDevice scenario";
+ }
}
AuthenticatorCommonTizen::~AuthenticatorCommonTizen() = default;
WebContents::FromRenderFrameHost(GetRenderFrameHost()));
}
+void AuthenticatorCommonTizen::DisplayWauthnDialog() {
+ LOG(INFO) << "[Passkey] DisplayWauthnDialog";
+ RenderFrameHostImpl* const render_frame_host_impl =
+ static_cast<RenderFrameHostImpl*>(this->GetRenderFrameHost());
+
+ LOG(INFO) << "[Passkey] TO render_frame_host_impl->DisplayWauthnDialog";
+ render_frame_host_impl->DisplayWauthnDialog();
+}
+
+void AuthenticatorCommonTizen::UpdateLinkedData(
+ const wauthn_hybrid_linked_data_s* linked_data) {
+ RenderFrameHostImpl* const render_frame_host_impl =
+ static_cast<RenderFrameHostImpl*>(this->GetRenderFrameHost());
+
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
+ base::BindOnce(&RenderFrameHostImpl::UpdateLinkedData,
+ base::Unretained(render_frame_host_impl), (const void*)linked_data));
+
+ LOG(INFO) << "[Passkey] contact_id size : "
+ << linked_data->contact_id->size;
+ LOG(INFO) << "[Passkey] contact_id : "
+ << to_hex_string(linked_data->contact_id->data, linked_data->contact_id->size);
+
+ LOG(INFO) << "[Passkey] link_id size : "
+ << linked_data->link_id->size;
+ LOG(INFO) << "[Passkey] link_id : "
+ << to_hex_string(linked_data->link_id->data, linked_data->link_id->size);
+
+ LOG(INFO) << "[Passkey] link_secret size : "
+ << linked_data->link_secret->size;
+ LOG(INFO) << "[Passkey] link_secret : "
+ << to_hex_string(linked_data->link_secret->data, linked_data->link_secret->size);
+
+ LOG(INFO) << "[Passkey] authenticator_pubkey size : "
+ << linked_data->authenticator_pubkey->size;
+ LOG(INFO) << "[Passkey] authenticator_pubkey : "
+ << to_hex_string(linked_data->authenticator_pubkey->data, linked_data->authenticator_pubkey->size);
+
+ LOG(INFO) << "[Passkey] authenticator_name size : "
+ << linked_data->authenticator_name->size;
+ LOG(INFO) << "[Passkey] authenticator_name : "
+ << to_hex_string(linked_data->authenticator_name->data, linked_data->authenticator_name->size);
+
+ LOG(INFO) << "[Passkey] signature size : "
+ << linked_data->signature->size;
+ LOG(INFO) << "[Passkey] signature : "
+ << to_hex_string(linked_data->signature->data, linked_data->signature->size);
+
+ LOG(INFO) << "[Passkey] tunnel_server_domain size : "
+ << linked_data->tunnel_server_domain->size;
+ LOG(INFO) << "[Passkey] tunnel_server_domain : "
+ << to_hex_string(linked_data->tunnel_server_domain->data, linked_data->tunnel_server_domain->size);
+
+ LOG(INFO) << "[Passkey] identity_key size : "
+ << linked_data->identity_key->size;
+ LOG(INFO) << "[Passkey] identity_key : "
+ << to_hex_string(linked_data->identity_key->data, linked_data->identity_key->size);
+
+}
+
void AuthenticatorCommonTizen::PopulateMakeCredentialWebAuthnArguments(
blink::mojom::PublicKeyCredentialCreationOptionsPtr options) {
+ LOG(INFO) << "[Passkey] PopulateMCWebauthnArgs";
std::memset(&mc_options_, 0, sizeof(mc_options_));
// Client data
void AuthenticatorCommonTizen::PopulateGetAssertionWebAuthnArguments(
blink::mojom::PublicKeyCredentialRequestOptionsPtr options) {
+ LOG(INFO) << "[Passkey] PopulateGAWebauthnArgs";
std::memset(&ga_options_, 0, sizeof(ga_options_));
// Client data
url::Origin caller_origin,
blink::mojom::PublicKeyCredentialCreationOptionsPtr options,
MakeCredentialCallback callback) {
- LOG(INFO) << __FUNCTION__;
+ LOG(INFO) << "[Passkey] AuthenticatorCommonTizen::MakeCredential";
if (req_state_) {
+ LOG(INFO) << "[Passkey] req_state_ not NULL";
std::move(callback).Run(blink::mojom::AuthenticatorStatus::PENDING_REQUEST,
nullptr, nullptr);
return;
security_checker_->ValidateAncestorOrigins(caller_origin, request_type,
&is_cross_origin_iframe);
if (status != blink::mojom::AuthenticatorStatus::SUCCESS) {
+ LOG(INFO) << "[Passkey] ValidateAncestorOrigins status : " << (int)status;
req_state_->request_outcome = MakeCredentialOutcome::kSecurityError;
CompleteMakeCredentialRequest(status);
return;
req_state_->request_outcome = MakeCredentialOutcome::kOtherFailure;
CompleteMakeCredentialRequest(
blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR);
+ LOG(INFO) << "[Passkey] invalid exclude_credentials length";
return;
}
if (rp_id_validation_result != blink::mojom::AuthenticatorStatus::SUCCESS) {
req_state_->request_outcome = MakeCredentialOutcome::kSecurityError;
+ LOG(INFO) << "[Passkey] ValidateDomainAndRelyingPartyID rp_id_validation_result : "
+ << (int)rp_id_validation_result;
CompleteMakeCredentialRequest(rp_id_validation_result);
return;
}
req_state_->request_delegate = MaybeCreateRequestDelegate();
if (!req_state_->request_delegate) {
+ LOG(INFO) << "[Passkey] request_delegate is NULL";
req_state_->request_outcome = MakeCredentialOutcome::kOtherFailure;
CompleteMakeCredentialRequest(
blink::mojom::AuthenticatorStatus::PENDING_REQUEST);
!disable_tls_check_ &&
!GetContentClient()->browser()->IsSecurityLevelAcceptableForWebAuthn(
GetRenderFrameHost(), caller_origin)) {
+ LOG(INFO) << "[Passkey] CERTIFICATE_ERROR";
req_state_->request_outcome = MakeCredentialOutcome::kOtherFailure;
CompleteMakeCredentialRequest(
blink::mojom::AuthenticatorStatus::CERTIFICATE_ERROR);
*options->appid_exclude, caller_origin,
options->remote_desktop_client_override, &appid_exclude.value());
if (add_id_status != blink::mojom::AuthenticatorStatus::SUCCESS) {
+ LOG(INFO) << "[Passkey] ValidateAppIdExtension add_id_status : "
+ << (int)add_id_status;
req_state_->request_outcome = MakeCredentialOutcome::kSecurityError;
CompleteMakeCredentialRequest(add_id_status);
return;
if (proxy) {
if (options->remote_desktop_client_override) {
// Don't allow proxying of an already proxied request.
+ LOG(INFO) << "[Passkey] NOT_ALLOWED_ERROR";
req_state_->request_outcome = MakeCredentialOutcome::kOtherFailure;
CompleteMakeCredentialRequest(
blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR);
return;
}
+ LOG(INFO) << "[Passkey] proxy not NULL";
options->remote_desktop_client_override =
blink::mojom::RemoteDesktopClientOverride::New(
/*origin=*/req_state_->caller_origin,
// This will be handled by the request handler.
break;
case device::fido_filter::Action::BLOCK:
+ LOG(INFO) << "[Passkey] fido_filter::Action::BLOCK";
req_state_->request_outcome = MakeCredentialOutcome::kFilterBlock;
CompleteMakeCredentialRequest(
blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR);
}
if (!IsFocused()) {
+ LOG(INFO) << "[Passkey] Not focused";
req_state_->request_outcome = MakeCredentialOutcome::kOtherFailure;
CompleteMakeCredentialRequest(
blink::mojom::AuthenticatorStatus::NOT_FOCUSED);
blink::mojom::ProtectionPolicy::UV_REQUIRED &&
authenticator_selection_criteria.user_verification_requirement !=
device::UserVerificationRequirement::kRequired)) {
+ LOG(INFO) << "[Passkey] PROTECTION_POLICY_INCONSISTENT";
req_state_->request_outcome = MakeCredentialOutcome::kOtherFailure;
CompleteMakeCredentialRequest(
blink::mojom::AuthenticatorStatus::PROTECTION_POLICY_INCONSISTENT);
std::optional<device::PRFInput> prf_input =
ParsePRFInputForMakeCredential(options->prf_input);
if (!prf_input) {
+ LOG(INFO) << "[Passkey] invalid PRF inputs, NOT_ALLOWED_ERROR";
mojo::ReportBadMessage("invalid PRF inputs");
req_state_->request_outcome = MakeCredentialOutcome::kOtherFailure;
CompleteMakeCredentialRequest(
ctap_make_credential_request->attestation_preference = attestation;
PopulateMakeCredentialWebAuthnArguments(std::move(options));
+ if (supportLinkedDevice) {
+ DisplayWauthnDialog();
+ } else {
+ ContinueMakeCredential();
+ }
+}
+
+void AuthenticatorCommonTizen::ContinueMakeCredential() {
+ LOG(INFO) << "[Passkey] TO wauthn_make_credential, authenticator : " << this;
+ LOG(INFO) << "[Passkey] TO wauthn_make_credential with linked_device : "
+ << ((mc_options_.linked_device) ? "yes" : "no");
int ret = wauthn_make_credential(&client_data_, &mc_options_, &mc_callbacks_);
if (ret != WAUTHN_ERROR_NONE) {
LOG(ERROR) << __FUNCTION__ << " call returned error status: "
blink::mojom::PublicKeyCredentialRequestOptionsPtr options,
blink::mojom::PaymentOptionsPtr payment_options,
GetAssertionCallback callback) {
- LOG(INFO) << __FUNCTION__;
+ LOG(INFO) << "[Passkey] AuthenticatorCommonTizen::GetAssertion";
if (req_state_) {
+ LOG(INFO) << "[Passkey] req_state_ not NULL";
std::move(callback).Run(blink::mojom::AuthenticatorStatus::PENDING_REQUEST,
nullptr, nullptr);
return;
: WebAuthRequestSecurityChecker::RequestType::
kGetPaymentCredentialAssertion;
if (!payment_options.is_null() && options->allow_credentials.empty()) {
+ LOG(INFO) << "[Passkey] NOT_ALLOWED_ERROR";
req_state_->request_outcome = GetAssertionOutcome::kOtherFailure;
CompleteGetAssertionRequest(
blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR);
security_checker_->ValidateAncestorOrigins(caller_origin, request_type,
&is_cross_origin_iframe);
if (status != blink::mojom::AuthenticatorStatus::SUCCESS) {
+ LOG(INFO) << "[Passkey] ValidateAncestorOrigins status : " << (int)status;
req_state_->request_outcome = GetAssertionOutcome::kSecurityError;
CompleteGetAssertionRequest(status);
return;
&options->allow_credentials)) {
mojo::ReportBadMessage("invalid allow_credentials length");
req_state_->request_outcome = GetAssertionOutcome::kOtherFailure;
+ LOG(INFO)
+ << "[Passkey] invalid allow_credentials length, NOT_ALLOWED_ERROR";
CompleteGetAssertionRequest(
blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR);
return;
blink::mojom::PaymentOptionsPtr payment_options,
bool is_cross_origin_iframe,
blink::mojom::AuthenticatorStatus rp_id_validation_result) {
+ LOG(INFO) << "[Passkey] ContinueGetAssertionAfterRpIdCheck";
if (!CheckRequestKey(request_key)) {
+ LOG(INFO) << "[Passkey] CheckRequestKey failed";
return;
}
req_state_->remote_rp_id_validation.reset();
if (rp_id_validation_result != blink::mojom::AuthenticatorStatus::SUCCESS) {
req_state_->request_outcome = GetAssertionOutcome::kSecurityError;
+ LOG(INFO) << "[Passkey] ValidateDomainAndRelyingPartyID rp_id_validation_result : "
+ << (int)rp_id_validation_result;
CompleteGetAssertionRequest(rp_id_validation_result);
return;
}
req_state_->request_delegate = MaybeCreateRequestDelegate();
if (!req_state_->request_delegate) {
+ LOG(INFO) << "[Passkey] request_delegate is NULL";
req_state_->request_outcome = GetAssertionOutcome::kOtherFailure;
CompleteGetAssertionRequest(
blink::mojom::AuthenticatorStatus::PENDING_REQUEST);
!disable_tls_check_ &&
!GetContentClient()->browser()->IsSecurityLevelAcceptableForWebAuthn(
GetRenderFrameHost(), caller_origin)) {
+ LOG(INFO) << "[Passkey] CERTIFICATE_ERROR";
req_state_->request_outcome = GetAssertionOutcome::kOtherFailure;
CompleteGetAssertionRequest(
blink::mojom::AuthenticatorStatus::CERTIFICATE_ERROR);
*options->extensions->appid, caller_origin,
options->extensions->remote_desktop_client_override, &app_id);
if (add_id_status != blink::mojom::AuthenticatorStatus::SUCCESS) {
+ LOG(INFO) << "[Passkey] ValidateAppIdExtension add_id_status : "
+ << (int)add_id_status;
req_state_->request_outcome = GetAssertionOutcome::kSecurityError;
CompleteGetAssertionRequest(add_id_status);
return;
if (options->is_conditional ||
(options->extensions->remote_desktop_client_override)) {
// Don't allow proxying of an already proxied or conditional request.
+ LOG(INFO) << "[Passkey] NOT_ALLOWED_ERROR";
req_state_->request_outcome = GetAssertionOutcome::kOtherFailure;
CompleteGetAssertionRequest(
blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR);
options,
base::BindOnce(&AuthenticatorCommonTizen::OnGetAssertionProxyResponse,
weak_factory_.GetWeakPtr(), GetRequestKey()));
+ LOG(INFO) << "[Passkey] proxy is not NULL";
return;
}
req_state_->relying_party_id,
/*device=*/std::nullopt,
/*id=*/std::nullopt) == device::fido_filter::Action::BLOCK) {
+ LOG(INFO) << "[Passkey] fido_filter::Action::BLOCK, NOT_ALLOWED_ERROR";
req_state_->request_outcome = GetAssertionOutcome::kFilterBlock;
CompleteGetAssertionRequest(
blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR);
if (options->extensions->large_blob_read &&
options->extensions->large_blob_write) {
+ LOG(INFO) << "[Passkey] CANNOT_READ_AND_WRITE_LARGE_BLOB";
req_state_->request_outcome = GetAssertionOutcome::kOtherFailure;
CompleteGetAssertionRequest(
blink::mojom::AuthenticatorStatus::CANNOT_READ_AND_WRITE_LARGE_BLOB);
req_state_->requested_extensions.insert(RequestExtension::kLargeBlobRead);
} else if (options->extensions->large_blob_write) {
if (options->allow_credentials.size() != 1) {
+ LOG(INFO) << "[Passkey] INVALID_ALLOW_CREDENTIALS_FOR_LARGE_BLOB";
req_state_->request_outcome = GetAssertionOutcome::kOtherFailure;
CompleteGetAssertionRequest(blink::mojom::AuthenticatorStatus::
INVALID_ALLOW_CREDENTIALS_FOR_LARGE_BLOB);
// authenticator support on Android.
if (!prf_inputs || options->extensions->prf_inputs_hashed) {
mojo::ReportBadMessage("invalid PRF inputs");
+ LOG(INFO) << "[Passkey] invalid PRF inputs, NOT_ALLOWED_ERROR";
req_state_->request_outcome = GetAssertionOutcome::kOtherFailure;
CompleteGetAssertionRequest(
blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR);
ContinueGetAssertionAfterBrowserPasskeysAvailabilityCheck(
RequestKey request_key,
bool available) {
+ LOG(INFO) << "[Passkey] ContinueGetAssertionAfterBrowserPasskeysAvailabilityCheck";
if (!CheckRequestKey(request_key)) {
return;
}
void AuthenticatorCommonTizen::ContinueGetAssertionAfterIsUvpaaOverrideCheck(
RequestKey request_key,
std::optional<bool> is_uvpaa_override) {
+ LOG(INFO) << "[Passkey] ContinueGetAssertionAfterIsUvpaaOverrideCheck";
if (!CheckRequestKey(request_key)) {
return;
}
is_uvpaa_override_ = is_uvpaa_override;
+ if (supportLinkedDevice) {
+ DisplayWauthnDialog();
+ } else {
+ ContinueGetAssertion();
+ }
+}
+
+void AuthenticatorCommonTizen::ContinueGetAssertion() {
+ LOG(INFO) << "[Passkey] TO wauthn_get_assertion, authenticator : " << this;
+ LOG(INFO) << "[Passkey] TO wauthn_get_assertion with linked_device : "
+ << ((mc_options_.linked_device) ? "yes" : "no");
int ret = wauthn_get_assertion(&client_data_, &ga_options_, &ga_callbacks_);
if (ret != WAUTHN_ERROR_NONE) {
LOG(ERROR) << __FUNCTION__ << " call returned error status: "
#endif
}
+void AuthenticatorCommonTizen::SetWauthnLinkedDevice(void* linkDevice) {
+ LOG(INFO) << "[Passkey] Set linkDevice, authenticator : " << this;
+ wauthn_hybrid_linked_data_s *deviceInfo = (wauthn_hybrid_linked_data_s *)linkDevice;
+ LOG(INFO) << "[Passkey] contact_id size : "
+ << deviceInfo->contact_id->size;
+ LOG(INFO) << "[Passkey] contact_id : "
+ << to_hex_string(deviceInfo->contact_id->data, deviceInfo->contact_id->size);
+
+ LOG(INFO) << "[Passkey] link_id size : "
+ << deviceInfo->link_id->size;
+ LOG(INFO) << "[Passkey] link_id : "
+ << to_hex_string(deviceInfo->link_id->data, deviceInfo->link_id->size);
+
+ LOG(INFO) << "[Passkey] link_secret size : "
+ << deviceInfo->link_secret->size;
+ LOG(INFO) << "[Passkey] link_secret : "
+ << to_hex_string(deviceInfo->link_secret->data, deviceInfo->link_secret->size);
+
+ LOG(INFO) << "[Passkey] authenticator_pubkey size : "
+ << deviceInfo->authenticator_pubkey->size;
+ LOG(INFO) << "[Passkey] authenticator_pubkey : "
+ << to_hex_string(deviceInfo->authenticator_pubkey->data, deviceInfo->authenticator_pubkey->size);
+
+ LOG(INFO) << "[Passkey] authenticator_name size : "
+ << deviceInfo->authenticator_name->size;
+ LOG(INFO) << "[Passkey] authenticator_name : "
+ << to_hex_string(deviceInfo->authenticator_name->data, deviceInfo->authenticator_name->size);
+
+ LOG(INFO) << "[Passkey] signature size : "
+ << deviceInfo->signature->size;
+ LOG(INFO) << "[Passkey] signature : "
+ << to_hex_string(deviceInfo->signature->data, deviceInfo->signature->size);
+
+ LOG(INFO) << "[Passkey] tunnel_server_domain size : "
+ << deviceInfo->tunnel_server_domain->size;
+ LOG(INFO) << "[Passkey] tunnel_server_domain : "
+ << to_hex_string(deviceInfo->tunnel_server_domain->data, deviceInfo->tunnel_server_domain->size);
+
+ LOG(INFO) << "[Passkey] identity_key size : "
+ << deviceInfo->identity_key->size;
+ LOG(INFO) << "[Passkey] identity_key : "
+ << to_hex_string(deviceInfo->identity_key->data, deviceInfo->identity_key->size);
+
+ if (absl::holds_alternative<MakeCredentialCallback>(req_state_.get()->response_callback)) {
+ mc_options_.linked_device = (wauthn_hybrid_linked_data_s*)linkDevice;
+ ContinueMakeCredential();
+ } else if (absl::holds_alternative<GetAssertionCallback>(req_state_.get()->response_callback)) {
+ ga_options_.linked_device = (wauthn_hybrid_linked_data_s*)linkDevice;
+ ContinueGetAssertion();
+ } else {
+ LOG(INFO) << "[Passkey] invalid req_state_";
+ }
+}
+
+void AuthenticatorCommonTizen::ClearWauthnLinkedDevice() {
+ LOG(INFO) << "[Passkey] Clear linkDevice, authenticator : " << this;
+ if (absl::holds_alternative<MakeCredentialCallback>(req_state_.get()->response_callback)) {
+ mc_options_.linked_device = nullptr;
+ ContinueMakeCredential();
+ } else if (absl::holds_alternative<GetAssertionCallback>(req_state_.get()->response_callback)) {
+ ga_options_.linked_device = nullptr;
+ ContinueGetAssertion();
+ } else {
+ LOG(INFO) << "[Passkey] invalid req_state_";
+ }
+}
+
void AuthenticatorCommonTizen::Report(
url::Origin caller_origin,
blink::mojom::PublicKeyCredentialReportOptionsPtr options,
void AuthenticatorCommonTizen::BeginRequestTimeout(
std::optional<base::TimeDelta> timeout) {
+ LOG(INFO) << "[Passkey] timeout(microseconds) : "
+ << timeout->InMicroseconds();
req_state_->timer->Start(FROM_HERE,
AdjustTimeout(timeout, GetRenderFrameHost()),
base::BindOnce(&AuthenticatorCommonTizen::OnTimeout,
// TODO(crbug.com/41371792): Add web tests to verify timeouts are
// indistinguishable from NOT_ALLOWED_ERROR cases.
void AuthenticatorCommonTizen::OnTimeout() {
+ LOG(INFO) << "[Passkey] Timeout";
+ RenderFrameHostImpl* const render_frame_host_impl =
+ static_cast<RenderFrameHostImpl*>(this->GetRenderFrameHost());
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE, base::BindOnce(&RenderFrameHostImpl::UpdateWAuthnResult,
+ base::Unretained(render_frame_host_impl),
+ WAUTHN_ERROR_TIMED_OUT));
+
if (!req_state_->request_delegate) {
// If no UI has been shown yet (likely because we timed out waiting for RP
// ID validation) then simply cancel the request.
blink::mojom::MakeCredentialAuthenticatorResponsePtr response,
blink::mojom::WebAuthnDOMExceptionDetailsPtr dom_exception_details,
Focus check_focus) {
+ LOG(INFO) << "[Passkey] CompleteMakeCredentialRequest, status : "
+ << (int)status << ", check_focus : " << (int)check_focus;
DCHECK(absl::holds_alternative<MakeCredentialCallback>(
req_state_->response_callback) &&
absl::get<MakeCredentialCallback>(req_state_->response_callback));
if (check_focus != Focus::kDontCheck &&
!(req_state_->request_delegate && IsFocused())) {
+ LOG(INFO) << "NOT_FOCUSED, response with nullptr";
std::move(make_credential_response_callback)
.Run(blink::mojom::AuthenticatorStatus::NOT_FOCUSED, nullptr, nullptr);
} else {
+ LOG(INFO) << "FOCUSED, response with detailed info";
std::move(make_credential_response_callback)
.Run(status, std::move(response), std::move(dom_exception_details));
}
#include <EWebKit_product.h>
#include <Elementary.h>
#include <assert.h>
+#include <fstream>
#include <vector>
#endif
#endif
+#if defined(TIZEN_PASSKEY_SUPPORT)
+#include "tizen_src/ewk/efl_integration/common/content_switches_efl.h"
+#endif
+
// Parses tizen version string (2.4 | 2.3.1 | 3.0 etc).
// Output std::vector where
// std::vector[0] = major,
&Window::DisplayQRCode, this);
evas_object_smart_callback_add(web_view_, "webauthn,response",
&Window::CloseQRCode, this);
+ evas_object_smart_callback_add(web_view_, "webauth,display,dialog",
+ &Window::DisplayWAuthnDiaglog, this);
+ evas_object_smart_callback_add(web_view_, "webauth,update,linked,data",
+ &Window::SaveLinkedData, this);
+ evas_object_smart_callback_add(web_view_, "webauth,update,result",
+ &Window::GetWAuthnResult, this);
#endif // defined(TIZEN_PASSKEY_SUPPORT)
#if BUILDFLAG(IS_TIZEN)
}
void Window::CloseQRCode(void* data, Evas_Object*, void*) {
+ log_trace("%s", __PRETTY_FUNCTION__);
Window* thiz = static_cast<Window*>(data);
evas_object_del(thiz->qr_img_);
evas_object_del(thiz->qr_window_);
}
void Window::CancelAuthentication(void* data, Evas_Object*, void*) {
+ log_trace("%s", __PRETTY_FUNCTION__);
Window* thiz = static_cast<Window*>(data);
ewk_view_webauthn_cancel(thiz->web_view_);
evas_object_del(thiz->qr_img_);
evas_object_del(thiz->qr_window_);
evas_object_del(thiz->layout_);
+ evas_object_del(thiz->diag_window_);
thiz->qr_img_ = NULL;
thiz->qr_window_ = NULL;
thiz->layout_ = NULL;
+ thiz->diag_window_ = NULL;
}
+
+void Window::DisplayWAuthnDiaglog(void* data, Evas_Object*, void* contents) {
+ log_trace("%s", __PRETTY_FUNCTION__);
+
+ Window* thiz = static_cast<Window*>(data);
+ thiz->layout_ = elm_layout_add(thiz->window_);
+
+ if (!thiz->layout_) {
+ log_info("no layout!");
+ return;
+ }
+
+ elm_layout_theme_set(thiz->layout_, "layout", "application", "default");
+ evas_object_size_hint_weight_set(thiz->layout_, EVAS_HINT_EXPAND,
+ EVAS_HINT_EXPAND);
+ evas_object_show(thiz->layout_);
+
+ thiz->diag_window_ = elm_popup_add(thiz->layout_);
+ if (!thiz->diag_window_) {
+ return;
+ }
+
+ evas_object_move(thiz->diag_window_, 350, 300);
+ evas_object_resize(thiz->diag_window_, 600, 600);
+ evas_object_show(thiz->diag_window_);
+
+ /* Cancel Button */
+ Evas_Object* cancel_btn = elm_button_add(thiz->diag_window_);
+ elm_object_text_set(cancel_btn, "Cancel");
+ elm_object_style_set(cancel_btn, "bottom");
+ evas_object_resize(cancel_btn, 100, 30);
+ evas_object_move(cancel_btn, 800, 150);
+ evas_object_show(cancel_btn);
+ elm_object_part_content_set(thiz->layout_, "button1", cancel_btn);
+ evas_object_smart_callback_add(cancel_btn, "clicked", CancelAuthentication,
+ thiz);
+
+ /* Show QR code Button */
+ Evas_Object* show_qr_btn = elm_button_add(thiz->diag_window_);
+ elm_object_text_set(show_qr_btn, "QR code");
+ elm_object_style_set(show_qr_btn, "bottom");
+ evas_object_resize(show_qr_btn, 100, 30);
+ evas_object_move(show_qr_btn, 800, 230);
+ evas_object_show(show_qr_btn);
+ elm_object_part_content_set(thiz->layout_, "button2", show_qr_btn);
+ evas_object_smart_callback_add(show_qr_btn, "clicked", Window::GetQRCode,
+ thiz);
+
+ /* Show Linked Device Button */
+ Evas_Object* linked_device_btn = elm_button_add(thiz->diag_window_);
+ elm_object_text_set(linked_device_btn, "Device");
+ elm_object_style_set(linked_device_btn, "bottom");
+ evas_object_resize(linked_device_btn, 100, 30);
+ evas_object_move(linked_device_btn, 800, 310);
+ evas_object_show(linked_device_btn);
+ elm_object_part_content_set(thiz->layout_, "button3", linked_device_btn);
+ evas_object_smart_callback_add(linked_device_btn, "clicked", Window::SetLinkedDevice,
+ thiz);
+
+}
+
+void Window::GetQRCode(void* data, Evas_Object*, void*) {
+ log_trace("%s", __PRETTY_FUNCTION__);
+ Ewk_Wauthn_Method method;
+ method.showQRCode = true;
+ Window* thiz = static_cast<Window*>(data);
+ ewk_view_wauthn_method_set(thiz->web_view_, &method);
+ evas_object_del(thiz->diag_window_);
+ evas_object_del(thiz->layout_);
+ thiz->diag_window_ = NULL;
+ thiz->layout_ = NULL;
+}
+
+void Window::SetLinkedDevice(void* data, Evas_Object*, void*) {
+ log_trace("%s", __PRETTY_FUNCTION__);
+ Window* thiz = static_cast<Window*>(data);
+
+ Ewk_Wauthn_Const_Buffer contact_id;
+ Ewk_Wauthn_Const_Buffer link_id;
+ Ewk_Wauthn_Const_Buffer link_secret;
+ Ewk_Wauthn_Const_Buffer authenticator_pubkey;
+ Ewk_Wauthn_Const_Buffer authenticator_name;
+ Ewk_Wauthn_Const_Buffer signature;
+ Ewk_Wauthn_Const_Buffer tunnel_server_domain;
+ Ewk_Wauthn_Const_Buffer identity_key;
+
+ std::ifstream inFile("/tmp/device-webauthn.bin", std::ios::binary);
+ std::vector<unsigned char> contact_id_data;
+ std::vector<unsigned char> link_id_data;
+ std::vector<unsigned char> link_secret_data;
+ std::vector<unsigned char> authenticator_pubkey_data;
+ std::vector<unsigned char> authenticator_name_data;
+ std::vector<unsigned char> signature_data;
+ std::vector<unsigned char> tunnel_server_domain_data;
+ std::vector<unsigned char> identity_key_data;
+ if (inFile) {
+ log_trace("/tmp/device-webauthn.bin openned, to read data");
+
+ inFile.read(reinterpret_cast<char *>(&contact_id.size), sizeof(size_t));
+ log_trace("read contact_id.size : %d", contact_id.size);
+ contact_id_data.resize(contact_id.size);
+ inFile.read(reinterpret_cast<char *>(contact_id_data.data()), contact_id.size);
+ contact_id.data = contact_id_data.data();
+ log_trace("read contact_id finished");
+
+ inFile.read(reinterpret_cast<char *>(&link_id.size), sizeof(size_t));
+ log_trace("read link_id.size : %d", link_id.size);
+ link_id_data.resize(link_id.size);
+ inFile.read(reinterpret_cast<char *>(link_id_data.data()), link_id.size);
+ link_id.data = link_id_data.data();
+ log_trace("read link_id finished");
+
+ inFile.read(reinterpret_cast<char *>(&link_secret.size), sizeof(size_t));
+ log_trace("read link_secret.size : %d", link_secret.size);
+ link_secret_data.resize(link_secret.size);
+ inFile.read(reinterpret_cast<char *>(link_secret_data.data()), link_secret.size);
+ link_secret.data = link_secret_data.data();
+ log_trace("read link_secret finished");
+
+ inFile.read(reinterpret_cast<char *>(&authenticator_pubkey.size), sizeof(size_t));
+ log_trace("read authenticator_pubkey.size : %d", authenticator_pubkey.size);
+ authenticator_pubkey_data.resize(authenticator_pubkey.size);
+ inFile.read(reinterpret_cast<char *>(authenticator_pubkey_data.data()), authenticator_pubkey.size);
+ authenticator_pubkey.data = authenticator_pubkey_data.data();
+ log_trace("read authenticator_pubkey finished");
+
+ inFile.read(reinterpret_cast<char *>(&authenticator_name.size), sizeof(size_t));
+ log_trace("read authenticator_name.size : %d", authenticator_name.size);
+ authenticator_name_data.resize(authenticator_name.size);
+ inFile.read(reinterpret_cast<char *>(authenticator_name_data.data()), authenticator_name.size);
+ authenticator_name.data = authenticator_name_data.data();
+ log_trace("read authenticator_name finished");
+
+ inFile.read(reinterpret_cast<char *>(&signature.size), sizeof(size_t));
+ log_trace("read signature.size : %d", signature.size);
+ signature_data.resize(signature.size);
+ inFile.read(reinterpret_cast<char *>(signature_data.data()), signature.size);
+ signature.data = signature_data.data();
+ log_trace("read signature finished");
+
+ inFile.read(reinterpret_cast<char *>(&tunnel_server_domain.size), sizeof(size_t));
+ log_trace("read tunnel_server_domain.size : %d", tunnel_server_domain.size);
+ tunnel_server_domain_data.resize(tunnel_server_domain.size);
+ inFile.read(reinterpret_cast<char *>(tunnel_server_domain_data.data()), tunnel_server_domain.size);
+ tunnel_server_domain.data = tunnel_server_domain_data.data();
+ log_trace("read tunnel_server_domain finished");
+
+ inFile.read(reinterpret_cast<char *>(&identity_key.size), sizeof(size_t));
+ log_trace("read identity_key.size : %d", identity_key.size);
+ identity_key_data.resize(identity_key.size);
+ inFile.read(reinterpret_cast<char *>(identity_key_data.data()), identity_key.size);
+ identity_key.data = identity_key_data.data();
+ log_trace("read identity_key finished");
+ } else {
+ log_trace("/tmp/device-webauthn.bin open failed, cancel operation");
+ Window::CancelAuthentication(data, NULL, NULL);
+ return;
+ }
+
+ Ewk_Wauthn_Hybrid_Linked_Data linkData;
+ linkData.contact_id = &contact_id;
+ linkData.link_id = &link_id;
+ linkData.link_secret = &link_secret;
+ linkData.authenticator_pubkey = &authenticator_pubkey;
+ linkData.authenticator_name = &authenticator_name;
+ linkData.signature = &signature;
+ linkData.tunnel_server_domain = &tunnel_server_domain;
+ linkData.tunnel_server_domain = &tunnel_server_domain;
+ linkData.identity_key = &identity_key;
+
+ Ewk_Wauthn_Method method;
+ method.showQRCode = false;
+ method.linkDevice = &linkData;
+
+ ewk_view_wauthn_method_set(thiz->web_view_, &method);
+ evas_object_del(thiz->diag_window_);
+ evas_object_del(thiz->layout_);
+ thiz->diag_window_ = NULL;
+ thiz->layout_ = NULL;
+}
+
+void Window::SaveLinkedData(void* data, Evas_Object*, void* LinkedDevice) {
+ log_trace("%s", __PRETTY_FUNCTION__);
+ Window* thiz = static_cast<Window*>(data);
+ Ewk_Wauthn_Hybrid_Linked_Data *deviceInfo = (Ewk_Wauthn_Hybrid_Linked_Data *)LinkedDevice;
+
+ std::ofstream outFile("/tmp/device-webauthn.bin", std::ios::binary);
+ if (outFile) {
+ outFile.write(reinterpret_cast<const char*>(&deviceInfo->contact_id->size), sizeof(size_t));
+ outFile.write(reinterpret_cast<const char*>(deviceInfo->contact_id->data), deviceInfo->contact_id->size);
+
+ outFile.write(reinterpret_cast<const char*>(&deviceInfo->link_id->size), sizeof(size_t));
+ outFile.write(reinterpret_cast<const char*>(deviceInfo->link_id->data), deviceInfo->link_id->size);
+
+ outFile.write(reinterpret_cast<const char*>(&deviceInfo->link_secret->size), sizeof(size_t));
+ outFile.write(reinterpret_cast<const char*>(deviceInfo->link_secret->data), deviceInfo->link_secret->size);
+
+ outFile.write(reinterpret_cast<const char*>(&deviceInfo->authenticator_pubkey->size), sizeof(size_t));
+ outFile.write(reinterpret_cast<const char*>(deviceInfo->authenticator_pubkey->data), deviceInfo->authenticator_pubkey->size);
+
+ outFile.write(reinterpret_cast<const char*>(&deviceInfo->authenticator_name->size), sizeof(size_t));
+ outFile.write(reinterpret_cast<const char*>(deviceInfo->authenticator_name->data), deviceInfo->authenticator_name->size);
+
+ outFile.write(reinterpret_cast<const char*>(&deviceInfo->signature->size), sizeof(size_t));
+ outFile.write(reinterpret_cast<const char*>(deviceInfo->signature->data), deviceInfo->signature->size);
+
+ outFile.write(reinterpret_cast<const char*>(&deviceInfo->tunnel_server_domain->size), sizeof(size_t));
+ outFile.write(reinterpret_cast<const char*>(deviceInfo->tunnel_server_domain->data), deviceInfo->tunnel_server_domain->size);
+
+ outFile.write(reinterpret_cast<const char*>(&deviceInfo->identity_key->size), sizeof(size_t));
+ outFile.write(reinterpret_cast<const char*>(deviceInfo->identity_key->data), deviceInfo->identity_key->size);
+ } else {
+ log_trace("/tmp/device-webauthn.txt open failed.");
+ }
+
+ return;
+}
+
+void Window::GetWAuthnResult(void* data, Evas_Object*, void* result) {
+ log_trace("%s, result : %d", __PRETTY_FUNCTION__,
+ *((Ewk_Wauthn_Error_E *)result));
+}
+
#endif // defined(TIZEN_PASSKEY_SUPPORT)
void Window::OnUserFormRepostDecisionTaken(bool decision, void* data) {