Commit message: None
CVE: CVE-2018-6143
CWE: CWE-125
Vulnerability description: Insufficient validation in V8 in Google Chrome prior to 67.0.3396.62 allowed a remote attacker to perform an out of bounds memory read via a crafted HTML page.

Project: Chrome

  void CreatePublicKeyCredentialWithUnsupportedAlgorithmAndExpectNotSupported(
      content::WebContents* web_contents) {
    std::string result;
    std::string script =
        "navigator.credentials.create({ publicKey: {"
        "  challenge: new TextEncoder().encode('climb a mountain'),"
        "  rp: { id: '1098237235409872', name: 'Acme' },"
        "  user: { "
        "    id: new TextEncoder().encode('1098237235409872'),"
        "    name: 'avery.a.jones@example.com',"
        "    displayName: 'Avery A. Jones', "
        "    icon: 'https://pics.acme.com/00/p/aBjjjpqPb.png'},"
        "  pubKeyCredParams: [{ type: 'public-key', alg: '123'}],"
        "  timeout: 60000,"
        "  excludeList: [] }"
        "}).catch(c => window.domAutomationController.send(c.toString()));";
    ASSERT_TRUE(
        content::ExecuteScriptAndExtractString(web_contents, script, &result));
    ASSERT_EQ(
        "NotSupportedError: Parameters for this operation are not supported.",
        result);
  }

Project: Chrome

  CredentialManagerBrowserTest() {
    scoped_feature_list_.InitAndEnableFeature(features::kWebAuth);
  }

Project: Chrome

  void NavigateToURL(const net::EmbeddedTestServer& test_server,
                     const std::string& hostname,
                     const std::string& relative_url) {
    NavigationObserver observer(WebContents());
    GURL url = test_server.GetURL(hostname, relative_url);
    ui_test_utils::NavigateToURL(browser(), url);
    observer.Wait();
  }

Project: Chrome

  void ScheduleNavigatorStoreCredentialAtUnload(
      content::WebContents* web_contents,
      const char* username,
      const char* password) {
    ASSERT_TRUE(content::ExecuteScript(
        web_contents,
        base::StringPrintf(
            "window.addEventListener(\"unload\", () => {"
            "  var c = new PasswordCredential({ id: '%s', password: '%s' });"
            "  navigator.credentials.store(c);"
            "});",
            username, password)));
  }

Project: Chrome

  void TestStoreInUnloadHandlerForSameSiteNavigation(
      bool preestablish_mojo_pipe) {
    const GURL a_url1 = https_test_server().GetURL("foo.a.com", "/title1.html");
    const GURL a_url2 = https_test_server().GetURL("bar.a.com", "/title2.html");

    ui_test_utils::NavigateToURL(browser(), a_url1);

    ChromePasswordManagerClient* client =
        ChromePasswordManagerClient::FromWebContents(WebContents());

    EXPECT_FALSE(client->has_binding_for_credential_manager());
    if (preestablish_mojo_pipe) {
      ASSERT_NO_FATAL_FAILURE(
          TriggerNavigatorGetPasswordCredentialsAndExpectHasResult(
              WebContents(), false));
      EXPECT_TRUE(client->has_binding_for_credential_manager());
    }

    ASSERT_NO_FATAL_FAILURE(ScheduleNavigatorStoreCredentialAtUnload(
        WebContents(), "user", "hunter2"));

    content::RenderFrameHost* old_rfh = WebContents()->GetMainFrame();
    ui_test_utils::NavigateToURL(browser(), a_url2);
    ASSERT_EQ(old_rfh, WebContents()->GetMainFrame());

    EXPECT_FALSE(client->has_binding_for_credential_manager());

    if (!client->was_store_ever_called())
      return;

    BubbleObserver prompt_observer(WebContents());
    prompt_observer.WaitForAutomaticSavePrompt();
    ASSERT_TRUE(prompt_observer.IsSavePromptShownAutomatically());
    prompt_observer.AcceptSavePrompt();

    WaitForPasswordStore();

    password_manager::TestPasswordStore* test_password_store =
        static_cast<password_manager::TestPasswordStore*>(
            PasswordStoreFactory::GetForProfile(
                browser()->profile(), ServiceAccessType::IMPLICIT_ACCESS)
                .get());

    ASSERT_EQ(1u, test_password_store->stored_passwords().size());
    autofill::PasswordForm signin_form =
        test_password_store->stored_passwords().begin()->second[0];
    EXPECT_EQ(base::ASCIIToUTF16("user"), signin_form.username_value);
    EXPECT_EQ(base::ASCIIToUTF16("hunter2"), signin_form.password_value);
    EXPECT_EQ(a_url1.GetOrigin(), signin_form.origin);
  }

