diff --git a/patches/content-browser-webauth-authenticator_impl_unittest.cc.patch b/patches/content-browser-webauth-authenticator_impl_unittest.cc.patch new file mode 100644 index 000000000000..37f83f3535f0 --- /dev/null +++ b/patches/content-browser-webauth-authenticator_impl_unittest.cc.patch @@ -0,0 +1,31 @@ +diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc +index dca681a3f79ff33f163957da42def9ddca3d8175..2e9e103e8cea8d9cda259d27649a2c441e4437e4 100644 +--- a/content/browser/webauth/authenticator_impl_unittest.cc ++++ b/content/browser/webauth/authenticator_impl_unittest.cc +@@ -63,6 +63,7 @@ + #include "content/browser/webauth/client_data_json.h" + #include "content/browser/webauth/virtual_authenticator.h" + #include "content/browser/webauth/virtual_authenticator_manager_impl.h" ++#include "content/browser/webauth/webauth_request_security_checker.h" + #include "content/public/browser/authenticator_request_client_delegate.h" + #include "content/public/browser/content_browser_client.h" + #include "content/public/browser/render_frame_host.h" +@@ -616,6 +617,9 @@ class AuthenticatorTestBase : public RenderViewHostTestHarness { + void SetUp() override { + RenderViewHostTestHarness::SetUp(); + ++ WebAuthRequestSecurityChecker::UseSystemSharedURLLoaderFactoryForTesting() = ++ true; ++ + mojo::SetDefaultProcessErrorHandler(base::BindRepeating( + &AuthenticatorTestBase::OnMojoError, base::Unretained(this))); + +@@ -641,6 +645,8 @@ class AuthenticatorTestBase : public RenderViewHostTestHarness { + + void TearDown() override { + RenderViewHostTestHarness::TearDown(); ++ WebAuthRequestSecurityChecker::UseSystemSharedURLLoaderFactoryForTesting() = ++ false; + + mojo::SetDefaultProcessErrorHandler(base::NullCallback()); + diff --git a/patches/content-browser-webauth-webauth_browsertest.cc.patch b/patches/content-browser-webauth-webauth_browsertest.cc.patch new file mode 100644 index 000000000000..236679850f91 --- /dev/null +++ b/patches/content-browser-webauth-webauth_browsertest.cc.patch @@ -0,0 +1,91 @@ +diff --git a/content/browser/webauth/webauth_browsertest.cc b/content/browser/webauth/webauth_browsertest.cc +index 0ebb28807bfd6b9fc543db8d829700213c3fa581..be781a5818b855df4893d8476f63e25866788b69 100644 +--- a/content/browser/webauth/webauth_browsertest.cc ++++ b/content/browser/webauth/webauth_browsertest.cc +@@ -40,6 +40,7 @@ + #include "content/browser/renderer_host/render_frame_host_impl.h" + #include "content/browser/webauth/authenticator_environment.h" + #include "content/browser/webauth/authenticator_impl.h" ++#include "content/browser/webauth/webauth_request_security_checker.h" + #include "content/public/browser/authenticator_request_client_delegate.h" + #include "content/public/browser/navigation_handle.h" + #include "content/public/browser/navigation_throttle.h" +@@ -179,6 +180,11 @@ constexpr char kRpIdNoEntryMessage[] = + ".well-known/webauthn resource of the claimed RP ID was " + "successful, but no listed origin matched the caller."; + ++constexpr char kRpIdFetchFailedMessage[] = ++ "SecurityError: The relying party ID is not a registrable domain suffix " ++ "of, nor equal to the current domain. Subsequently, an attempt to fetch " ++ "the .well-known/webauthn resource of the claimed RP ID failed."; ++ + constexpr char kMaxLargeBlobMessage[] = + "NotSupportedError: The 'largeBlob' extension's 'write' parameter exceeds " + "the maximum allowed size (2kb)"; +@@ -1810,6 +1816,8 @@ IN_PROC_BROWSER_TEST_F(WebAuthCrossDomainTest, Create) { + parameters.rp_id = "foo.com"; + test_client()->set_webauthn_origins_response( + "application/json", GetHttpsURL("www.acme.com", "/").spec()); ++ WebAuthRequestSecurityChecker::UseSystemSharedURLLoaderFactoryForTesting() = ++ true; + std::string result = EvalJs(shell()->web_contents()->GetPrimaryMainFrame(), + BuildCreateCallWithParameters(parameters)) + .ExtractString(); +@@ -1817,11 +1825,30 @@ IN_PROC_BROWSER_TEST_F(WebAuthCrossDomainTest, Create) { + EXPECT_EQ(kOkMessage, result); + } + ++IN_PROC_BROWSER_TEST_F(WebAuthCrossDomainTest, CreateFetchFailed) { ++ CreateParameters parameters; ++ parameters.rp_id = "foo.com"; ++ // Set up the system URL loader factory to respond to requests, but do not ++ // force its use. This will result in the browser context-specific URL ++ // loader factory being used, which will fail to handle the request. ++ test_client()->set_webauthn_origins_response( ++ "application/json", GetHttpsURL("www.acme.com", "/").spec()); ++ WebAuthRequestSecurityChecker::UseSystemSharedURLLoaderFactoryForTesting() = ++ false; ++ std::string result = EvalJs(shell()->web_contents()->GetPrimaryMainFrame(), ++ BuildCreateCallWithParameters(parameters)) ++ .ExtractString(); ++ ++ EXPECT_EQ(kRpIdFetchFailedMessage, result); ++} ++ + IN_PROC_BROWSER_TEST_F(WebAuthCrossDomainTest, CreateBadContentType) { + CreateParameters parameters; + parameters.rp_id = "foo.com"; + test_client()->set_webauthn_origins_response( + "text/plain", GetHttpsURL("www.acme.com", "/").spec()); ++ WebAuthRequestSecurityChecker::UseSystemSharedURLLoaderFactoryForTesting() = ++ true; + std::string result = EvalJs(shell()->web_contents()->GetPrimaryMainFrame(), + BuildCreateCallWithParameters(parameters)) + .ExtractString(); +@@ -1834,6 +1861,8 @@ IN_PROC_BROWSER_TEST_F(WebAuthCrossDomainTest, CreateBadOrigin) { + parameters.rp_id = "foo.com"; + test_client()->set_webauthn_origins_response("application/json", + "https://nottherightdomain.com"); ++ WebAuthRequestSecurityChecker::UseSystemSharedURLLoaderFactoryForTesting() = ++ true; + std::string result = EvalJs(shell()->web_contents()->GetPrimaryMainFrame(), + BuildCreateCallWithParameters(parameters)) + .ExtractString(); +@@ -1847,6 +1876,8 @@ IN_PROC_BROWSER_TEST_F(WebAuthCrossDomainTest, Timeout) { + parameters.rp_id = "foo.com"; + parameters.timeout = kShortTimeout; + test_client()->sinkhole_webauthn_origins_requests(); ++ WebAuthRequestSecurityChecker::UseSystemSharedURLLoaderFactoryForTesting() = ++ true; + std::string result = EvalJs(shell()->web_contents()->GetPrimaryMainFrame(), + BuildCreateCallWithParameters(parameters)) + .ExtractString(); +@@ -1867,6 +1898,8 @@ IN_PROC_BROWSER_TEST_F(WebAuthCrossDomainTest, Get) { + parameters.rp_id = "foo.com"; + test_client()->set_webauthn_origins_response( + "application/json", GetHttpsURL("www.acme.com", "/").spec()); ++ WebAuthRequestSecurityChecker::UseSystemSharedURLLoaderFactoryForTesting() = ++ true; + std::string result = EvalJs(shell()->web_contents()->GetPrimaryMainFrame(), + BuildGetCallWithParameters(parameters)) + .ExtractString(); diff --git a/patches/content-browser-webauth-webauth_request_security_checker.cc.patch b/patches/content-browser-webauth-webauth_request_security_checker.cc.patch new file mode 100644 index 000000000000..980160a8d0ec --- /dev/null +++ b/patches/content-browser-webauth-webauth_request_security_checker.cc.patch @@ -0,0 +1,89 @@ +diff --git a/content/browser/webauth/webauth_request_security_checker.cc b/content/browser/webauth/webauth_request_security_checker.cc +index befcc5fe79e376ad4a24d1762bf151138689d418..7303eaffd9302d94484407359102d77e76c6252c 100644 +--- a/content/browser/webauth/webauth_request_security_checker.cc ++++ b/content/browser/webauth/webauth_request_security_checker.cc +@@ -10,8 +10,10 @@ + #include "base/metrics/histogram_macros.h" + #include "base/strings/string_number_conversions.h" + #include "content/browser/bad_message.h" ++#include "content/public/browser/browser_context.h" + #include "content/public/browser/content_browser_client.h" + #include "content/public/browser/render_frame_host.h" ++#include "content/public/browser/storage_partition.h" + #include "content/public/browser/web_authentication_delegate.h" + #include "content/public/browser/webauthn_security_utils.h" + #include "content/public/common/content_client.h" +@@ -84,7 +86,14 @@ std::unique_ptr + WebAuthRequestSecurityChecker::RemoteValidation::Create( + const url::Origin& caller_origin, + const std::string& relying_party_id, ++ scoped_refptr url_loader_factory, + base::OnceCallback callback) { ++ if (!url_loader_factory) { ++ std::move(callback).Run( ++ blink::mojom::AuthenticatorStatus::BAD_RELYING_PARTY_ID); ++ return nullptr; ++ } ++ + // The relying party may allow other origins to use its RP ID based on the + // contents of a .well-known file. + std::string canonicalized_domain_storage; +@@ -112,14 +121,6 @@ WebAuthRequestSecurityChecker::RemoteValidation::Create( + replace_host.SetHostStr(canonicalized_domain); + well_known_url = well_known_url.ReplaceComponents(replace_host); + +- scoped_refptr url_loader_factory = +- GetContentClient()->browser()->GetSystemSharedURLLoaderFactory(); +- if (!url_loader_factory) { +- std::move(callback).Run( +- blink::mojom::AuthenticatorStatus::BAD_RELYING_PARTY_ID); +- return nullptr; +- } +- + auto network_request = std::make_unique(); + network_request->url = well_known_url; + +@@ -256,8 +257,9 @@ bool WebAuthRequestSecurityChecker::IsSameOriginWithAncestors( + const url::Origin& origin) { + RenderFrameHost* parent = render_frame_host_->GetParentOrOuterDocument(); + while (parent) { +- if (!parent->GetLastCommittedOrigin().IsSameOriginWith(origin)) ++ if (!parent->GetLastCommittedOrigin().IsSameOriginWith(origin)) { + return false; ++ } + parent = parent->GetParentOrOuterDocument(); + } + return true; +@@ -376,8 +378,19 @@ WebAuthRequestSecurityChecker::ValidateDomainAndRelyingPartyID( + return nullptr; + } + ++ scoped_refptr url_loader_factory; ++ if (!WebAuthRequestSecurityChecker:: ++ UseSystemSharedURLLoaderFactoryForTesting()) { ++ url_loader_factory = render_frame_host_->GetStoragePartition() ++ ->GetURLLoaderFactoryForBrowserProcess(); ++ } ++ if (!url_loader_factory) { ++ url_loader_factory = ++ GetContentClient()->browser()->GetSystemSharedURLLoaderFactory(); ++ } ++ + return RemoteValidation::Create(caller_origin, relying_party_id, +- std::move(callback)); ++ url_loader_factory, std::move(callback)); + } + + blink::mojom::AuthenticatorStatus +@@ -515,4 +528,11 @@ bool WebAuthRequestSecurityChecker:: + return true; + } + ++// static ++bool& WebAuthRequestSecurityChecker:: ++ UseSystemSharedURLLoaderFactoryForTesting() { ++ static bool value = false; ++ return value; ++} ++ + } // namespace content diff --git a/patches/content-browser-webauth-webauth_request_security_checker.h.patch b/patches/content-browser-webauth-webauth_request_security_checker.h.patch new file mode 100644 index 000000000000..46e1a0225f7c --- /dev/null +++ b/patches/content-browser-webauth-webauth_request_security_checker.h.patch @@ -0,0 +1,32 @@ +diff --git a/content/browser/webauth/webauth_request_security_checker.h b/content/browser/webauth/webauth_request_security_checker.h +index 017f2e28a100b911cf8aa321b2395adf14925420..dedfbda18c9c5209e1d5d2a0eddbf906ecf44f9e 100644 +--- a/content/browser/webauth/webauth_request_security_checker.h ++++ b/content/browser/webauth/webauth_request_security_checker.h +@@ -23,7 +23,8 @@ class Value; + + namespace network { + class SimpleURLLoader; +-} ++class SharedURLLoaderFactory; ++} // namespace network + + namespace content { + +@@ -60,6 +61,8 @@ class CONTENT_EXPORT WebAuthRequestSecurityChecker + static std::unique_ptr Create( + const url::Origin& caller_origin, + const std::string& relying_party_id, ++ scoped_refptr ++ shared_url_loader_factory, + base::OnceCallback callback); + + // ValidateWellKnownJSON implements the core of remote validation. It isn't +@@ -154,6 +157,8 @@ class CONTENT_EXPORT WebAuthRequestSecurityChecker + [[nodiscard]] bool DeduplicateCredentialDescriptorListAndValidateLength( + std::vector* list); + ++ static bool& UseSystemSharedURLLoaderFactoryForTesting(); ++ + protected: + friend class base::RefCounted; + virtual ~WebAuthRequestSecurityChecker();