Project: Chrome

  void TriggerNavigatorGetPasswordCredentialsAndExpectHasResult(
      content::WebContents* web_contents,
      bool expect_has_results) {
    bool result = false;
    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
        web_contents,
        "navigator.credentials.get({password: true}).then(c => {"
        "  window.domAutomationController.send(!!c);"
        "});",
        &result));
    ASSERT_EQ(expect_has_results, result);
  }

Project: Chrome

CredentialManagerImpl::CredentialManagerImpl(PasswordManagerClient* client)
    : client_(client) {
  auto_signin_enabled_.Init(prefs::kCredentialsEnableAutosignin,
                            client_->GetPrefs());
}

Project: Chrome

void CredentialManagerImpl::DoneRequiringUserMediation() {
  DCHECK(pending_require_user_mediation_);
  pending_require_user_mediation_.reset();
}

Project: Chrome

void CredentialManagerImpl::Get(CredentialMediationRequirement mediation,
                                bool include_passwords,
                                const std::vector<GURL>& federations,
                                GetCallback callback) {
  using metrics_util::LogCredentialManagerGetResult;

  PasswordStore* store = GetPasswordStore();
  if (password_manager_util::IsLoggingActive(client_)) {
    CredentialManagerLogger(client_->GetLogManager())
        .LogRequestCredential(GetLastCommittedURL(), mediation, federations);
  }
  if (pending_request_ || !store) {
    std::move(callback).Run(
        pending_request_ ? CredentialManagerError::PENDING_REQUEST
                         : CredentialManagerError::PASSWORDSTOREUNAVAILABLE,
        base::nullopt);
    LogCredentialManagerGetResult(metrics_util::CREDENTIAL_MANAGER_GET_REJECTED,
                                  mediation);
    return;
  }

  if (!client_->IsFillingEnabledForCurrentPage() ||
      !client_->OnCredentialManagerUsed()) {
    std::move(callback).Run(CredentialManagerError::SUCCESS, CredentialInfo());
    LogCredentialManagerGetResult(metrics_util::CREDENTIAL_MANAGER_GET_NONE,
                                  mediation);
    return;
  }
  if (mediation == CredentialMediationRequirement::kSilent &&
      !IsZeroClickAllowed()) {
    std::move(callback).Run(CredentialManagerError::SUCCESS, CredentialInfo());
    LogCredentialManagerGetResult(
        metrics_util::CREDENTIAL_MANAGER_GET_NONE_ZERO_CLICK_OFF, mediation);
    return;
  }

  pending_request_.reset(new CredentialManagerPendingRequestTask(
      this, base::Bind(&RunGetCallback, base::Passed(&callback)), mediation,
      include_passwords, federations));
  GetPasswordStore()->GetLogins(GetSynthesizedFormForOrigin(),
                                pending_request_.get());
}

Project: Chrome

GURL CredentialManagerImpl::GetLastCommittedURL() const {
  return client_->GetLastCommittedEntryURL();
}

Project: Chrome

GURL CredentialManagerImpl::GetOrigin() const {
  return GetLastCommittedURL().GetOrigin();
}

Project: Chrome

PasswordStore::FormDigest CredentialManagerImpl::GetSynthesizedFormForOrigin()
    const {
  PasswordStore::FormDigest digest = {autofill::PasswordForm::SCHEME_HTML,
                                      std::string(),
                                      GetLastCommittedURL().GetOrigin()};
  digest.signon_realm = digest.origin.spec();
  return digest;
}

Project: Chrome

bool CredentialManagerImpl::IsZeroClickAllowed() const {
  return *auto_signin_enabled_ && !client_->IsIncognito();
}

Project: Chrome

void CredentialManagerImpl::PreventSilentAccess(
    PreventSilentAccessCallback callback) {
  if (password_manager_util::IsLoggingActive(client_)) {
    CredentialManagerLogger(client_->GetLogManager())
        .LogPreventSilentAccess(GetLastCommittedURL());
  }
  std::move(callback).Run();

  PasswordStore* store = GetPasswordStore();
  if (!store || !client_->IsSavingAndFillingEnabledForCurrentPage() ||
      !client_->OnCredentialManagerUsed())
    return;

  if (!pending_require_user_mediation_) {
    pending_require_user_mediation_.reset(
        new CredentialManagerPendingPreventSilentAccessTask(this));
  }
  pending_require_user_mediation_->AddOrigin(GetSynthesizedFormForOrigin());
}

Project: Chrome

void RunGetCallback(GetCallback callback, const CredentialInfo& info) {
  std::move(callback).Run(CredentialManagerError::SUCCESS, info);
}

Project: Chrome

void CredentialManagerImpl::SendCredential(
    const SendCredentialCallback& send_callback,
    const CredentialInfo& info) {
  DCHECK(pending_request_);
  DCHECK(send_callback.Equals(pending_request_->send_callback()));

  if (password_manager_util::IsLoggingActive(client_)) {
    CredentialManagerLogger(client_->GetLogManager())
        .LogSendCredential(GetLastCommittedURL(), info.type);
  }
  send_callback.Run(info);
  pending_request_.reset();
}

Project: Chrome

void CredentialManagerImpl::SendPasswordForm(
    const SendCredentialCallback& send_callback,
    CredentialMediationRequirement mediation,
    const autofill::PasswordForm* form) {
  CredentialInfo info;
  if (form) {
    password_manager::CredentialType type_to_return =
        form->federation_origin.unique()
            ? CredentialType::CREDENTIAL_TYPE_PASSWORD
            : CredentialType::CREDENTIAL_TYPE_FEDERATED;
    info = CredentialInfo(*form, type_to_return);
    if (PasswordStore* store = GetPasswordStore()) {
      if (form->skip_zero_click && IsZeroClickAllowed()) {
        autofill::PasswordForm update_form = *form;
        update_form.skip_zero_click = false;
        store->UpdateLogin(update_form);
      }
    }
    base::RecordAction(
        base::UserMetricsAction("CredentialManager_AccountChooser_Accepted"));
    metrics_util::LogCredentialManagerGetResult(
        metrics_util::CREDENTIAL_MANAGER_GET_ACCOUNT_CHOOSER, mediation);
  } else {
    base::RecordAction(
        base::UserMetricsAction("CredentialManager_AccountChooser_Dismissed"));
    metrics_util::LogCredentialManagerGetResult(
        metrics_util::CREDENTIAL_MANAGER_GET_NONE, mediation);
  }
  SendCredential(send_callback, info);
}

Project: Chrome

void CredentialManagerImpl::Store(const CredentialInfo& credential,
                                  StoreCallback callback) {
  DCHECK_NE(CredentialType::CREDENTIAL_TYPE_EMPTY, credential.type);

  if (password_manager_util::IsLoggingActive(client_)) {
    CredentialManagerLogger(client_->GetLogManager())
        .LogStoreCredential(GetLastCommittedURL(), credential.type);
  }

  std::move(callback).Run();

  if (!client_->IsSavingAndFillingEnabledForCurrentPage() ||
      !client_->OnCredentialManagerUsed())
    return;

  client_->NotifyStorePasswordCalled();

  GURL origin = GetLastCommittedURL().GetOrigin();
  std::unique_ptr<autofill::PasswordForm> form(
      CreatePasswordFormFromCredentialInfo(credential, origin));

  std::unique_ptr<autofill::PasswordForm> observed_form =
      CreateObservedPasswordFormFromOrigin(origin);
  auto form_fetcher = std::make_unique<FormFetcherImpl>(
      PasswordStore::FormDigest(*observed_form), client_, false, false);
  form_manager_ = std::make_unique<CredentialManagerPasswordFormManager>(
      client_, *observed_form, std::move(form), this, nullptr,
      std::move(form_fetcher));
  form_manager_->Init(nullptr);
}

Project: Chrome

PasswordManagerClient* CredentialManagerImpl::client() const {
  return client_;
}

Project: Chrome

CredentialManagerImpl::~CredentialManagerImpl() {}