diff --git a/DEPS b/DEPS
index f8f432e..a16d2bc2 100644
--- a/DEPS
+++ b/DEPS
@@ -78,7 +78,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '79f728aa4918895beec52edf0ee12dc5fe51eec2',
+  'v8_revision': '9a1d0f9307ce99a8831f97da87cf7bbd98576731',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
diff --git a/android_webview/common/crash_reporter/crash_keys.cc b/android_webview/common/crash_reporter/crash_keys.cc
index f62d444..e8ee59497 100644
--- a/android_webview/common/crash_reporter/crash_keys.cc
+++ b/android_webview/common/crash_reporter/crash_keys.cc
@@ -55,13 +55,6 @@
       // sandbox/:
       {"seccomp-sigsys", kMediumSize},
 
-      // Site isolation.  These keys help debug renderer kills such as
-      // https://crbug.com/773140.
-      {"requested_site_url", kSmallSize},
-      {"requested_origin", kSmallSize},
-      {"killed_process_origin_lock", kSmallSize},
-      {"site_isolation_mode", kSmallSize},
-
       // Temporary for https://crbug.com/685996.
       {"user-cloud-policy-manager-connect-trace", kMediumSize},
 
diff --git a/chrome/app/chrome_crash_reporter_client_win.cc b/chrome/app/chrome_crash_reporter_client_win.cc
index c2b7b90..e6159d7 100644
--- a/chrome/app/chrome_crash_reporter_client_win.cc
+++ b/chrome/app/chrome_crash_reporter_client_win.cc
@@ -105,13 +105,6 @@
       // media/:
       {kZeroEncodeDetails, kSmallSize},
 
-      // Site isolation.  These keys help debug renderer kills such as
-      // https://crbug.com/773140.
-      {"requested_site_url", kSmallSize},
-      {"requested_origin", kSmallSize},
-      {"killed_process_origin_lock", kSmallSize},
-      {"site_isolation_mode", kSmallSize},
-
       // Temporary for https://crbug.com/685996.
       {"user-cloud-policy-manager-connect-trace", kMediumSize},
 
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index fb64a066..9161fa5 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -4232,6 +4232,18 @@
   <message name="IDS_AD_PASSWORD_CHANGE_PASSWORDS_MISMATCH_ERROR" desc="Error message in case new password fields does not match on the Active Directory password change dialog.">
     Passwords do not match.
   </message>
+  <message name="IDS_AD_MORE_OPTIONS_BUTTON" desc="Text on the 'More options' button on the Active Directory domain join screen.">
+    More options
+  </message>
+  <message name="IDS_AD_ORG_UNIT_HINT" desc="Hint for the Active Directory Organizational units input on the 'More options' dialog.">
+    Computer OU (e.g. OU=Chromebooks,DC=example,DC=com)
+  </message>
+  <message name="IDS_AD_CONFIRM_BUTTON" desc="Text on the 'Confirm' button on the 'More options' dialog.">
+    Confirm
+  </message>
+  <message name="IDS_AD_CANCEL_BUTTON" desc="Text on the 'Cancel' button on the 'More options' dialog.">
+    Cancel
+  </message>
   <message name="IDS_AD_DOMAIN_JOIN_UNKNOWN_ERROR" desc="Default error text on the Active Directory join screen">
     Oops!  Something went wrong when trying to join the domain. Please try again.
   </message>
@@ -4256,6 +4268,18 @@
   <message name="IDS_AD_USER_HIT_JOIN_QUOTA" desc="Alert message that user can't add more machines to the domain">
     Failed to join the machine to the domain. This might be due to exceeding the maximum number of allowed machine joins for your account on the server.
   </message>
+  <message name="IDS_AD_OU_DOES_NOT_EXIST" desc="Alert message that user joins the machine to non-existing organizational unit.">
+    Failed to join the machine to the domain. Organizational unit does not exist.
+  </message>
+  <message name="IDS_AD_OU_INVALID" desc="Alert message that user joins the machine to invalid organizational unit.">
+    Failed to join the machine to the domain. Organizational unit is invalid.
+  </message>
+  <message name="IDS_AD_OU_ACCESS_DENIED" desc="Alert message that user does not have rights to join the machine to specified organizational unit.">
+    Failed to join the machine to the domain. This might be due to insufficient privileges for your account for the organizational unit.
+  </message>
+  <message name="IDS_AD_OU_SETTING_FAILED" desc="Alert message that user could not join the machine to specified organizational unit due to unknown reason.">
+    Failed to join the machine to the domain. This might be due to issues with the organizational unit.
+  </message>
   <message name="IDS_AD_BOARD_NOT_SUPPORTED" desc="Alert message that the Chromebook model is not supported for Active Directory">
     Chrome <ph name="MS_AD_NAME">Microsoft® Active Directory®</ph> integration is only supported on x86_64 platforms. Chromebooks built on top of an ARM or x86 platform do not support this functionality.
   </message>
diff --git a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
index 429f0bf1..113b5c2 100644
--- a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
@@ -526,6 +526,7 @@
     if (utterance == "Click me")
       break;
   }
+  speech_monitor_.GetNextUtterance();
   EXPECT_EQ("Button", speech_monitor_.GetNextUtterance());
 
   // Press Search+/ to enter ChromeVox's "find in page".
diff --git a/chrome/browser/chromeos/login/active_directory_login_browsertest.cc b/chrome/browser/chromeos/login/active_directory_login_browsertest.cc
index 6a4975a..6e13bba2 100644
--- a/chrome/browser/chromeos/login/active_directory_login_browsertest.cc
+++ b/chrome/browser/chromeos/login/active_directory_login_browsertest.cc
@@ -50,6 +50,7 @@
 constexpr char kAdMachineName[] = "machine_name";
 constexpr char kTestActiveDirectoryUser[] = "test-user";
 constexpr char kAdMachineInput[] = "machineNameInput";
+constexpr char kAdMoreOptionsButton[] = "moreOptionsBtn";
 constexpr char kAdUserInput[] = "userInput";
 constexpr char kAdPasswordInput[] = "passwordInput";
 constexpr char kAdButton[] = "button";
@@ -66,18 +67,6 @@
 
 constexpr char kCloseButtonId[] = "closeButton";
 
-// Used for the callback from FakeAuthPolicy::JoinAdDomain.
-void OnJoinedDomain(base::OnceClosure closure, authpolicy::ErrorType error) {
-  EXPECT_EQ(authpolicy::ERROR_NONE, error);
-  std::move(closure).Run();
-}
-
-// Used for the callback from FakeAuthPolicy::RefreshDevicePolicy.
-void OnRefreshedPolicy(base::OnceClosure closure, authpolicy::ErrorType error) {
-  EXPECT_EQ(authpolicy::ERROR_NONE, error);
-  std::move(closure).Run();
-}
-
 class TestAuthPolicyClient : public FakeAuthPolicyClient {
  public:
   TestAuthPolicyClient() { FakeAuthPolicyClient::set_started(true); }
@@ -149,18 +138,29 @@
     AuthPolicyLoginHelper helper;
     {
       base::RunLoop loop;
-      helper.JoinAdDomain(kAdMachineName,
-                          kTestActiveDirectoryUser + ("@" + test_realm_),
-                          "" /* password */,
-                          base::BindOnce(&OnJoinedDomain, loop.QuitClosure()));
+      helper.JoinAdDomain(
+          kAdMachineName, "" /* distinguished_name */,
+          kTestActiveDirectoryUser + ("@" + test_realm_), "" /* password */,
+          base::BindOnce(
+              [](base::OnceClosure closure, const std::string& expected_domain,
+                 authpolicy::ErrorType error, const std::string& domain) {
+                EXPECT_EQ(authpolicy::ERROR_NONE, error);
+                EXPECT_EQ(expected_domain, domain);
+                std::move(closure).Run();
+              },
+              loop.QuitClosure(), test_realm_));
       loop.Run();
     }
     ASSERT_TRUE(AuthPolicyLoginHelper::LockDeviceActiveDirectoryForTesting(
         test_realm_));
     {
       base::RunLoop loop;
-      fake_auth_policy_client()->RefreshDevicePolicy(
-          base::BindOnce(&OnRefreshedPolicy, loop.QuitClosure()));
+      fake_auth_policy_client()->RefreshDevicePolicy(base::BindOnce(
+          [](base::OnceClosure closure, authpolicy::ErrorType error) {
+            EXPECT_EQ(authpolicy::ERROR_NONE, error);
+            std::move(closure).Run();
+          },
+          loop.QuitClosure()));
       loop.Run();
     }
   }
@@ -198,6 +198,7 @@
     // Checks if Active Directory signin is visible.
     JSExpect("!document.querySelector('#offline-ad-auth').hidden");
     JSExpect(JSElement(kAdOfflineAuthId, kAdMachineInput) + ".hidden");
+    JSExpect(JSElement(kAdOfflineAuthId, kAdMoreOptionsButton) + ".hidden");
     JSExpect("!" + JSElement(kAdOfflineAuthId, kAdUserInput) + ".hidden");
     JSExpect("!" + JSElement(kAdOfflineAuthId, kAdPasswordInput) + ".hidden");
 
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_screen.h b/chrome/browser/chromeos/login/enrollment/enrollment_screen.h
index 2470117..de64f640 100644
--- a/chrome/browser/chromeos/login/enrollment/enrollment_screen.h
+++ b/chrome/browser/chromeos/login/enrollment/enrollment_screen.h
@@ -104,6 +104,8 @@
   FRIEND_TEST_ALL_PREFIXES(EnterpriseEnrollmentTest,
                            TestActiveDirectoryEnrollment_Success);
   FRIEND_TEST_ALL_PREFIXES(EnterpriseEnrollmentTest,
+                           TestActiveDirectoryEnrollment_DistinguishedName);
+  FRIEND_TEST_ALL_PREFIXES(EnterpriseEnrollmentTest,
                            TestActiveDirectoryEnrollment_UIErrors);
   FRIEND_TEST_ALL_PREFIXES(HandsOffNetworkScreenTest, RequiresNoInput);
   FRIEND_TEST_ALL_PREFIXES(HandsOffNetworkScreenTest, ContinueClickedOnlyOnce);
diff --git a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
index 36102408..18c5955 100644
--- a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
+++ b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
@@ -28,15 +28,47 @@
 
 namespace {
 
-const char kAdMachineNameInput[] =
+constexpr char kAdMachineNameInput[] =
     "document.querySelector('#oauth-enroll-ad-join-ui /deep/ "
     "#machineNameInput')";
-const char kAdUsernameInput[] =
+constexpr char kAdMachineOrgUnitInput[] =
+    "document.querySelector('#oauth-enroll-ad-join-ui /deep/ "
+    "#orgUnitInput')";
+constexpr char kAdUsernameInput[] =
     "document.querySelector('#oauth-enroll-ad-join-ui /deep/ #userInput')";
-const char kAdPasswordInput[] =
+constexpr char kAdPasswordInput[] =
     "document.querySelector('#oauth-enroll-ad-join-ui /deep/ #passwordInput')";
-const char kAdTestRealm[] = "test_realm.com";
-const char kAdTestUser[] = "test_user@test_realm.com";
+constexpr char kAdUserDomain[] = "user.domain.com";
+constexpr char kAdMachineDomain[] = "machine.domain.com";
+constexpr char kAdMachineDomainDN[] =
+    "OU=leaf,OU=root,DC=machine,DC=domain,DC=com";
+constexpr const char* kAdOrganizationlUnit[] = {"leaf", "root"};
+constexpr char kAdTestUser[] = "test_user@user.domain.com";
+
+class MockAuthPolicyClient : public FakeAuthPolicyClient {
+ public:
+  MockAuthPolicyClient() = default;
+  ~MockAuthPolicyClient() override = default;
+  void JoinAdDomain(const authpolicy::JoinDomainRequest& request,
+                    int password_fd,
+                    JoinCallback callback) override {
+    if (expected_request_) {
+      ASSERT_EQ(expected_request_->SerializeAsString(),
+                request.SerializeAsString());
+      expected_request_.reset();
+    }
+    FakeAuthPolicyClient::JoinAdDomain(request, password_fd,
+                                       std::move(callback));
+  }
+
+  void set_expected_request(
+      std::unique_ptr<authpolicy::JoinDomainRequest> expected_request) {
+    expected_request_ = std::move(expected_request);
+  }
+
+ private:
+  std::unique_ptr<authpolicy::JoinDomainRequest> expected_request_;
+};
 
 }  // namespace
 
@@ -99,6 +131,7 @@
 
   // Submits Active Directory domain join credentials.
   void SubmitActiveDirectoryCredentials(const std::string& machine_name,
+                                        const std::string& machine_ou,
                                         const std::string& username,
                                         const std::string& password) {
     EXPECT_TRUE(IsStepDisplayed("ad-join"));
@@ -111,15 +144,34 @@
         std::string(kAdUsernameInput) + ".value = '" + username + "'";
     const std::string set_password =
         std::string(kAdPasswordInput) + ".value = '" + password + "'";
+    const std::string set_machine_ou =
+        std::string(kAdMachineOrgUnitInput) + ".value = '" + machine_ou + "'";
     js_checker().ExecuteAsync(set_machine_name);
     js_checker().ExecuteAsync(set_username);
     js_checker().ExecuteAsync(set_password);
+    js_checker().ExecuteAsync(set_machine_ou);
     js_checker().ExecuteAsync(
         "document.querySelector('#oauth-enroll-ad-join-ui /deep/ "
         "#button').fire('tap')");
     ExecutePendingJavaScript();
   }
 
+  void SetExpectedJoinRequest(const std::string& machine_name,
+                              const std::string& machine_domain,
+                              std::vector<std::string> organizational_unit,
+                              const std::string& username) {
+    auto request = std::make_unique<authpolicy::JoinDomainRequest>();
+    if (!machine_name.empty())
+      request->set_machine_name(machine_name);
+    if (!machine_domain.empty())
+      request->set_machine_domain(machine_domain);
+    for (std::string& it : organizational_unit)
+      request->add_machine_ou()->swap(it);
+    if (!username.empty())
+      request->set_user_principal_name(username);
+    mock_auth_policy_client()->set_expected_request(std::move(request));
+  }
+
   void DisableAttributePromptUpdate() {
     AddEnrollmentSetupFunction(
         [](EnterpriseEnrollmentHelperMock* enrollment_helper) {
@@ -149,22 +201,34 @@
   }
 
   // Forces the Active Directory domain join flow during enterprise enrollment.
-  void SetupActiveDirectoryJoin() {
+  void SetupActiveDirectoryJoin(const std::string& expected_domain) {
     AddEnrollmentSetupFunction(
-        [this](EnterpriseEnrollmentHelperMock* enrollment_helper) {
+        [this,
+         expected_domain](EnterpriseEnrollmentHelperMock* enrollment_helper) {
           // Causes the attribute-prompt flow to activate.
           EXPECT_CALL(*enrollment_helper,
                       EnrollUsingAuthCode("test_auth_code", _))
-              .WillOnce(InvokeWithoutArgs([this]() {
-                this->enrollment_screen()->JoinDomain(
-                    base::BindOnce([](const std::string& realm) {
-                      EXPECT_EQ(kAdTestRealm, realm);
-                    }));
+              .WillOnce(InvokeWithoutArgs([this, expected_domain]() {
+                this->enrollment_screen()->JoinDomain(base::BindOnce(
+                    [](const std::string& expected_domain,
+                       const std::string& domain) {
+                      ASSERT_EQ(expected_domain, domain);
+                    },
+                    expected_domain));
               }));
         });
-    static_cast<FakeAuthPolicyClient*>(
-        DBusThreadManager::Get()->GetAuthPolicyClient())
-        ->DisableOperationDelayForTesting();
+  }
+
+  void SetUp() override {
+    DBusThreadManager::GetSetterForTesting()->SetAuthPolicyClient(
+        std::make_unique<MockAuthPolicyClient>());
+    mock_auth_policy_client()->DisableOperationDelayForTesting();
+    LoginManagerTest::SetUp();
+  }
+
+  MockAuthPolicyClient* mock_auth_policy_client() {
+    return static_cast<MockAuthPolicyClient*>(
+        DBusThreadManager::Get()->GetAuthPolicyClient());
   }
 
   void SetupActiveDirectoryJSNotifications() {
@@ -328,7 +392,7 @@
                        TestActiveDirectoryEnrollment_Success) {
   ShowEnrollmentScreen();
   DisableAttributePromptUpdate();
-  SetupActiveDirectoryJoin();
+  SetupActiveDirectoryJoin(kAdUserDomain);
   SubmitEnrollmentCredentials();
 
   chromeos::DBusThreadManager::Get()
@@ -337,7 +401,43 @@
 
   content::DOMMessageQueue message_queue;
   SetupActiveDirectoryJSNotifications();
-  SubmitActiveDirectoryCredentials("machine_name", kAdTestUser, "password");
+  SetExpectedJoinRequest("machine_name", "", {}, kAdTestUser);
+  SubmitActiveDirectoryCredentials("machine_name", "", kAdTestUser, "password");
+  WaitForMessage(&message_queue, "\"ShowSpinnerScreen\"");
+  EXPECT_FALSE(IsStepDisplayed("ad-join"));
+
+  CompleteEnrollment();
+  // Verify that the success page is displayed.
+  EXPECT_TRUE(IsStepDisplayed("success"));
+  EXPECT_FALSE(IsStepDisplayed("error"));
+
+  // We have to remove the enrollment_helper before the dtor gets called.
+  enrollment_screen()->enrollment_helper_.reset();
+}
+
+// Verifies that the distinguished name specified on the Active Directory join
+// domain screen correctly parsed and passed into AuthPolicyClient.
+IN_PROC_BROWSER_TEST_F(EnterpriseEnrollmentTest,
+                       TestActiveDirectoryEnrollment_DistinguishedName) {
+  ShowEnrollmentScreen();
+  DisableAttributePromptUpdate();
+  SetupActiveDirectoryJoin(kAdMachineDomain);
+  SubmitEnrollmentCredentials();
+
+  chromeos::DBusThreadManager::Get()
+      ->GetUpstartClient()
+      ->StartAuthPolicyService();
+
+  content::DOMMessageQueue message_queue;
+  SetupActiveDirectoryJSNotifications();
+  SetExpectedJoinRequest(
+      "machine_name", kAdMachineDomain,
+      std::vector<std::string>(
+          kAdOrganizationlUnit,
+          kAdOrganizationlUnit + arraysize(kAdOrganizationlUnit)),
+      kAdTestUser);
+  SubmitActiveDirectoryCredentials("machine_name", kAdMachineDomainDN,
+                                   kAdTestUser, "password");
   WaitForMessage(&message_queue, "\"ShowSpinnerScreen\"");
   EXPECT_FALSE(IsStepDisplayed("ad-join"));
 
@@ -357,7 +457,7 @@
 IN_PROC_BROWSER_TEST_F(EnterpriseEnrollmentTest,
                        TestActiveDirectoryEnrollment_UIErrors) {
   ShowEnrollmentScreen();
-  SetupActiveDirectoryJoin();
+  SetupActiveDirectoryJoin(kAdUserDomain);
   SubmitEnrollmentCredentials();
 
   chromeos::DBusThreadManager::Get()
@@ -369,14 +469,15 @@
   // being checked in the UI. Machine name length is checked after that in the
   // authpolicyd.
   SetupActiveDirectoryJSNotifications();
-  SubmitActiveDirectoryCredentials("too_long_machine_name", kAdTestUser, "");
+  SubmitActiveDirectoryCredentials("too_long_machine_name", "", kAdTestUser,
+                                   "");
   EXPECT_TRUE(IsStepDisplayed("ad-join"));
   js_checker().ExpectFalse(std::string(kAdMachineNameInput) + ".isInvalid");
   js_checker().ExpectFalse(std::string(kAdUsernameInput) + ".isInvalid");
   js_checker().ExpectTrue(std::string(kAdPasswordInput) + ".isInvalid");
 
   // Checking error in case of too long machine name.
-  SubmitActiveDirectoryCredentials("too_long_machine_name", kAdTestUser,
+  SubmitActiveDirectoryCredentials("too_long_machine_name", "", kAdTestUser,
                                    "password");
   WaitForMessage(&message_queue, "\"ShowJoinDomainError\"");
   EXPECT_TRUE(IsStepDisplayed("ad-join"));
@@ -385,7 +486,7 @@
   js_checker().ExpectFalse(std::string(kAdPasswordInput) + ".isInvalid");
 
   // Checking error in case of bad username (without realm).
-  SubmitActiveDirectoryCredentials("machine_name", "test_user", "password");
+  SubmitActiveDirectoryCredentials("machine_name", "", "test_user", "password");
   WaitForMessage(&message_queue, "\"ShowJoinDomainError\"");
   EXPECT_TRUE(IsStepDisplayed("ad-join"));
   js_checker().ExpectFalse(std::string(kAdMachineNameInput) + ".isInvalid");
diff --git a/chrome/browser/resources/chromeos/chromevox/common/editable_text_base.js b/chrome/browser/resources/chromeos/chromevox/common/editable_text_base.js
index f148885..a8b44c8f 100644
--- a/chrome/browser/resources/chromeos/chromevox/common/editable_text_base.js
+++ b/chrome/browser/resources/chromeos/chromevox/common/editable_text_base.js
@@ -36,7 +36,16 @@
  * @param {boolean} triggeredByUser .
  */
 cvox.TextChangeEvent = function(newValue, newStart, newEnd, triggeredByUser) {
+  Object.defineProperty(this, 'value', {
+    get: function() {
+      return this.value_;
+    }.bind(this),
+    set: function(val) {
+      this.value_ = val.replace('\u00a0', ' ');
+    }.bind(this)
+  });
   this.value = newValue;
+
   this.start = newStart;
   this.end = newEnd;
   this.triggeredByUser = triggeredByUser;
@@ -102,8 +111,17 @@
   /**
    * Current value of the text field.
    * @type {string}
-   * @protected
+   * @private
    */
+  this.value_ = '';
+  Object.defineProperty(this, 'value', {
+    get: function() {
+      return this.value_;
+    }.bind(this),
+    set: function(val) {
+      this.value_ = val.replace('\u00a0', ' ');
+    }.bind(this)
+  });
   this.value = value;
 
   /**
@@ -317,8 +335,6 @@
  * @param {cvox.TextChangeEvent} evt The text change event.
  */
 cvox.ChromeVoxEditableTextBase.prototype.changed = function(evt) {
-  // Normalize space characters.
-  evt.value = evt.value.replace('\u00a0', ' ');
   if (!this.shouldDescribeChange(evt)) {
     this.lastChangeDescribed = false;
     return;
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util.js
index 5a01fca..903c414 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util.js
@@ -263,7 +263,6 @@
  * @return {AutomationNode}
  */
 AutomationUtil.hitTest = function(node, point) {
-  var loc = node.location;
   var child = node.firstChild;
   while (child) {
     var hit = AutomationUtil.hitTest(child, point);
@@ -272,6 +271,12 @@
     child = child.nextSibling;
   }
 
+  var loc = node.unclippedLocation;
+
+  // When |node| is partially or fully offscreen, try to find a better match.
+  if (loc.left < 0 || loc.top < 0)
+    return null;
+
   if (point.x <= (loc.left + loc.width) && point.x >= loc.left &&
       point.y <= (loc.top + loc.height) && point.y >= loc.top)
     return node;
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/desktop_automation_handler.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/desktop_automation_handler.js
index 0a646ef..b31c9d0 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/desktop_automation_handler.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/desktop_automation_handler.js
@@ -321,22 +321,6 @@
     if (!node.root)
       return;
 
-    var root = AutomationUtil.getTopLevelRoot(node.root);
-    // If we're crossing out of a root, save it in case it needs recovering.
-    var prevRange = ChromeVoxState.instance.currentRange;
-    var prevNode = prevRange ? prevRange.start.node : null;
-    if (prevNode) {
-      var prevRoot = AutomationUtil.getTopLevelRoot(prevNode);
-      if (prevRoot && prevRoot !== root)
-        ChromeVoxState.instance.focusRecoveryMap.set(prevRoot, prevRange);
-    }
-    // If a previous node was saved for this focus, restore it.
-    var savedRange = ChromeVoxState.instance.focusRecoveryMap.get(root);
-    ChromeVoxState.instance.focusRecoveryMap.delete(root);
-    if (savedRange) {
-      ChromeVoxState.instance.navigateToRange(savedRange, false);
-      return;
-    }
     var event = new CustomAutomationEvent(EventType.FOCUS, node, evt.eventFrom);
     this.onEventDefault(event);
 
@@ -349,6 +333,7 @@
    * @param {!AutomationEvent} evt
    */
   onLoadComplete: function(evt) {
+    this.lastRootUrl_ = '';
     chrome.automation.getFocus(function(focus) {
       if (!focus || !AutomationUtil.isDescendantOf(focus, evt.target))
         return;
@@ -606,7 +591,7 @@
       // starts tabbing before load complete), then don't move ChromeVox's
       // position on the page.
       if (curRoot && focusedRoot == curRoot &&
-          this.lastRootUrl_ == focusedRoot.docUrl && focus != focusedRoot)
+          this.lastRootUrl_ == focusedRoot.docUrl)
         return;
 
       this.lastRootUrl_ = focusedRoot.docUrl || '';
@@ -625,10 +610,6 @@
           o.format('$name', focusedRoot);
       }
 
-      if (ChromeVoxState.instance.currentRange &&
-          focus == ChromeVoxState.instance.currentRange.start.node)
-        return;
-
       ChromeVoxState.instance.setCurrentRange(cursors.Range.fromNode(focus));
       if (!this.shouldOutput_(evt))
         return;
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/find_handler.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/find_handler.js
index 80ee94d..b604b41 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/find_handler.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/find_handler.js
@@ -30,7 +30,7 @@
  */
 FindHandler.init_ = function() {
   chrome.automation.addTreeChangeObserver(
-      TreeChangeObserverFilter.NO_TREE_CHANGES, FindHandler.onTextMatch_);
+      TreeChangeObserverFilter.TEXT_MARKER_CHANGES, FindHandler.onTextMatch_);
 };
 
 /**
diff --git a/chrome/browser/resources/chromeos/login/offline_ad_login.html b/chrome/browser/resources/chromeos/login/offline_ad_login.html
index a05bbe3..4e75585 100644
--- a/chrome/browser/resources/chromeos/login/offline_ad_login.html
+++ b/chrome/browser/resources/chromeos/login/offline_ad_login.html
@@ -24,6 +24,8 @@
     'authCompleted' - Fired when user enters login and password. Fires with an
                       argument |credentials| which contains:
                       |credentials| = { 'machineName': <machine name input>,
+                                        'distinguished_name': <orgUnitInput>,
+                                        (e.g. "OU=Computers,DC=example,DC=com")
                                         'username': <username> (UPN),
                                         'password': <typed password> }
   Methods:
@@ -57,8 +59,32 @@
               i18n-values="error:adLoginInvalidPassword;
                            label:adLoginPassword">
           </gaia-input>
+          <gaia-button id="moreOptionsBtn" type="link"
+              on-tap="onMoreOptionsClicked_" hidden="[[!showMachineInput]]">
+            $i18n{adJoinMoreOptions}
+          </gaia-button>
         </gaia-input-form>
       </div>
     </gaia-card>
+
+    <dialog is="cr-dialog" id="moreOptionsDlg" on-close="onMoreOptionsClosed_">
+      <div slot="title">
+        $i18n{adJoinMoreOptions}
+      </div>
+      <div slot="body">
+        <gaia-input id="orgUnitInput" label="$i18n{adJoinOrgUnit}" required>
+        </gaia-input>
+      </div>
+      <div slot="button-container">
+        <paper-button autofocus on-tap="onMoreOptionsCancelTap_"
+            class="action-button">
+          $i18n{adJoinCancel}
+        </paper-button>
+        <paper-button autofocus on-tap="onMoreOptionsConfirmTap_"
+            class="action-button">
+          $i18n{adJoinConfirm}
+        </paper-button>
+      </div>
+    </dialog>
   </template>
 </dom-module>
diff --git a/chrome/browser/resources/chromeos/login/offline_ad_login.js b/chrome/browser/resources/chromeos/login/offline_ad_login.js
index b394531..8f5d0973 100644
--- a/chrome/browser/resources/chromeos/login/offline_ad_login.js
+++ b/chrome/browser/resources/chromeos/login/offline_ad_login.js
@@ -50,6 +50,9 @@
     machineNameError: String,
   },
 
+  /** @private Used for 'More options' dialog. */
+  storedOrgUnit: String,
+
   /** @private */
   realmChanged_: function() {
     this.adWelcomeMessage =
@@ -127,10 +130,40 @@
       user += this.userRealm;
     var msg = {
       'machinename': this.$.machineNameInput.value,
+      'distinguished_name': this.$.orgUnitInput.value,
       'username': user,
       'password': this.$.passwordInput.value
     };
     this.$.passwordInput.value = '';
     this.fire('authCompleted', msg);
   },
+
+  /** @private */
+  onMoreOptionsClicked_: function() {
+    this.disabled = true;
+    this.fire('dialogShown');
+    this.storedOrgUnit = this.$.orgUnitInput.value;
+    this.$$('#moreOptionsDlg').showModal();
+    this.$$('#gaiaCard').classList.add('full-disabled');
+  },
+
+  /** @private */
+  onMoreOptionsConfirmTap_: function() {
+    this.storedOrgUnit = null;
+    this.$$('#moreOptionsDlg').close();
+  },
+
+  /** @private */
+  onMoreOptionsCancelTap_: function() {
+    this.$$('#moreOptionsDlg').close();
+  },
+
+  /** @private */
+  onMoreOptionsClosed_: function() {
+    if (this.storedOrgUnit)
+      this.$.orgUnitInput.value = this.storedOrgUnit;
+    this.fire('dialogHidden');
+    this.disabled = false;
+    this.$$('#gaiaCard').classList.remove('full-disabled');
+  },
 });
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js b/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js
index f57f6906..4d2db03 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js
@@ -150,9 +150,10 @@
         this.offlineAdUi_.disabled = true;
         this.activeDirectoryMachine_ = e.detail.machinename;
         this.activeDirectoryUsername_ = e.detail.username;
-        chrome.send(
-            'oauthEnrollAdCompleteLogin',
-            [e.detail.machinename, e.detail.username, e.detail.password]);
+        chrome.send('oauthEnrollAdCompleteLogin', [
+          e.detail.machinename, e.detail.distinguished_name, e.detail.username,
+          e.detail.password
+        ]);
       }.bind(this));
 
       this.authenticator_.addEventListener(
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
index e8b95db..492913c 100644
--- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
@@ -422,6 +422,10 @@
   builder->Add("adLoginInvalidPassword", IDS_AD_INVALID_PASSWORD);
   builder->Add("adJoinErrorMachineNameInvalid", IDS_AD_MACHINENAME_INVALID);
   builder->Add("adJoinErrorMachineNameTooLong", IDS_AD_MACHINENAME_TOO_LONG);
+  builder->Add("adJoinMoreOptions", IDS_AD_MORE_OPTIONS_BUTTON);
+  builder->Add("adJoinOrgUnit", IDS_AD_ORG_UNIT_HINT);
+  builder->Add("adJoinCancel", IDS_AD_CANCEL_BUTTON);
+  builder->Add("adJoinConfirm", IDS_AD_CONFIRM_BUTTON);
   builder->Add("licenseSelectionCardTitle",
                IDS_ENTERPRISE_ENROLLMENT_LICENSE_SELECTION);
   builder->Add("licenseSelectionCardExplanation",
@@ -569,13 +573,14 @@
 
 void EnrollmentScreenHandler::HandleAdCompleteLogin(
     const std::string& machine_name,
+    const std::string& distinguished_name,
     const std::string& user_name,
     const std::string& password) {
   observe_network_failure_ = false;
   DCHECK(controller_);
   DCHECK(authpolicy_login_helper_);
   authpolicy_login_helper_->JoinAdDomain(
-      machine_name, user_name, password,
+      machine_name, distinguished_name, user_name, password,
       base::BindOnce(&EnrollmentScreenHandler::HandleAdDomainJoin,
                      weak_ptr_factory_.GetWeakPtr(), machine_name, user_name));
 }
@@ -583,12 +588,14 @@
 void EnrollmentScreenHandler::HandleAdDomainJoin(
     const std::string& machine_name,
     const std::string& user_name,
-    authpolicy::ErrorType code) {
+    authpolicy::ErrorType code,
+    const std::string& machine_domain) {
   switch (code) {
-    case authpolicy::ERROR_NONE:
+    case authpolicy::ERROR_NONE: {
       ShowEnrollmentSpinnerScreen();
-      controller_->OnAdJoined(gaia::ExtractDomainName(user_name));
+      controller_->OnAdJoined(machine_domain);
       return;
+    }
     case authpolicy::ERROR_NETWORK_PROBLEM:
       // Could be a network problem, but could also be a misspelled domain name.
       ShowError(IDS_AD_AUTH_NETWORK_ERROR, true);
@@ -620,6 +627,18 @@
     case authpolicy::ERROR_USER_HIT_JOIN_QUOTA:
       ShowError(IDS_AD_USER_HIT_JOIN_QUOTA, true);
       return;
+    case authpolicy::ERROR_OU_DOES_NOT_EXIST:
+      ShowError(IDS_AD_OU_DOES_NOT_EXIST, true);
+      return;
+    case authpolicy::ERROR_INVALID_OU:
+      ShowError(IDS_AD_OU_INVALID, true);
+      return;
+    case authpolicy::ERROR_OU_ACCESS_DENIED:
+      ShowError(IDS_AD_OU_ACCESS_DENIED, true);
+      return;
+    case authpolicy::ERROR_SETTING_OU_FAILED:
+      ShowError(IDS_AD_OU_SETTING_FAILED, true);
+      return;
 #if !defined(ARCH_CPU_X86_64)
     // Currently, the Active Directory integration is only supported on x86_64
     // systems. (see https://crbug.com/676602)
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h
index 28de6f39..23b7d798 100644
--- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h
@@ -83,6 +83,7 @@
   void HandleCompleteLogin(const std::string& user,
                            const std::string& auth_code);
   void HandleAdCompleteLogin(const std::string& machine_name,
+                             const std::string& distinguished_name,
                              const std::string& user_name,
                              const std::string& password);
   void HandleRetry();
@@ -127,7 +128,8 @@
   // Handler callback from AuthPolicyClient.
   void HandleAdDomainJoin(const std::string& machine_name,
                           const std::string& user_name,
-                          authpolicy::ErrorType code);
+                          authpolicy::ErrorType code,
+                          const std::string& machine_domain);
 
   // Keeps the controller for this view.
   Controller* controller_ = nullptr;
diff --git a/chrome/common/crash_keys.cc b/chrome/common/crash_keys.cc
index 1fe7e412..9d5d559 100644
--- a/chrome/common/crash_keys.cc
+++ b/chrome/common/crash_keys.cc
@@ -91,13 +91,6 @@
     {"seccomp-sigsys", kMediumSize},
 #endif
 
-    // Site isolation.  These keys help debug renderer kills such as
-    // https://crbug.com/773140.
-    {"requested_site_url", kSmallSize},
-    {"requested_origin", kSmallSize},
-    {"killed_process_origin_lock", kSmallSize},
-    {"site_isolation_mode", kSmallSize},
-
     // Temporary for https://crbug.com/685996.
     {kUserCloudPolicyManagerConnectTrace, kMediumSize},
 
diff --git a/chromecast/crash/cast_crash_keys.cc b/chromecast/crash/cast_crash_keys.cc
index 2a5a42b8..4e9d922 100644
--- a/chromecast/crash/cast_crash_keys.cc
+++ b/chromecast/crash/cast_crash_keys.cc
@@ -42,13 +42,6 @@
       // media/:
       {"zero-encode-details", ::crash_keys::kSmallSize},
 
-      // Site isolation.  These keys help debug renderer kills such as
-      // https://crbug.com/773140.
-      {"requested_site_url", ::crash_keys::kSmallSize},
-      {"requested_origin", ::crash_keys::kSmallSize},
-      {"killed_process_origin_lock", ::crash_keys::kSmallSize},
-      {"site_isolation_mode", ::crash_keys::kSmallSize},
-
       // Temporary for https://crbug.com/685996.
       {"user-cloud-policy-manager-connect-trace", ::crash_keys::kMediumSize},
 
diff --git a/chromeos/dbus/auth_policy_client.cc b/chromeos/dbus/auth_policy_client.cc
index c243d8d..0084fbdf 100644
--- a/chromeos/dbus/auth_policy_client.cc
+++ b/chromeos/dbus/auth_policy_client.cc
@@ -69,7 +69,7 @@
                                  authpolicy::kJoinADDomainMethod);
     dbus::MessageWriter writer(&method_call);
     if (!writer.AppendProtoAsArrayOfBytes(request)) {
-      std::move(callback).Run(authpolicy::ERROR_DBUS_FAILURE);
+      std::move(callback).Run(authpolicy::ERROR_DBUS_FAILURE, std::string());
       return;
     }
     writer.AppendFileDescriptor(password_fd);
@@ -178,12 +178,18 @@
   void HandleJoinCallback(JoinCallback callback, dbus::Response* response) {
     if (!response) {
       DLOG(ERROR) << "Join: Couldn't call to authpolicy";
-      std::move(callback).Run(authpolicy::ERROR_DBUS_FAILURE);
+      std::move(callback).Run(authpolicy::ERROR_DBUS_FAILURE, std::string());
       return;
     }
 
     dbus::MessageReader reader(response);
-    std::move(callback).Run(GetErrorFromReader(&reader));
+    authpolicy::ErrorType error = GetErrorFromReader(&reader);
+    std::string machine_domain;
+    if (error == authpolicy::ERROR_NONE) {
+      if (!reader.PopString(&machine_domain))
+        error = authpolicy::ERROR_DBUS_FAILURE;
+    }
+    std::move(callback).Run(error, machine_domain);
   }
 
   template <class T>
diff --git a/chromeos/dbus/auth_policy_client.h b/chromeos/dbus/auth_policy_client.h
index d7932399..e8e0164 100644
--- a/chromeos/dbus/auth_policy_client.h
+++ b/chromeos/dbus/auth_policy_client.h
@@ -32,7 +32,9 @@
   using GetUserKerberosFilesCallback =
       base::OnceCallback<void(authpolicy::ErrorType error,
                               const authpolicy::KerberosFiles& kerberos_files)>;
-  using JoinCallback = base::OnceCallback<void(authpolicy::ErrorType error)>;
+  using JoinCallback =
+      base::OnceCallback<void(authpolicy::ErrorType error,
+                              const std::string& machine_domain)>;
   using RefreshPolicyCallback =
       base::OnceCallback<void(authpolicy::ErrorType error)>;
 
diff --git a/chromeos/dbus/fake_auth_policy_client.cc b/chromeos/dbus/fake_auth_policy_client.cc
index 5010932..80c9e81 100644
--- a/chromeos/dbus/fake_auth_policy_client.cc
+++ b/chromeos/dbus/fake_auth_policy_client.cc
@@ -95,7 +95,9 @@
     const authpolicy::JoinDomainRequest& request,
     int password_fd,
     JoinCallback callback) {
+  DCHECK(!AuthPolicyLoginHelper::IsAdLocked());
   authpolicy::ErrorType error = authpolicy::ERROR_NONE;
+  std::string machine_domain;
   if (!started_) {
     LOG(ERROR) << "authpolicyd not started";
     error = authpolicy::ERROR_DBUS_FAILURE;
@@ -111,11 +113,18 @@
                           base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
     if (parts.size() != 2 || parts[0].empty() || parts[1].empty()) {
       error = authpolicy::ERROR_PARSE_UPN_FAILED;
+    } else {
+      machine_domain = parts[1];
     }
   }
+
   if (error == authpolicy::ERROR_NONE)
     machine_name_ = request.machine_name();
-  PostDelayedClosure(base::BindOnce(std::move(callback), error),
+  if (error != authpolicy::ERROR_NONE)
+    machine_domain.clear();
+  else if (request.has_machine_domain() && !request.machine_domain().empty())
+    machine_domain = request.machine_domain();
+  PostDelayedClosure(base::BindOnce(std::move(callback), error, machine_domain),
                      dbus_operation_delay_);
 }
 
@@ -123,6 +132,7 @@
     const authpolicy::AuthenticateUserRequest& request,
     int password_fd,
     AuthCallback callback) {
+  DCHECK(AuthPolicyLoginHelper::IsAdLocked());
   authpolicy::ErrorType error = authpolicy::ERROR_NONE;
   authpolicy::ActiveDirectoryAccountInfo account_info;
   if (!started_) {
diff --git a/chromeos/dbus/fake_auth_policy_client_unittest.cc b/chromeos/dbus/fake_auth_policy_client_unittest.cc
index 41c8e850..74e2be3 100644
--- a/chromeos/dbus/fake_auth_policy_client_unittest.cc
+++ b/chromeos/dbus/fake_auth_policy_client_unittest.cc
@@ -17,9 +17,11 @@
 namespace chromeos {
 namespace {
 
-const char kCorrectMachineName[] = "machine_name";
-const char kCorrectUserName[] = "user@realm.com";
-const char kAccountId[] = "user-account-id";
+constexpr char kCorrectMachineName[] = "machine_name";
+constexpr char kCorrectUserName[] = "user@domain.com";
+constexpr char kCorrectUserDomain[] = "domain.com";
+constexpr char kAccountId[] = "user-account-id";
+constexpr char kMachineDomain[] = "machine.domain";
 
 }  // namespace
 
@@ -28,7 +30,7 @@
   FakeAuthPolicyClientTest() = default;
 
  protected:
-  FakeAuthPolicyClient* authpolicy_client() { return &client_; }
+  FakeAuthPolicyClient* authpolicy_client() { return auth_policy_client_ptr_; }
 
   void SetUp() override {
     ::testing::Test::SetUp();
@@ -36,6 +38,11 @@
         std::make_unique<FakeSessionManagerClient>());
     DBusThreadManager::GetSetterForTesting()->SetCryptohomeClient(
         std::make_unique<FakeCryptohomeClient>());
+    auto auth_policy_client = std::make_unique<FakeAuthPolicyClient>();
+    auth_policy_client_ptr_ = auth_policy_client.get();
+    DBusThreadManager::GetSetterForTesting()->SetAuthPolicyClient(
+        std::move(auth_policy_client));
+    authpolicy_client()->DisableOperationDelayForTesting();
   }
 
   void JoinAdDomain(const std::string& machine_name,
@@ -48,6 +55,18 @@
                                       std::move(callback));
   }
 
+  void JoinAdDomainWithMachineDomain(const std::string& machine_name,
+                                     const std::string& machine_domain,
+                                     const std::string& username,
+                                     AuthPolicyClient::JoinCallback callback) {
+    authpolicy::JoinDomainRequest request;
+    request.set_machine_name(machine_name);
+    request.set_user_principal_name(username);
+    request.set_machine_domain(machine_domain);
+    authpolicy_client()->JoinAdDomain(request, /* password_fd */ -1,
+                                      std::move(callback));
+  }
+
   void AuthenticateUser(const std::string& username,
                         const std::string& account_id,
                         AuthPolicyClient::AuthCallback callback) {
@@ -64,7 +83,7 @@
   }
 
  private:
-  FakeAuthPolicyClient client_;
+  FakeAuthPolicyClient* auth_policy_client_ptr_;  // not owned.
   base::MessageLoop loop_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeAuthPolicyClientTest);
@@ -73,61 +92,111 @@
 // Tests parsing machine name.
 TEST_F(FakeAuthPolicyClientTest, JoinAdDomain_ParseMachineName) {
   authpolicy_client()->set_started(true);
-  LockDeviceActiveDirectory();
   JoinAdDomain("correct_length1", kCorrectUserName,
-               base::BindOnce([](authpolicy::ErrorType error) {
-                 EXPECT_EQ(authpolicy::ERROR_NONE, error);
-               }));
+               base::BindOnce(
+                   [](authpolicy::ErrorType error, const std::string& domain) {
+                     EXPECT_EQ(authpolicy::ERROR_NONE, error);
+                     EXPECT_EQ(kCorrectUserDomain, domain);
+                   }));
   JoinAdDomain("", kCorrectUserName,
-               base::BindOnce([](authpolicy::ErrorType error) {
-                 EXPECT_EQ(authpolicy::ERROR_INVALID_MACHINE_NAME, error);
-               }));
+               base::BindOnce(
+                   [](authpolicy::ErrorType error, const std::string& domain) {
+                     EXPECT_EQ(authpolicy::ERROR_INVALID_MACHINE_NAME, error);
+                     EXPECT_TRUE(domain.empty());
+                   }));
   JoinAdDomain("too_long_machine_name", kCorrectUserName,
-               base::BindOnce([](authpolicy::ErrorType error) {
-                 EXPECT_EQ(authpolicy::ERROR_MACHINE_NAME_TOO_LONG, error);
-               }));
+               base::BindOnce(
+                   [](authpolicy::ErrorType error, const std::string& domain) {
+                     EXPECT_EQ(authpolicy::ERROR_MACHINE_NAME_TOO_LONG, error);
+                     EXPECT_TRUE(domain.empty());
+                   }));
   JoinAdDomain("invalid:name", kCorrectUserName,
-               base::BindOnce([](authpolicy::ErrorType error) {
-                 EXPECT_EQ(authpolicy::ERROR_INVALID_MACHINE_NAME, error);
-               }));
+               base::BindOnce(
+                   [](authpolicy::ErrorType error, const std::string& domain) {
+                     EXPECT_EQ(authpolicy::ERROR_INVALID_MACHINE_NAME, error);
+                     EXPECT_TRUE(domain.empty());
+                   }));
+  base::RunLoop loop;
   JoinAdDomain(">nvalidname", kCorrectUserName,
-               base::BindOnce([](authpolicy::ErrorType error) {
-                 EXPECT_EQ(authpolicy::ERROR_INVALID_MACHINE_NAME, error);
-               }));
+               base::BindOnce(
+                   [](base::OnceClosure closure, authpolicy::ErrorType error,
+                      const std::string& domain) {
+                     EXPECT_EQ(authpolicy::ERROR_INVALID_MACHINE_NAME, error);
+                     EXPECT_TRUE(domain.empty());
+                     std::move(closure).Run();
+                   },
+                   loop.QuitClosure()));
+  loop.Run();
+}
 
-  base::RunLoop().RunUntilIdle();
+// Tests join to a different machine domain.
+TEST_F(FakeAuthPolicyClientTest, JoinAdDomain_MachineDomain) {
+  authpolicy_client()->set_started(true);
+  JoinAdDomainWithMachineDomain(kCorrectMachineName, kMachineDomain,
+                                kCorrectUserName,
+                                base::BindOnce([](authpolicy::ErrorType error,
+                                                  const std::string& domain) {
+                                  EXPECT_EQ(authpolicy::ERROR_NONE, error);
+                                  EXPECT_EQ(kMachineDomain, domain);
+                                }));
+  base::RunLoop loop;
+  JoinAdDomainWithMachineDomain(
+      kCorrectMachineName, "", kCorrectUserName,
+      base::BindOnce(
+          [](base::OnceClosure closure, authpolicy::ErrorType error,
+             const std::string& domain) {
+            EXPECT_EQ(authpolicy::ERROR_NONE, error);
+            EXPECT_EQ(kCorrectUserDomain, domain);
+            std::move(closure).Run();
+          },
+          loop.QuitClosure()));
+  loop.Run();
 }
 
 // Tests parsing user name.
 TEST_F(FakeAuthPolicyClientTest, JoinAdDomain_ParseUPN) {
   authpolicy_client()->set_started(true);
-  LockDeviceActiveDirectory();
-  JoinAdDomain(kCorrectMachineName, "user@realm.com",
-               base::BindOnce([](authpolicy::ErrorType error) {
-                 EXPECT_EQ(authpolicy::ERROR_NONE, error);
-               }));
+  JoinAdDomain(kCorrectMachineName, kCorrectUserName,
+               base::BindOnce(
+                   [](authpolicy::ErrorType error, const std::string& domain) {
+                     EXPECT_EQ(authpolicy::ERROR_NONE, error);
+                     EXPECT_EQ(kCorrectUserDomain, domain);
+                   }));
   JoinAdDomain(kCorrectMachineName, "user",
-               base::BindOnce([](authpolicy::ErrorType error) {
-                 EXPECT_EQ(authpolicy::ERROR_PARSE_UPN_FAILED, error);
-               }));
+               base::BindOnce(
+                   [](authpolicy::ErrorType error, const std::string& domain) {
+                     EXPECT_EQ(authpolicy::ERROR_PARSE_UPN_FAILED, error);
+                     EXPECT_TRUE(domain.empty());
+                   }));
   JoinAdDomain(kCorrectMachineName, "",
-               base::BindOnce([](authpolicy::ErrorType error) {
-                 EXPECT_EQ(authpolicy::ERROR_PARSE_UPN_FAILED, error);
-               }));
+               base::BindOnce(
+                   [](authpolicy::ErrorType error, const std::string& domain) {
+                     EXPECT_EQ(authpolicy::ERROR_PARSE_UPN_FAILED, error);
+                     EXPECT_TRUE(domain.empty());
+                   }));
   JoinAdDomain(kCorrectMachineName, "user@",
-               base::BindOnce([](authpolicy::ErrorType error) {
-                 EXPECT_EQ(authpolicy::ERROR_PARSE_UPN_FAILED, error);
-               }));
+               base::BindOnce(
+                   [](authpolicy::ErrorType error, const std::string& domain) {
+                     EXPECT_EQ(authpolicy::ERROR_PARSE_UPN_FAILED, error);
+                     EXPECT_TRUE(domain.empty());
+                   }));
   JoinAdDomain(kCorrectMachineName, "@realm",
-               base::BindOnce([](authpolicy::ErrorType error) {
-                 EXPECT_EQ(authpolicy::ERROR_PARSE_UPN_FAILED, error);
-               }));
+               base::BindOnce(
+                   [](authpolicy::ErrorType error, const std::string& domain) {
+                     EXPECT_EQ(authpolicy::ERROR_PARSE_UPN_FAILED, error);
+                     EXPECT_TRUE(domain.empty());
+                   }));
+  base::RunLoop loop;
   JoinAdDomain(kCorrectMachineName, "user@realm@com",
-               base::BindOnce([](authpolicy::ErrorType error) {
-                 EXPECT_EQ(authpolicy::ERROR_PARSE_UPN_FAILED, error);
-               }));
-
-  base::RunLoop().RunUntilIdle();
+               base::BindOnce(
+                   [](base::OnceClosure closure, authpolicy::ErrorType error,
+                      const std::string& domain) {
+                     EXPECT_EQ(authpolicy::ERROR_PARSE_UPN_FAILED, error);
+                     EXPECT_TRUE(domain.empty());
+                     std::move(closure).Run();
+                   },
+                   loop.QuitClosure()));
+  loop.Run();
 }
 
 // Test AuthenticateUser.
@@ -147,11 +216,13 @@
 
 // Tests calls to not started authpolicyd fails.
 TEST_F(FakeAuthPolicyClientTest, NotStartedAuthPolicyService) {
-  LockDeviceActiveDirectory();
   JoinAdDomain(kCorrectMachineName, kCorrectUserName,
-               base::BindOnce([](authpolicy::ErrorType error) {
-                 EXPECT_EQ(authpolicy::ERROR_DBUS_FAILURE, error);
-               }));
+               base::BindOnce(
+                   [](authpolicy::ErrorType error, const std::string& domain) {
+                     EXPECT_EQ(authpolicy::ERROR_DBUS_FAILURE, error);
+                     EXPECT_TRUE(domain.empty());
+                   }));
+  LockDeviceActiveDirectory();
   AuthenticateUser(
       kCorrectUserName, std::string() /* account_id */,
       base::BindOnce([](authpolicy::ErrorType error,
@@ -162,13 +233,16 @@
       base::BindOnce([](authpolicy::ErrorType error) {
         EXPECT_EQ(authpolicy::ERROR_DBUS_FAILURE, error);
       }));
+  base::RunLoop loop;
   authpolicy_client()->RefreshUserPolicy(
       AccountId::FromUserEmail(kCorrectUserName),
-      base::BindOnce([](authpolicy::ErrorType error) {
-        EXPECT_EQ(authpolicy::ERROR_DBUS_FAILURE, error);
-      }));
-
-  base::RunLoop().RunUntilIdle();
+      base::BindOnce(
+          [](base::OnceClosure closure, authpolicy::ErrorType error) {
+            EXPECT_EQ(authpolicy::ERROR_DBUS_FAILURE, error);
+            std::move(closure).Run();
+          },
+          loop.QuitClosure()));
+  loop.Run();
 }
 
 // Tests RefreshDevicePolicy. On a not locked device it should cache policy. On
@@ -180,12 +254,14 @@
         EXPECT_EQ(authpolicy::ERROR_DEVICE_POLICY_CACHED_BUT_NOT_SENT, error);
       }));
   LockDeviceActiveDirectory();
-  authpolicy_client()->RefreshDevicePolicy(
-      base::BindOnce([](authpolicy::ErrorType error) {
+  base::RunLoop loop;
+  authpolicy_client()->RefreshDevicePolicy(base::BindOnce(
+      [](base::OnceClosure closure, authpolicy::ErrorType error) {
         EXPECT_EQ(authpolicy::ERROR_NONE, error);
-      }));
-
-  base::RunLoop().RunUntilIdle();
+        std::move(closure).Run();
+      },
+      loop.QuitClosure()));
+  loop.Run();
 }
 
 }  // namespace chromeos
diff --git a/chromeos/login/auth/authpolicy_login_helper.cc b/chromeos/login/auth/authpolicy_login_helper.cc
index e51fd2ed..cd17676 100644
--- a/chromeos/login/auth/authpolicy_login_helper.cc
+++ b/chromeos/login/auth/authpolicy_login_helper.cc
@@ -5,6 +5,8 @@
 #include "chromeos/login/auth/authpolicy_login_helper.h"
 
 #include "base/files/file_util.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
 #include "base/task_scheduler/post_task.h"
 #include "chromeos/cryptohome/cryptohome_util.h"
 #include "chromeos/dbus/auth_policy_client.h"
@@ -19,6 +21,8 @@
 
 constexpr char kAttrMode[] = "enterprise.mode";
 constexpr char kDeviceModeEnterpriseAD[] = "enterprise_ad";
+constexpr char kDCPrefix[] = "DC=";
+constexpr char kOUPrefix[] = "OU=";
 
 base::ScopedFD GetDataReadPipe(const std::string& data) {
   int pipe_fds[2];
@@ -43,6 +47,30 @@
   // Do nothing.
 }
 
+bool ParseDomainAndOU(const std::string& distinguished_name,
+                      authpolicy::JoinDomainRequest* request) {
+  std::string machine_domain;
+  std::vector<std::string> split_dn =
+      base::SplitString(distinguished_name, ",", base::TRIM_WHITESPACE,
+                        base::SPLIT_WANT_NONEMPTY);
+  for (const std::string& str : split_dn) {
+    if (base::StartsWith(str, kOUPrefix,
+                         base::CompareCase::INSENSITIVE_ASCII)) {
+      *request->add_machine_ou() = str.substr(strlen(kOUPrefix));
+    } else if (base::StartsWith(str, kDCPrefix,
+                                base::CompareCase::INSENSITIVE_ASCII)) {
+      if (!machine_domain.empty())
+        machine_domain.append(".");
+      machine_domain.append(str.substr(strlen(kDCPrefix)));
+    } else {
+      return false;
+    }
+  }
+  if (!machine_domain.empty())
+    request->set_machine_domain(machine_domain);
+  return true;
+}
+
 }  // namespace
 
 AuthPolicyLoginHelper::AuthPolicyLoginHelper() : weak_factory_(this) {}
@@ -76,24 +104,32 @@
 bool AuthPolicyLoginHelper::LockDeviceActiveDirectoryForTesting(
     const std::string& realm) {
   return cu::InstallAttributesSet("enterprise.owned", "true") &&
-         cu::InstallAttributesSet("enterprise.mode", "enterprise_ad") &&
+         cu::InstallAttributesSet(kAttrMode, kDeviceModeEnterpriseAD) &&
          cu::InstallAttributesSet("enterprise.realm", realm) &&
          cu::InstallAttributesFinalize();
 }
 
 void AuthPolicyLoginHelper::JoinAdDomain(const std::string& machine_name,
+                                         const std::string& distinguished_name,
                                          const std::string& username,
                                          const std::string& password,
                                          JoinCallback callback) {
   DCHECK(!IsAdLocked());
   DCHECK(!weak_factory_.HasWeakPtrs()) << "Another operation is in progress";
   authpolicy::JoinDomainRequest request;
-  request.set_machine_name(machine_name);
-  request.set_user_principal_name(username);
+  if (!ParseDomainAndOU(distinguished_name, &request)) {
+    DLOG(ERROR) << "Failed to parse computer distinguished name";
+    std::move(callback).Run(authpolicy::ERROR_INVALID_OU, std::string());
+    return;
+  }
+  if (!machine_name.empty())
+    request.set_machine_name(machine_name);
+  if (!username.empty())
+    request.set_user_principal_name(username);
   chromeos::DBusThreadManager::Get()->GetAuthPolicyClient()->JoinAdDomain(
       request, GetDataReadPipe(password).get(),
       base::BindOnce(&AuthPolicyLoginHelper::OnJoinCallback,
-                     weak_factory_.GetWeakPtr(), base::Passed(&callback)));
+                     weak_factory_.GetWeakPtr(), std::move(callback)));
 }
 
 void AuthPolicyLoginHelper::AuthenticateUser(const std::string& username,
@@ -116,21 +152,23 @@
 }
 
 void AuthPolicyLoginHelper::OnJoinCallback(JoinCallback callback,
-                                           authpolicy::ErrorType error) {
+                                           authpolicy::ErrorType error,
+                                           const std::string& machine_domain) {
   DCHECK(!IsAdLocked());
   if (error != authpolicy::ERROR_NONE) {
-    std::move(callback).Run(error);
+    std::move(callback).Run(error, machine_domain);
     return;
   }
   chromeos::DBusThreadManager::Get()
       ->GetAuthPolicyClient()
-      ->RefreshDevicePolicy(
-          base::BindOnce(&AuthPolicyLoginHelper::OnFirstPolicyRefreshCallback,
-                         weak_factory_.GetWeakPtr(), base::Passed(&callback)));
+      ->RefreshDevicePolicy(base::BindOnce(
+          &AuthPolicyLoginHelper::OnFirstPolicyRefreshCallback,
+          weak_factory_.GetWeakPtr(), base::Passed(&callback), machine_domain));
 }
 
 void AuthPolicyLoginHelper::OnFirstPolicyRefreshCallback(
     JoinCallback callback,
+    const std::string& machine_domain,
     authpolicy::ErrorType error) {
   DCHECK(!IsAdLocked());
   // First policy refresh happens before device is locked. So policy store
@@ -139,7 +177,7 @@
   DCHECK(error != authpolicy::ERROR_NONE);
   if (error == authpolicy::ERROR_DEVICE_POLICY_CACHED_BUT_NOT_SENT)
     error = authpolicy::ERROR_NONE;
-  std::move(callback).Run(error);
+  std::move(callback).Run(error, machine_domain);
 }
 
 void AuthPolicyLoginHelper::OnAuthCallback(
diff --git a/chromeos/login/auth/authpolicy_login_helper.h b/chromeos/login/auth/authpolicy_login_helper.h
index 9b59d722..591b566f 100644
--- a/chromeos/login/auth/authpolicy_login_helper.h
+++ b/chromeos/login/auth/authpolicy_login_helper.h
@@ -47,10 +47,14 @@
   // Packs arguments and calls AuthPolicyClient::JoinAdDomain. Joins machine to
   // Active directory domain. Then it calls RefreshDevicePolicy to cache the
   // policy on the authpolicyd side. |machine_name| is a name for a local
-  // machine. |username|, |password| are credentials of the Active directory
-  // account which has right to join the machine to the domain. |callback| is
-  // called after getting (or failing to get) D-BUS response.
+  // machine. If |distinguished_name| is not empty |machine| would be put into
+  // that domain or/and organizational unit structure. Otherwise |machine| would
+  // be joined to domain of the |username|. |username|, |password| are
+  // credentials of the Active directory account which has right to join the
+  // machine to the domain. |callback| is called after getting (or failing to
+  // get) D-BUS response.
   void JoinAdDomain(const std::string& machine_name,
+                    const std::string& distinguished_name,
                     const std::string& username,
                     const std::string& password,
                     JoinCallback callback);
@@ -71,11 +75,14 @@
 
  private:
   // Called from AuthPolicyClient::JoinAdDomain.
-  void OnJoinCallback(JoinCallback callback, authpolicy::ErrorType error);
+  void OnJoinCallback(JoinCallback callback,
+                      authpolicy::ErrorType error,
+                      const std::string& machine_domain);
 
   // Called from AuthPolicyClient::RefreshDevicePolicy. This is used only once
   // during device enrollment with the first device policy refresh.
   void OnFirstPolicyRefreshCallback(JoinCallback callback,
+                                    const std::string& machine_domain,
                                     authpolicy::ErrorType error);
 
   // Called from AuthPolicyClient::AuthenticateUser.
diff --git a/chromeos/login/auth/authpolicy_login_helper_unittest.cc b/chromeos/login/auth/authpolicy_login_helper_unittest.cc
index 0a585ce..6769daa1 100644
--- a/chromeos/login/auth/authpolicy_login_helper_unittest.cc
+++ b/chromeos/login/auth/authpolicy_login_helper_unittest.cc
@@ -24,7 +24,7 @@
     EXPECT_FALSE(join_ad_domain_called_);
     EXPECT_FALSE(refresh_device_policy_called_);
     join_ad_domain_called_ = true;
-    std::move(callback).Run(authpolicy::ERROR_NONE);
+    std::move(callback).Run(authpolicy::ERROR_NONE, std::string());
   }
 
   void RefreshDevicePolicy(RefreshPolicyCallback callback) override {
@@ -60,8 +60,11 @@
       std::make_unique<FakeCryptohomeClient>());
   AuthPolicyLoginHelper helper;
   helper.JoinAdDomain(std::string(), std::string(), std::string(),
-                      base::BindOnce([](authpolicy::ErrorType error) {
+                      std::string(),
+                      base::BindOnce([](authpolicy::ErrorType error,
+                                        const std::string& domain) {
                         EXPECT_EQ(authpolicy::ERROR_NONE, error);
+                        EXPECT_TRUE(domain.empty());
                       }));
   mock_client_ptr->CheckExpectations();
 }
diff --git a/components/exo/wm_helper.cc b/components/exo/wm_helper.cc
index 9a086bda..3a42f7248 100644
--- a/components/exo/wm_helper.cc
+++ b/components/exo/wm_helper.cc
@@ -72,8 +72,7 @@
 }
 
 void WMHelper::AddCursorObserver(aura::client::CursorClientObserver* observer) {
-  // TODO(crbug.com/631103): Mushrome doesn't have a cursor manager yet.
-  if (ash::Shell::GetAshConfig() == ash::Config::CLASSIC)
+  if (ash::Shell::GetAshConfig() != ash::Config::MASH)
     ash::Shell::Get()->cursor_manager()->AddObserver(observer);
 }
 
@@ -183,15 +182,13 @@
 }
 
 ui::CursorSize WMHelper::GetCursorSize() const {
-  // TODO(crbug.com/631103): Mushrome doesn't have a cursor manager yet.
-  if (ash::Shell::GetAshConfig() == ash::Config::MUS)
+  if (ash::Shell::GetAshConfig() == ash::Config::MASH)
     return ui::CursorSize::kNormal;
   return ash::Shell::Get()->cursor_manager()->GetCursorSize();
 }
 
 const display::Display& WMHelper::GetCursorDisplay() const {
-  // TODO(crbug.com/631103): Mushrome doesn't have a cursor manager yet.
-  if (ash::Shell::GetAshConfig() == ash::Config::MUS) {
+  if (ash::Shell::GetAshConfig() == ash::Config::MASH) {
     static const display::Display display;
     return display;
   }
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 76191f4..be749242 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1653,6 +1653,9 @@
     "web_contents/web_drag_source_mac.mm",
     "web_contents/web_drag_utils_win.cc",
     "web_contents/web_drag_utils_win.h",
+    "webauth/cbor/cbor_binary.h",
+    "webauth/cbor/cbor_reader.cc",
+    "webauth/cbor/cbor_reader.h",
     "webauth/cbor/cbor_values.cc",
     "webauth/cbor/cbor_values.h",
     "webauth/cbor/cbor_writer.cc",
diff --git a/content/browser/bad_message.cc b/content/browser/bad_message.cc
index 94b6c46..9918cc87 100644
--- a/content/browser/bad_message.cc
+++ b/content/browser/bad_message.cc
@@ -73,5 +73,17 @@
   return crash_key;
 }
 
+base::debug::CrashKeyString* GetKilledProcessOriginLockKey() {
+  static auto* crash_key = base::debug::AllocateCrashKeyString(
+      "killed_process_origin_lock", base::debug::CrashKeySize::Size64);
+  return crash_key;
+}
+
+base::debug::CrashKeyString* GetRequestedSiteURLKey() {
+  static auto* crash_key = base::debug::AllocateCrashKeyString(
+      "requested_site_url", base::debug::CrashKeySize::Size64);
+  return crash_key;
+}
+
 }  // namespace bad_message
 }  // namespace content
diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h
index c0fbefd..d50dc9a 100644
--- a/content/browser/bad_message.h
+++ b/content/browser/bad_message.h
@@ -240,6 +240,13 @@
 // messages.
 base::debug::CrashKeyString* GetMojoErrorCrashKey();
 
+// Site isolation. These keys help debug renderer kills such as
+// https://crbug.com/773140.
+// Returns a key named "killed_process_origin_lock".
+base::debug::CrashKeyString* GetKilledProcessOriginLockKey();
+// Retuns a key named "requested_site_url".
+base::debug::CrashKeyString* GetRequestedSiteURLKey();
+
 }  // namespace bad_message
 }  // namespace content
 
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc
index b759c9e..37139a47 100644
--- a/content/browser/child_process_security_policy_impl.cc
+++ b/content/browser/child_process_security_policy_impl.cc
@@ -18,6 +18,7 @@
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
+#include "content/browser/bad_message.h"
 #include "content/browser/isolated_origin_util.h"
 #include "content/browser/site_instance_impl.h"
 #include "content/common/site_isolation_policy.h"
@@ -1059,10 +1060,15 @@
   if (!can_access) {
     // Returning false here will result in a renderer kill.  Set some crash
     // keys that will help understand the circumstances of that kill.
-    base::debug::SetCrashKeyValue("requested_site_url", site_url.spec());
-    base::debug::SetCrashKeyValue("requested_origin", url.GetOrigin().spec());
-    base::debug::SetCrashKeyValue("killed_process_origin_lock",
-                                  state->second->origin_lock().spec());
+    base::debug::SetCrashKeyString(bad_message::GetRequestedSiteURLKey(),
+                                   site_url.spec());
+    base::debug::SetCrashKeyString(bad_message::GetKilledProcessOriginLockKey(),
+                                   state->second->origin_lock().spec());
+
+    static auto* requested_origin_key = base::debug::AllocateCrashKeyString(
+        "requested_origin", base::debug::CrashKeySize::Size64);
+    base::debug::SetCrashKeyString(requested_origin_key,
+                                   url.GetOrigin().spec());
   }
   return can_access;
 }
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
index bb9d0265..a37bc56d 100644
--- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -892,6 +892,46 @@
   PlaceAndCaptureBox(kFrameSize, gfx::Size(100, 200), 1.0, 0.);
 }
 
+// Verifies that setDefaultBackgroundColorOverride changes the background color
+// of a page that does not specify one.
+IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest,
+                       SetDefaultBackgroundColorOverride) {
+  if (base::SysInfo::IsLowEndDevice())
+    return;
+
+  shell()->LoadURL(GURL("about:blank"));
+  WaitForLoadStop(shell()->web_contents());
+  Attach();
+
+  // Override background to blue.
+  std::unique_ptr<base::DictionaryValue> color(new base::DictionaryValue());
+  color->SetInteger("r", 0x00);
+  color->SetInteger("g", 0x00);
+  color->SetInteger("b", 0xff);
+  color->SetDouble("a", 1.0);
+  std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue());
+  params->Set("color", std::move(color));
+  SendCommand("Emulation.setDefaultBackgroundColorOverride", std::move(params));
+
+  SkBitmap expected_bitmap;
+  // We compare against the actual physical backing size rather than the
+  // view size, because the view size is stored adjusted for DPI and only in
+  // integer precision.
+  gfx::Size view_size = static_cast<RenderWidgetHostViewBase*>(
+                            shell()->web_contents()->GetRenderWidgetHostView())
+                            ->GetPhysicalBackingSize();
+  expected_bitmap.allocN32Pixels(view_size.width(), view_size.height());
+  expected_bitmap.eraseColor(SkColorSetRGB(0x00, 0x00, 0xff));
+  CaptureScreenshotAndCompareTo(expected_bitmap, ENCODING_PNG, true);
+
+  // Tests that resetting Emulation.setDefaultBackgroundColorOverride
+  // clears the background color override.
+  SendCommand("Emulation.setDefaultBackgroundColorOverride",
+              std::make_unique<base::DictionaryValue>());
+  expected_bitmap.eraseColor(SK_ColorWHITE);
+  CaptureScreenshotAndCompareTo(expected_bitmap, ENCODING_PNG, true);
+}
+
 // Verifies that setDefaultBackgroundColor and captureScreenshot support a
 // transparent background, and that setDeviceMetricsOverride doesn't affect it.
 
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc
index 58ba7dd..5e4d137 100644
--- a/content/browser/loader/resource_loader.cc
+++ b/content/browser/loader/resource_loader.cc
@@ -102,15 +102,13 @@
     request->GetLoadTimingInfo(&response->head.load_timing);
 
   if (request->ssl_info().cert.get()) {
-    response->head.has_major_certificate_errors =
-        net::IsCertStatusError(request->ssl_info().cert_status) &&
-        !net::IsCertStatusMinorError(request->ssl_info().cert_status);
+    response->head.cert_status = request->ssl_info().cert_status;
     response->head.is_legacy_symantec_cert =
-        !response->head.has_major_certificate_errors &&
+        (!net::IsCertStatusError(response->head.cert_status) ||
+         net::IsCertStatusMinorError(response->head.cert_status)) &&
         net::IsLegacySymantecCert(request->ssl_info().public_key_hashes);
     response->head.cert_validity_start =
         request->ssl_info().cert->valid_start();
-    response->head.cert_status = request->ssl_info().cert_status;
     if (info->ShouldReportRawHeaders()) {
       // Only pass these members when the network panel of the DevTools is open,
       // i.e. ShouldReportRawHeaders() is set. These data are used to populate
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 3d38968..12c1074 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2218,8 +2218,9 @@
   if (crash_report_mode == CrashReportMode::GENERATE_CRASH_DUMP) {
     // Set crash keys to understand renderer kills related to site isolation.
     auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
-    base::debug::SetCrashKeyValue("killed_process_origin_lock",
-                                  policy->GetOriginLock(GetID()).spec());
+    base::debug::SetCrashKeyString(bad_message::GetKilledProcessOriginLockKey(),
+                                   policy->GetOriginLock(GetID()).spec());
+
     std::string site_isolation_mode;
     if (SiteIsolationPolicy::UseDedicatedProcessesForAllSites())
       site_isolation_mode += "spp ";
@@ -2227,7 +2228,10 @@
       site_isolation_mode += "tdi ";
     if (SiteIsolationPolicy::AreIsolatedOriginsEnabled())
       site_isolation_mode += "io ";
-    base::debug::SetCrashKeyValue("site_isolation_mode", site_isolation_mode);
+
+    static auto* isolation_mode_key = base::debug::AllocateCrashKeyString(
+        "site_isolation_mode", base::debug::CrashKeySize::Size32);
+    base::debug::SetCrashKeyString(isolation_mode_key, site_isolation_mode);
 
     // Report a crash, since none will be generated by the killed renderer.
     base::debug::DumpWithoutCrashing();
@@ -3574,9 +3578,10 @@
                                              browser_context, site_url)) {
     ChildProcessSecurityPolicyImpl* policy =
         ChildProcessSecurityPolicyImpl::GetInstance();
-    base::debug::SetCrashKeyValue("requested_site_url", site_url.spec());
-    base::debug::SetCrashKeyValue(
-        "killed_process_origin_lock",
+    base::debug::SetCrashKeyString(bad_message::GetRequestedSiteURLKey(),
+                                   site_url.spec());
+    base::debug::SetCrashKeyString(
+        bad_message::GetKilledProcessOriginLockKey(),
         policy->GetOriginLock(render_process_host->GetID()).spec());
     CHECK(false) << "Unsuitable process reused for site " << site_url;
   }
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
index 827e674c..61b61fc5 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -566,9 +566,10 @@
           HAS_WRONG_LOCK:
         // We should never attempt to reassign a different origin lock to a
         // process.
-        base::debug::SetCrashKeyValue("requested_site_url", site_.spec());
-        base::debug::SetCrashKeyValue(
-            "killed_process_origin_lock",
+        base::debug::SetCrashKeyString(bad_message::GetRequestedSiteURLKey(),
+                                       site_.spec());
+        base::debug::SetCrashKeyString(
+            bad_message::GetKilledProcessOriginLockKey(),
             policy->GetOriginLock(process_->GetID()).spec());
         CHECK(false) << "Trying to lock a process to " << site_
                      << " but the process is already locked to "
@@ -586,9 +587,10 @@
     // If the site that we've just committed doesn't require a dedicated
     // process, make sure we aren't putting it in a process for a site that
     // does.
-    base::debug::SetCrashKeyValue("requested_site_url", site_.spec());
-    base::debug::SetCrashKeyValue(
-        "killed_process_origin_lock",
+    base::debug::SetCrashKeyString(bad_message::GetRequestedSiteURLKey(),
+                                   site_.spec());
+    base::debug::SetCrashKeyString(
+        bad_message::GetKilledProcessOriginLockKey(),
         policy->GetOriginLock(process_->GetID()).spec());
     CHECK_EQ(lock_state,
              ChildProcessSecurityPolicyImpl::CheckOriginLockResult::NO_LOCK)
diff --git a/content/browser/webauth/cbor/cbor_binary.h b/content/browser/webauth/cbor/cbor_binary.h
new file mode 100644
index 0000000..14a182d
--- /dev/null
+++ b/content/browser/webauth/cbor/cbor_binary.h
@@ -0,0 +1,35 @@
+// Copyright 2017 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 <stdint.h>
+
+#ifndef CONTENT_BROWSER_WEBAUTH_CBOR_CBOR_BINARY_H_
+#define CONTENT_BROWSER_WEBAUTH_CBOR_CBOR_BINARY_H_
+
+namespace content {
+namespace impl {
+
+// Mask selecting the low-order 5 bits of the "initial byte", which is where
+// the additional information is encoded.
+static constexpr uint8_t kAdditionalInformationMask = 0x1F;
+// Mask selecting the high-order 3 bits of the "initial byte", which indicates
+// the major type of the encoded value.
+static constexpr uint8_t kMajorTypeMask = 0xE0;
+// Indicates the number of bits the "initial byte" needs to be shifted to the
+// right after applying |kMajorTypeMask| to produce the major type in the
+// lowermost bits.
+static constexpr uint8_t kMajorTypeBitShift = 5u;
+// Indicates the integer is in the following byte.
+static constexpr uint8_t kAdditionalInformation1Byte = 24u;
+// Indicates the integer is in the next 2 bytes.
+static constexpr uint8_t kAdditionalInformation2Bytes = 25u;
+// Indicates the integer is in the next 4 bytes.
+static constexpr uint8_t kAdditionalInformation4Bytes = 26u;
+// Indicates the integer is in the next 8 bytes.
+static constexpr uint8_t kAdditionalInformation8Bytes = 27u;
+
+}  // namespace impl
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_WEBAUTH_CBOR_CBOR_BINARY_H_
diff --git a/content/browser/webauth/cbor/cbor_reader.cc b/content/browser/webauth/cbor/cbor_reader.cc
new file mode 100644
index 0000000..654f249
--- /dev/null
+++ b/content/browser/webauth/cbor/cbor_reader.cc
@@ -0,0 +1,286 @@
+// Copyright 2017 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/webauth/cbor/cbor_reader.h"
+
+#include <math.h>
+#include "base/numerics/safe_conversions.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "content/browser/webauth/cbor/cbor_binary.h"
+
+namespace content {
+
+namespace {
+
+CBORValue::Type GetMajorType(uint8_t initial_data_byte) {
+  return static_cast<CBORValue::Type>(
+      (initial_data_byte & impl::kMajorTypeMask) >> impl::kMajorTypeBitShift);
+}
+
+uint8_t GetAdditionalInfo(uint8_t initial_data_byte) {
+  return initial_data_byte & impl::kAdditionalInformationMask;
+}
+
+// Error messages that correspond to each of the error codes.
+const char kNoError[] = "Successfully deserialized to a CBOR value.";
+const char kUnsupportedMajorType[] = "Unsupported major type.";
+const char kUnknownAdditionalInfo[] =
+    "Unknown additional info format in the first byte.";
+const char kIncompleteCBORData[] =
+    "Prematurely terminated CBOR data byte array.";
+const char kIncorrectMapKeyType[] =
+    "Map keys other than utf-8 encoded strings are not allowed.";
+const char kTooMuchNesting[] = "Too much nesting.";
+const char kInvalidUTF8[] = "String encoding other than utf8 are not allowed.";
+const char kExtraneousData[] = "Trailing data bytes are not allowed.";
+const char kDuplicateKey[] = "Duplicate map keys are not allowed.";
+const char kMapKeyOutOfOrder[] =
+    "Map keys must be sorted by byte length and then by byte-wise lexical "
+    "order.";
+const char kNonMinimalCBOREncoding[] =
+    "Unsigned integers must be encoded with minimum number of bytes.";
+
+}  // namespace
+
+CBORReader::CBORReader(Bytes::const_iterator it, Bytes::const_iterator end)
+    : it_(it), end_(end), error_code_(DecoderError::NO_ERROR) {}
+CBORReader::~CBORReader() {}
+
+// static
+base::Optional<CBORValue> CBORReader::Read(const Bytes& data,
+                                           DecoderError* error_code_out,
+                                           int max_nesting_level) {
+  CBORReader reader(data.begin(), data.end());
+  base::Optional<CBORValue> decoded_cbor = reader.DecodeCBOR(max_nesting_level);
+
+  if (decoded_cbor.has_value())
+    reader.CheckExtraneousData();
+  if (error_code_out)
+    *error_code_out = reader.GetErrorCode();
+
+  if (reader.GetErrorCode() != DecoderError::NO_ERROR)
+    return base::nullopt;
+  return decoded_cbor;
+}
+
+base::Optional<CBORValue> CBORReader::DecodeCBOR(int max_nesting_level) {
+  if (max_nesting_level < 0 || max_nesting_level > kCBORMaxDepth) {
+    error_code_ = DecoderError::TOO_MUCH_NESTING;
+    return base::nullopt;
+  }
+
+  if (!CanConsume(1)) {
+    error_code_ = DecoderError::INCOMPLETE_CBOR_DATA;
+    return base::nullopt;
+  }
+
+  const uint8_t initial_byte = *it_++;
+  const auto major_type = GetMajorType(initial_byte);
+  const uint8_t additional_info = GetAdditionalInfo(initial_byte);
+
+  uint64_t length;
+  if (!ReadUnsignedInt(additional_info, &length))
+    return base::nullopt;
+
+  switch (major_type) {
+    case CBORValue::Type::UNSIGNED:
+      return CBORValue(length);
+    case CBORValue::Type::BYTE_STRING:
+      return ReadBytes(length);
+    case CBORValue::Type::STRING:
+      return ReadString(length);
+    case CBORValue::Type::ARRAY:
+      return ReadCBORArray(length, max_nesting_level);
+    case CBORValue::Type::MAP:
+      return ReadCBORMap(length, max_nesting_level);
+    case CBORValue::Type::NONE:
+      break;
+  }
+
+  error_code_ = DecoderError::UNSUPPORTED_MAJOR_TYPE;
+  return base::nullopt;
+}
+
+bool CBORReader::ReadUnsignedInt(int additional_info, uint64_t* length) {
+  uint8_t additional_bytes = 0;
+  if (additional_info < 24) {
+    *length = additional_info;
+    return true;
+  } else if (additional_info == 24) {
+    additional_bytes = 1;
+  } else if (additional_info == 25) {
+    additional_bytes = 2;
+  } else if (additional_info == 26) {
+    additional_bytes = 4;
+  } else if (additional_info == 27) {
+    additional_bytes = 8;
+  } else {
+    error_code_ = DecoderError::UNKNOWN_ADDITIONAL_INFO;
+    return false;
+  }
+
+  if (!CanConsume(additional_bytes)) {
+    error_code_ = DecoderError::INCOMPLETE_CBOR_DATA;
+    return false;
+  }
+
+  uint64_t int_data = 0;
+  for (uint8_t i = 0; i < additional_bytes; ++i) {
+    int_data <<= 8;
+    int_data |= *it_++;
+  }
+
+  *length = int_data;
+  return CheckUintEncodedByteLength(additional_bytes, int_data);
+}
+
+base::Optional<CBORValue> CBORReader::ReadString(uint64_t num_bytes) {
+  if (!CanConsume(num_bytes)) {
+    error_code_ = DecoderError::INCOMPLETE_CBOR_DATA;
+    return base::nullopt;
+  }
+
+  std::string cbor_string(it_, it_ + num_bytes);
+  it_ += num_bytes;
+
+  return HasValidUTF8Format(cbor_string)
+             ? base::make_optional<CBORValue>(CBORValue(std::move(cbor_string)))
+             : base::nullopt;
+}
+
+base::Optional<CBORValue> CBORReader::ReadBytes(uint64_t num_bytes) {
+  if (!CanConsume(num_bytes)) {
+    error_code_ = DecoderError::INCOMPLETE_CBOR_DATA;
+    return base::nullopt;
+  }
+
+  Bytes cbor_byte_string(it_, it_ + num_bytes);
+  it_ += num_bytes;
+
+  return CBORValue(std::move(cbor_byte_string));
+}
+
+base::Optional<CBORValue> CBORReader::ReadCBORArray(uint64_t length,
+                                                    int max_nesting_level) {
+  CBORValue::ArrayValue cbor_array;
+  while (length-- > 0) {
+    base::Optional<CBORValue> cbor_element = DecodeCBOR(max_nesting_level - 1);
+    if (!cbor_element.has_value())
+      return base::nullopt;
+    cbor_array.push_back(std::move(cbor_element.value()));
+  }
+  return CBORValue(std::move(cbor_array));
+}
+
+base::Optional<CBORValue> CBORReader::ReadCBORMap(uint64_t length,
+                                                  int max_nesting_level) {
+  CBORValue::MapValue cbor_map;
+  while (length-- > 0) {
+    base::Optional<CBORValue> key = DecodeCBOR(max_nesting_level - 1);
+    base::Optional<CBORValue> value = DecodeCBOR(max_nesting_level - 1);
+    if (!key.has_value() || !value.has_value())
+      return base::nullopt;
+    if (key.value().type() != CBORValue::Type::STRING) {
+      error_code_ = DecoderError::INCORRECT_MAP_KEY_TYPE;
+      return base::nullopt;
+    }
+
+    if (!CheckDuplicateKey(key.value().GetString(), &cbor_map) ||
+        !CheckOutOfOrderKey(key.value().GetString(), &cbor_map)) {
+      return base::nullopt;
+    }
+
+    cbor_map.insert_or_assign(key.value().GetString(),
+                              std::move(value.value()));
+  }
+  return CBORValue(std::move(cbor_map));
+}
+
+bool CBORReader::CanConsume(uint64_t bytes) {
+  if (base::checked_cast<uint64_t>(std::distance(it_, end_)) >= bytes) {
+    return true;
+  }
+  error_code_ = DecoderError::INCOMPLETE_CBOR_DATA;
+  return false;
+}
+
+bool CBORReader::CheckUintEncodedByteLength(uint8_t additional_bytes,
+                                            uint64_t uint_data) {
+  if ((additional_bytes == 1 && uint_data < 24) ||
+      uint_data <= (1ULL << 8 * (additional_bytes >> 1)) - 1) {
+    error_code_ = DecoderError::NON_MINIMAL_CBOR_ENCODING;
+    return false;
+  }
+  return true;
+}
+
+void CBORReader::CheckExtraneousData() {
+  if (it_ != end_)
+    error_code_ = DecoderError::EXTRANEOUS_DATA;
+}
+
+bool CBORReader::CheckDuplicateKey(const std::string& new_key,
+                                   CBORValue::MapValue* map) {
+  if (base::ContainsKey(*map, new_key)) {
+    error_code_ = DecoderError::DUPLICATE_KEY;
+    return false;
+  }
+  return true;
+}
+
+bool CBORReader::HasValidUTF8Format(const std::string& string_data) {
+  if (!base::IsStringUTF8(string_data.data())) {
+    error_code_ = DecoderError::INVALID_UTF8;
+    return false;
+  }
+  return true;
+}
+
+bool CBORReader::CheckOutOfOrderKey(const std::string& new_key,
+                                    CBORValue::MapValue* map) {
+  auto comparator = map->key_comp();
+  if (!map->empty() && comparator(new_key, map->rbegin()->first)) {
+    error_code_ = DecoderError::OUT_OF_ORDER_KEY;
+    return false;
+  }
+  return true;
+}
+
+CBORReader::DecoderError CBORReader::GetErrorCode() {
+  return error_code_;
+}
+
+// static
+const char* CBORReader::ErrorCodeToString(DecoderError error) {
+  switch (error) {
+    case DecoderError::NO_ERROR:
+      return kNoError;
+    case DecoderError::UNSUPPORTED_MAJOR_TYPE:
+      return kUnsupportedMajorType;
+    case DecoderError::UNKNOWN_ADDITIONAL_INFO:
+      return kUnknownAdditionalInfo;
+    case DecoderError::INCOMPLETE_CBOR_DATA:
+      return kIncompleteCBORData;
+    case DecoderError::INCORRECT_MAP_KEY_TYPE:
+      return kIncorrectMapKeyType;
+    case DecoderError::TOO_MUCH_NESTING:
+      return kTooMuchNesting;
+    case DecoderError::INVALID_UTF8:
+      return kInvalidUTF8;
+    case DecoderError::EXTRANEOUS_DATA:
+      return kExtraneousData;
+    case DecoderError::DUPLICATE_KEY:
+      return kDuplicateKey;
+    case DecoderError::OUT_OF_ORDER_KEY:
+      return kMapKeyOutOfOrder;
+    case DecoderError::NON_MINIMAL_CBOR_ENCODING:
+      return kNonMinimalCBOREncoding;
+    default:
+      NOTREACHED();
+      return "Unknown error code.";
+  }
+}
+
+}  // namespace content
diff --git a/content/browser/webauth/cbor/cbor_reader.h b/content/browser/webauth/cbor/cbor_reader.h
new file mode 100644
index 0000000..46552097
--- /dev/null
+++ b/content/browser/webauth/cbor/cbor_reader.h
@@ -0,0 +1,107 @@
+// Copyright 2017 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_CBOR_CBOR_READER_H_
+#define CONTENT_BROWSER_WEBAUTH_CBOR_CBOR_READER_H_
+
+#include <stddef.h>
+#include <string>
+#include <vector>
+
+#include "base/optional.h"
+#include "content/browser/webauth/cbor/cbor_values.h"
+#include "content/common/content_export.h"
+
+// Concise Binary Object Representation (CBOR) decoder as defined by
+// https://tools.ietf.org/html/rfc7049. This decoder only accepts canonical
+// CBOR as defined by section 3.9.
+// Supported:
+//  * Major types:
+//     * 0: Unsigned integers, up to 64-bit.
+//     * 2: Byte strings.
+//     * 3: UTF-8 strings.
+//     * 4: Definite-length arrays.
+//     * 5: Definite-length maps.
+//
+// Requirements for canonical CBOR representation:
+//  - Duplicate keys for map are not allowed.
+//  - Keys for map must be sorted first by length and then by byte-wise
+//    lexical order.
+//
+// Known limitations and interpretations of the RFC:
+//  - Does not support negative integers, floating point numbers, indefinite
+//    data streams and tagging.
+//  - Non-character codepoint are not supported for Major type 3.
+//  - Incomplete CBOR data items are treated as syntax errors.
+//  - Trailing data bytes are treated as errors.
+//  - Unknown additional information formats are treated as syntax errors.
+//  - Callers can decode CBOR values with at most 16 nested depth layer. More
+//    strict restrictions on nesting layer size of CBOR values can be enforced
+//    by setting |max_nesting_level|.
+
+namespace content {
+
+class CONTENT_EXPORT CBORReader {
+ public:
+  using Bytes = std::vector<uint8_t>;
+
+  enum class DecoderError {
+    NO_ERROR = 0,
+    UNSUPPORTED_MAJOR_TYPE,
+    UNKNOWN_ADDITIONAL_INFO,
+    INCOMPLETE_CBOR_DATA,
+    INCORRECT_MAP_KEY_TYPE,
+    TOO_MUCH_NESTING,
+    INVALID_UTF8,
+    EXTRANEOUS_DATA,
+    DUPLICATE_KEY,
+    OUT_OF_ORDER_KEY,
+    NON_MINIMAL_CBOR_ENCODING,
+  };
+
+  // CBOR nested depth sufficient for most use cases.
+  static const int kCBORMaxDepth = 16;
+
+  ~CBORReader();
+
+  // Reads and parses |input_data| into a CBORValue. If any one of the syntax
+  // formats is violated -including unknown additional info and incomplete
+  // CBOR data- then an empty optional is returned. Optional |error_code_out|
+  // can be provided by the caller to obtain additional information about
+  // decoding failures.
+  static base::Optional<CBORValue> Read(const Bytes& input_data,
+                                        DecoderError* error_code_out = nullptr,
+                                        int max_nesting_level = kCBORMaxDepth);
+
+  // Translates errors to human-readable error messages.
+  static const char* ErrorCodeToString(DecoderError error_code);
+
+ private:
+  CBORReader(Bytes::const_iterator it, const Bytes::const_iterator end);
+  base::Optional<CBORValue> DecodeCBOR(int max_nesting_level);
+  bool ReadUnsignedInt(int additional_info, uint64_t* length);
+  base::Optional<CBORValue> ReadBytes(uint64_t num_bytes);
+  base::Optional<CBORValue> ReadString(uint64_t num_bytes);
+  base::Optional<CBORValue> ReadCBORArray(uint64_t length,
+                                          int max_nesting_level);
+  base::Optional<CBORValue> ReadCBORMap(uint64_t length, int max_nesting_level);
+  bool CanConsume(uint64_t bytes);
+  void CheckExtraneousData();
+  bool CheckDuplicateKey(const std::string& new_key, CBORValue::MapValue* map);
+  bool HasValidUTF8Format(const std::string& string_data);
+  bool CheckOutOfOrderKey(const std::string& new_key, CBORValue::MapValue* map);
+  bool CheckUintEncodedByteLength(uint8_t additional_bytes, uint64_t uint_data);
+
+  DecoderError GetErrorCode();
+
+  Bytes::const_iterator it_;
+  const Bytes::const_iterator end_;
+  DecoderError error_code_;
+
+  DISALLOW_COPY_AND_ASSIGN(CBORReader);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_WEBAUTH_CBOR_CBOR_READER_H_
diff --git a/content/browser/webauth/cbor/cbor_reader_unittest.cc b/content/browser/webauth/cbor/cbor_reader_unittest.cc
new file mode 100644
index 0000000..947137e
--- /dev/null
+++ b/content/browser/webauth/cbor/cbor_reader_unittest.cc
@@ -0,0 +1,530 @@
+// Copyright 2017 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/webauth/cbor/cbor_reader.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+/* Leveraging RFC 7049 examples from
+   https://github.com/cbor/test-vectors/blob/master/appendix_a.json. */
+namespace content {
+
+TEST(CBORReaderTest, TestReadUint) {
+  typedef struct {
+    const uint64_t value;
+    const std::vector<uint8_t> cbor_data;
+  } UintTestCase;
+
+  static const UintTestCase kUintTestCases[] = {
+      {0, {0x00}},
+      {1, {0x01}},
+      {10, {0x0a}},
+      {23, {0x17}},
+      {24, {0x18, 0x18}},
+      {25, {0x18, 0x19}},
+      {100, {0x18, 0x64}},
+      {1000, {0x19, 0x03, 0xe8}},
+      {1000000, {0x1a, 0x00, 0x0f, 0x42, 0x40}},
+      {0xFFFFFFFF, {0x1a, 0xff, 0xff, 0xff, 0xff}},
+  };
+
+  int test_case_index = 0;
+  for (const UintTestCase& test_case : kUintTestCases) {
+    testing::Message scope_message;
+    scope_message << "testing uint at index : " << test_case_index++;
+    SCOPED_TRACE(scope_message);
+
+    base::Optional<CBORValue> cbor = CBORReader::Read(test_case.cbor_data);
+    ASSERT_TRUE(cbor.has_value());
+    ASSERT_EQ(cbor.value().type(), CBORValue::Type::UNSIGNED);
+    EXPECT_EQ(cbor.value().GetUnsigned(), test_case.value);
+  }
+}
+
+TEST(CBORReaderTest, TestUintEncodedWithNonMinimumByteLength) {
+  static const std::vector<std::vector<uint8_t>> non_minimal_uint_encodings = {
+      // Uint 23 encoded with 1 byte.
+      {0x18, 0x17},
+      // Uint 255 encoded with 2 bytes.
+      {0x19, 0x00, 0xff},
+      // Uint 65535 encoded with 4 byte.
+      {0x1a, 0x00, 0x00, 0xff, 0xff},
+      // Uint 4294967295 encoded with 8 byte.
+      {0x1b, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}};
+
+  int test_case_index = 0;
+  CBORReader::DecoderError error_code;
+  for (const auto non_minimal_uint : non_minimal_uint_encodings) {
+    testing::Message scope_message;
+    scope_message << "testing element at index " << test_case_index++;
+    SCOPED_TRACE(scope_message);
+
+    base::Optional<CBORValue> cbor =
+        CBORReader::Read(non_minimal_uint, &error_code);
+    EXPECT_FALSE(cbor.has_value());
+    EXPECT_EQ(error_code, CBORReader::DecoderError::NON_MINIMAL_CBOR_ENCODING);
+  }
+}
+
+TEST(CBORReaderTest, TestReadBytes) {
+  typedef struct {
+    const std::vector<uint8_t> value;
+    const std::vector<uint8_t> cbor_data;
+  } ByteTestCase;
+
+  static const ByteTestCase kByteStringTestCases[] = {
+      // clang-format off
+      {{}, {0x40}},
+      {{0x01, 0x02, 0x03, 0x04},{0x44, 0x01, 0x02, 0x03, 0x04}},
+      // clang-format on
+  };
+
+  int element_index = 0;
+  for (const ByteTestCase& test_case : kByteStringTestCases) {
+    testing::Message scope_message;
+    scope_message << "testing string test case at : " << element_index++;
+    SCOPED_TRACE(scope_message);
+
+    base::Optional<CBORValue> cbor = CBORReader::Read(test_case.cbor_data);
+    ASSERT_TRUE(cbor.has_value());
+    ASSERT_EQ(cbor.value().type(), CBORValue::Type::BYTE_STRING);
+    EXPECT_EQ(cbor.value().GetBytestring(), test_case.value);
+  }
+}
+
+TEST(CBORReaderTest, TestReadString) {
+  typedef struct {
+    const std::string value;
+    const std::vector<uint8_t> cbor_data;
+  } StringTestCase;
+
+  static const StringTestCase kStringTestCases[] = {
+      {"", {0x60}},
+      {"a", {0x61, 0x61}},
+      {"IETF", {0x64, 0x49, 0x45, 0x54, 0x46}},
+      {"\"\\", {0x62, 0x22, 0x5c}},
+      {"\xc3\xbc", {0x62, 0xc3, 0xbc}},
+      {"\xe6\xb0\xb4", {0x63, 0xe6, 0xb0, 0xb4}},
+      {"\xf0\x90\x85\x91", {0x64, 0xf0, 0x90, 0x85, 0x91}},
+  };
+
+  for (const StringTestCase& test_case : kStringTestCases) {
+    testing::Message scope_message;
+    scope_message << "testing string value : "
+                  << base::StringPrintf("%s", test_case.value.data());
+    SCOPED_TRACE(scope_message);
+
+    base::Optional<CBORValue> cbor = CBORReader::Read(test_case.cbor_data);
+    ASSERT_TRUE(cbor.has_value());
+    ASSERT_EQ(cbor.value().type(), CBORValue::Type::STRING);
+    EXPECT_EQ(cbor.value().GetString(), test_case.value);
+  }
+}
+
+TEST(CBORReaderTest, TestReadArray) {
+  static const std::vector<uint8_t> kArrayTestCaseCbor = {
+      // clang-format off
+      0x98, 0x19,  // array of 25 elements
+        0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+        0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+        0x18, 0x18, 0x19,
+      // clang-format on
+  };
+
+  base::Optional<CBORValue> cbor = CBORReader::Read(kArrayTestCaseCbor);
+  ASSERT_TRUE(cbor.has_value());
+  CBORValue cbor_array = std::move(cbor.value());
+  ASSERT_EQ(cbor_array.type(), CBORValue::Type::ARRAY);
+  ASSERT_THAT(cbor_array.GetArray(), testing::SizeIs(25));
+
+  std::vector<CBORValue> array;
+  for (int i = 0; i < 25; i++) {
+    testing::Message scope_message;
+    scope_message << "testing array element at index " << i;
+    SCOPED_TRACE(scope_message);
+
+    ASSERT_EQ(cbor_array.GetArray()[i].type(), CBORValue::Type::UNSIGNED);
+    EXPECT_EQ(cbor_array.GetArray()[i].GetUnsigned(),
+              static_cast<uint64_t>(i + 1));
+  }
+}
+
+TEST(CBORReaderTest, TestReadMapWithMapValue) {
+  static const std::vector<uint8_t> kMapTestCaseCbor = {
+      // clang-format off
+      0xa3,  // map of 3 pairs:
+        0x60,  // ""
+        0x61, 0x2e,  // "."
+
+        0x61, 0x62,  // "b"
+        0x61, 0x42,  // "B"
+
+        0x62, 0x61, 0x61,  // "aa"
+        0x62, 0x41, 0x41,  // "AA"
+      // clang-format on
+  };
+
+  base::Optional<CBORValue> cbor = CBORReader::Read(kMapTestCaseCbor);
+  ASSERT_TRUE(cbor.has_value());
+  CBORValue cbor_val = std::move(cbor.value());
+  ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP);
+  ASSERT_EQ(cbor_val.GetMap().size(), 3u);
+
+  ASSERT_EQ(cbor_val.GetMap().count(""), 1u);
+  ASSERT_EQ(cbor_val.GetMap().find("")->second.type(), CBORValue::Type::STRING);
+  EXPECT_EQ(cbor_val.GetMap().find("")->second.GetString(), ".");
+
+  ASSERT_EQ(cbor_val.GetMap().count("b"), 1u);
+  ASSERT_EQ(cbor_val.GetMap().find("b")->second.type(),
+            CBORValue::Type::STRING);
+  EXPECT_EQ(cbor_val.GetMap().find("b")->second.GetString(), "B");
+
+  ASSERT_EQ(cbor_val.GetMap().count("aa"), 1u);
+  ASSERT_EQ(cbor_val.GetMap().find("aa")->second.type(),
+            CBORValue::Type::STRING);
+  EXPECT_EQ(cbor_val.GetMap().find("aa")->second.GetString(), "AA");
+}
+
+TEST(CBORReaderTest, TestReadMapWithArray) {
+  static const std::vector<uint8_t> kMapArrayTestCaseCbor = {
+      // clang-format off
+      0xa2,  // map of 2 pairs
+        0x61, 0x61,  // "a"
+        0x01,
+
+        0x61, 0x62,  // "b"
+        0x82,        // array with 2 elements
+          0x02,
+          0x03,
+      // clang-format on
+  };
+
+  base::Optional<CBORValue> cbor = CBORReader::Read(kMapArrayTestCaseCbor);
+  ASSERT_TRUE(cbor.has_value());
+  CBORValue cbor_val = std::move(cbor.value());
+  ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP);
+  ASSERT_EQ(cbor_val.GetMap().size(), 2u);
+
+  ASSERT_EQ(cbor_val.GetMap().count("a"), 1u);
+  ASSERT_EQ(cbor_val.GetMap().find("a")->second.type(),
+            CBORValue::Type::UNSIGNED);
+  EXPECT_EQ(cbor_val.GetMap().find("a")->second.GetUnsigned(), 1u);
+
+  ASSERT_EQ(cbor_val.GetMap().count("b"), 1u);
+  ASSERT_EQ(cbor_val.GetMap().find("b")->second.type(), CBORValue::Type::ARRAY);
+
+  CBORValue nested_array = cbor_val.GetMap().find("b")->second.Clone();
+  ASSERT_EQ(nested_array.GetArray().size(), 2u);
+  for (int i = 0; i < 2; i++) {
+    ASSERT_THAT(nested_array.GetArray()[i].type(), CBORValue::Type::UNSIGNED);
+    EXPECT_EQ(nested_array.GetArray()[i].GetUnsigned(),
+              static_cast<uint64_t>(i + 2));
+  }
+}
+
+TEST(CBORReaderTest, TestReadNestedMap) {
+  static const std::vector<uint8_t> kNestedMapTestCase = {
+      // clang-format off
+      0xa2,  // map of 2 pairs
+        0x61, 0x61,  // "a"
+        0x01,
+
+        0x61, 0x62,  // "b"
+        0xa2,        // map of 2 pairs
+          0x61, 0x63,  // "c"
+          0x02,
+
+          0x61, 0x64,  // "d"
+          0x03,
+      // clang-format on
+  };
+
+  base::Optional<CBORValue> cbor = CBORReader::Read(kNestedMapTestCase);
+  ASSERT_TRUE(cbor.has_value());
+  CBORValue cbor_val = std::move(cbor.value());
+  ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP);
+  ASSERT_EQ(cbor_val.GetMap().size(), 2u);
+  ASSERT_EQ(cbor_val.GetMap().count("a"), 1u);
+  ASSERT_EQ(cbor_val.GetMap().find("a")->second.type(),
+            CBORValue::Type::UNSIGNED);
+  EXPECT_EQ(cbor_val.GetMap().find("a")->second.GetUnsigned(), 1u);
+
+  ASSERT_EQ(cbor_val.GetMap().count("b"), 1u);
+  CBORValue nested_map = cbor_val.GetMap().find("b")->second.Clone();
+  ASSERT_EQ(nested_map.type(), CBORValue::Type::MAP);
+  ASSERT_EQ(nested_map.GetMap().size(), 2u);
+
+  ASSERT_EQ(nested_map.GetMap().count("c"), 1u);
+  ASSERT_EQ(nested_map.GetMap().find("c")->second.type(),
+            CBORValue::Type::UNSIGNED);
+  EXPECT_EQ(nested_map.GetMap().find("c")->second.GetUnsigned(), 2u);
+
+  ASSERT_EQ(nested_map.GetMap().count("d"), 1u);
+  ASSERT_EQ(nested_map.GetMap().find("d")->second.type(),
+            CBORValue::Type::UNSIGNED);
+  EXPECT_EQ(nested_map.GetMap().find("d")->second.GetUnsigned(), 3u);
+}
+
+TEST(CBORReaderTest, TestIncompleteCBORDataError) {
+  static const std::vector<std::vector<uint8_t>> incomplete_cbor_list = {
+      // Additional info byte corresponds to unsigned int that corresponds
+      // to 2 additional bytes. But actual data encoded  in one byte.
+      {0x19, 0x03},
+      // CBOR bytestring of length 3 encoded with additional info of length 4.
+      {0x44, 0x01, 0x02, 0x03},
+      // CBOR string data "IETF" of length 4 encoded with additional info of
+      // length 5.
+      {0x65, 0x49, 0x45, 0x54, 0x46},
+      // CBOR array of length 1 encoded with additional info of length 2.
+      {0x82, 0x02},
+      // CBOR map with single key value pair encoded with additional info of
+      // length 2.
+      {0xa2, 0x61, 0x61, 0x01},
+  };
+
+  int test_element_index = 0;
+  for (auto incomplete_data : incomplete_cbor_list) {
+    testing::Message scope_message;
+    scope_message << "testing incomplete data at index : "
+                  << test_element_index++;
+    SCOPED_TRACE(scope_message);
+
+    CBORReader::DecoderError error_code;
+    base::Optional<CBORValue> cbor =
+        CBORReader::Read(incomplete_data, &error_code);
+    EXPECT_FALSE(cbor.has_value());
+    EXPECT_EQ(error_code, CBORReader::DecoderError::INCOMPLETE_CBOR_DATA);
+  }
+}
+
+// While RFC 7049 allows CBOR map keys with all types, current decoder only
+// supports string type for CBOR map keys. Checks for error when decoding CBOR
+// map with key other than UTF-8 string.
+TEST(CBORReaderTest, TestUnsupportedMapKeyFormatError) {
+  static const std::vector<uint8_t> kMapWithUintKey = {
+      // clang-format off
+      0xa2,        // map of 2 pairs
+        0x01,      // key : 1
+        0x02,      // value : 2
+
+        0x61, 0x64,  // key : "d"
+        0x03,        // value : 3
+      // clang-format on
+  };
+
+  CBORReader::DecoderError error_code;
+  base::Optional<CBORValue> cbor =
+      CBORReader::Read(kMapWithUintKey, &error_code);
+  EXPECT_FALSE(cbor.has_value());
+  EXPECT_EQ(error_code, CBORReader::DecoderError::INCORRECT_MAP_KEY_TYPE);
+}
+
+TEST(CBORReaderTest, TestUnknownAdditionalInfoError) {
+  static const std::vector<std::vector<uint8_t>> kUnknownAdditionalInfoList = {
+      // "IETF" encoded with major type 3 and additional info of 28.
+      {0x7C, 0x49, 0x45, 0x54, 0x46},
+      // "\"\\" encoded with major type 3 and additional info of 29.
+      {0x7D, 0x22, 0x5c},
+      // "\xc3\xbc" encoded with major type 3 and additional info of 30.
+      {0x7E, 0xc3, 0xbc},
+      // "\xe6\xb0\xb4" encoded with major type 3 and additional info of 31.
+      {0x7F, 0xe6, 0xb0, 0xb4}};
+
+  int test_element_index = 0;
+  for (auto incorrect_cbor : kUnknownAdditionalInfoList) {
+    testing::Message scope_message;
+    scope_message << "testing data : " << test_element_index++;
+    SCOPED_TRACE(scope_message);
+
+    CBORReader::DecoderError error_code;
+    base::Optional<CBORValue> cbor =
+        CBORReader::Read(incorrect_cbor, &error_code);
+    EXPECT_FALSE(cbor.has_value());
+    EXPECT_EQ(error_code, CBORReader::DecoderError::UNKNOWN_ADDITIONAL_INFO);
+  }
+}
+
+TEST(CBORReaderTest, TestTooMuchNestingError) {
+  static const std::vector<std::vector<uint8_t>> kZeroDepthCBORList = {
+      // Unsigned int with value 100.
+      {0x18, 0x64},
+      // CBOR bytestring of length 4.
+      {0x44, 0x01, 0x02, 0x03, 0x04},
+      // CBOR string of corresponding to "IETF.
+      {0x64, 0x49, 0x45, 0x54, 0x46},
+      // Empty CBOR array.
+      {0x80},
+      // Empty CBOR Map
+      {0xa0},
+  };
+
+  int test_element_index = 0;
+  for (auto zero_depth_data : kZeroDepthCBORList) {
+    testing::Message scope_message;
+    scope_message << "testing zero nested data : " << test_element_index++;
+    SCOPED_TRACE(scope_message);
+
+    CBORReader::DecoderError error_code;
+    base::Optional<CBORValue> cbor =
+        CBORReader::Read(zero_depth_data, &error_code, 0);
+    EXPECT_TRUE(cbor.has_value());
+    EXPECT_EQ(error_code, CBORReader::DecoderError::NO_ERROR);
+  }
+
+  // Corresponds to a CBOR structure with a nesting depth of 2:
+  //      {"a": 1,
+  //       "b": [2, 3]}
+  static const std::vector<uint8_t> kNestedCBORData = {
+      // clang-format off
+      0xa2,  // map of 2 pairs
+        0x61, 0x61,  // "a"
+        0x01,
+
+        0x61, 0x62,  // "b"
+        0x82,        // array with 2 elements
+          0x02,
+          0x03,
+      // clang-format on
+  };
+
+  CBORReader::DecoderError error_code;
+  base::Optional<CBORValue> cbor_single_layer_max =
+      CBORReader::Read(kNestedCBORData, &error_code, 1);
+  EXPECT_FALSE(cbor_single_layer_max.has_value());
+  EXPECT_EQ(error_code, CBORReader::DecoderError::TOO_MUCH_NESTING);
+
+  base::Optional<CBORValue> cbor_double_layer_max =
+      CBORReader::Read(kNestedCBORData, &error_code, 2);
+  EXPECT_TRUE(cbor_double_layer_max.has_value());
+  EXPECT_EQ(error_code, CBORReader::DecoderError::NO_ERROR);
+}
+
+TEST(CBORReaderTest, TestOutOfOrderKeyError) {
+  static const std::vector<uint8_t> kMapWithUnsortedKey = {
+      // clang-format off
+      0xa6,  // map of 6 pairs:
+        0x60,  // ""
+        0x61, 0x2e,  // "."
+
+        0x61, 0x62,  // "b"
+        0x61, 0x42,  // "B"
+
+        0x61, 0x63,  // "c"
+        0x61, 0x43,  // "C"
+
+        0x61, 0x64,  // "d"
+        0x61, 0x44,  // "D"
+
+        0x61, 0x61,  // "a" (Out of order key)
+        0x61, 0x45,  // "E"
+
+        0x62, 0x61, 0x61,  // "aa"
+        0x62, 0x41, 0x41,  // "AA"
+      // clang-format on
+  };
+
+  CBORReader::DecoderError error_code;
+
+  base::Optional<CBORValue> cbor =
+      CBORReader::Read(kMapWithUnsortedKey, &error_code);
+  EXPECT_FALSE(cbor.has_value());
+  EXPECT_EQ(error_code, CBORReader::DecoderError::OUT_OF_ORDER_KEY);
+}
+
+TEST(CBORReaderTest, TestDuplicateKeyError) {
+  static const std::vector<uint8_t> kMapWithDuplicateKey = {
+      // clang-format off
+      0xa6,  // map of 6 pairs:
+        0x60,  // ""
+        0x61, 0x2e,  // "."
+
+        0x61, 0x62,  // "b"
+        0x61, 0x42,  // "B"
+
+        0x61, 0x62,  // "b" (Duplicate key)
+        0x61, 0x43,  // "C"
+
+        0x61, 0x64,  // "d"
+        0x61, 0x44,  // "D"
+
+        0x61, 0x65,  // "e"
+        0x61, 0x44,  // "D"
+
+        0x62, 0x61, 0x61,  // "aa"
+        0x62, 0x41, 0x41,  // "AA"
+      // clang-format on
+  };
+
+  CBORReader::DecoderError error_code;
+
+  base::Optional<CBORValue> cbor =
+      CBORReader::Read(kMapWithDuplicateKey, &error_code);
+  EXPECT_FALSE(cbor.has_value());
+  EXPECT_EQ(error_code, CBORReader::DecoderError::DUPLICATE_KEY);
+}
+
+// Leveraging Markus Kuhn’s UTF-8 decoder stress test. See
+// http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt for details.
+TEST(CBORReaderTest, TestIncorrectStringEncodingError) {
+  static const std::vector<std::vector<uint8_t>> utf8_character_encodings = {
+      // Corresponds to utf8 encoding of "퟿" (section 2.3.1 of stress test).
+      {0x63, 0xED, 0x9F, 0xBF},
+      // Corresponds to utf8 encoding of "" (section 2.3.2 of stress test).
+      {0x63, 0xEE, 0x80, 0x80},
+      // Corresponds to utf8 encoding of "�"  (section 2.3.3 of stress test).
+      {0x63, 0xEF, 0xBF, 0xBD},
+  };
+
+  int test_element_index = 0;
+  CBORReader::DecoderError error_code;
+  for (auto cbor_byte : utf8_character_encodings) {
+    testing::Message scope_message;
+    scope_message << "testing cbor data utf8 encoding : "
+                  << test_element_index++;
+    SCOPED_TRACE(scope_message);
+
+    base::Optional<CBORValue> correctly_encoded_cbor =
+        CBORReader::Read(cbor_byte, &error_code);
+    EXPECT_TRUE(correctly_encoded_cbor.has_value());
+    EXPECT_EQ(error_code, CBORReader::DecoderError::NO_ERROR);
+  }
+
+  // Incorrect UTF8 encoding referenced by section 3.5.3 of the stress test.
+  std::vector<uint8_t> impossible_utf_byte{0x64, 0xfe, 0xfe, 0xff, 0xff};
+  base::Optional<CBORValue> incorrectly_encoded_cbor =
+      CBORReader::Read(impossible_utf_byte, &error_code);
+  EXPECT_FALSE(incorrectly_encoded_cbor.has_value());
+  EXPECT_EQ(error_code, CBORReader::DecoderError::INVALID_UTF8);
+}
+
+TEST(CBORReaderTest, TestExtraneousCBORDataError) {
+  static const std::vector<std::vector<uint8_t>> zero_padded_cbor_list = {
+      // 1 extra byte after a 2-byte unsigned int.
+      {0x19, 0x03, 0x05, 0x00},
+      // 1 extra byte after a 4-byte cbor byte array.
+      {0x44, 0x01, 0x02, 0x03, 0x04, 0x00},
+      // 1 extra byte after a 4-byte string.
+      {0x64, 0x49, 0x45, 0x54, 0x46, 0x00},
+      // 1 extra byte after CBOR array of length 2.
+      {0x82, 0x01, 0x02, 0x00},
+      // 1 extra key value pair after CBOR map of size 2.
+      {0xa1, 0x61, 0x63, 0x02, 0x61, 0x64, 0x03},
+  };
+
+  int test_element_index = 0;
+  for (auto extraneous_cbor_data : zero_padded_cbor_list) {
+    testing::Message scope_message;
+    scope_message << "testing cbor extraneous data : " << test_element_index++;
+    SCOPED_TRACE(scope_message);
+
+    CBORReader::DecoderError error_code;
+    base::Optional<CBORValue> cbor =
+        CBORReader::Read(extraneous_cbor_data, &error_code);
+    EXPECT_FALSE(cbor.has_value());
+    EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA);
+  }
+}
+
+}  // namespace content
diff --git a/content/browser/webauth/cbor/cbor_values.cc b/content/browser/webauth/cbor/cbor_values.cc
index 1b3494c9..790a23f 100644
--- a/content/browser/webauth/cbor/cbor_values.cc
+++ b/content/browser/webauth/cbor/cbor_values.cc
@@ -20,12 +20,10 @@
 CBORValue::CBORValue(Type type) : type_(type) {
   // Initialize with the default value.
   switch (type_) {
-    case Type::NONE:
-      return;
     case Type::UNSIGNED:
       unsigned_value_ = 0;
       return;
-    case Type::BYTESTRING:
+    case Type::BYTE_STRING:
       new (&bytestring_value_) BinaryValue();
       return;
     case Type::STRING:
@@ -37,17 +35,20 @@
     case Type::MAP:
       new (&map_value_) MapValue();
       return;
+    case Type::NONE:
+      return;
   }
+  NOTREACHED();
 }
 
 CBORValue::CBORValue(uint64_t in_unsigned)
     : type_(Type::UNSIGNED), unsigned_value_(in_unsigned) {}
 
 CBORValue::CBORValue(const BinaryValue& in_bytes)
-    : type_(Type::BYTESTRING), bytestring_value_(in_bytes) {}
+    : type_(Type::BYTE_STRING), bytestring_value_(in_bytes) {}
 
 CBORValue::CBORValue(BinaryValue&& in_bytes) noexcept
-    : type_(Type::BYTESTRING), bytestring_value_(std::move(in_bytes)) {}
+    : type_(Type::BYTE_STRING), bytestring_value_(std::move(in_bytes)) {}
 
 CBORValue::CBORValue(const char* in_string)
     : CBORValue(std::string(in_string)) {}
@@ -96,7 +97,7 @@
       return CBORValue();
     case Type::UNSIGNED:
       return CBORValue(unsigned_value_);
-    case Type::BYTESTRING:
+    case Type::BYTE_STRING:
       return CBORValue(bytestring_value_);
     case Type::STRING:
       return CBORValue(string_value_);
@@ -139,12 +140,10 @@
   type_ = that.type_;
 
   switch (type_) {
-    case Type::NONE:
-      return;
     case Type::UNSIGNED:
       unsigned_value_ = that.unsigned_value_;
       return;
-    case Type::BYTESTRING:
+    case Type::BYTE_STRING:
       new (&bytestring_value_) BinaryValue(std::move(that.bytestring_value_));
       return;
     case Type::STRING:
@@ -156,17 +155,15 @@
     case Type::MAP:
       new (&map_value_) MapValue(std::move(that.map_value_));
       return;
+    case Type::NONE:
+      return;
   }
+  NOTREACHED();
 }
 
 void CBORValue::InternalCleanup() {
   switch (type_) {
-    case Type::NONE:
-    case Type::UNSIGNED:
-      // Nothing to do
-      break;
-      ;
-    case Type::BYTESTRING:
+    case Type::BYTE_STRING:
       bytestring_value_.~BinaryValue();
       break;
     case Type::STRING:
@@ -178,6 +175,9 @@
     case Type::MAP:
       map_value_.~MapValue();
       break;
+    case Type::NONE:
+    case Type::UNSIGNED:
+      break;
   }
   type_ = Type::NONE;
 }
diff --git a/content/browser/webauth/cbor/cbor_values.h b/content/browser/webauth/cbor/cbor_values.h
index 6fe9e14..3e993d90 100644
--- a/content/browser/webauth/cbor/cbor_values.h
+++ b/content/browser/webauth/cbor/cbor_values.h
@@ -5,7 +5,6 @@
 #ifndef CONTENT_BROWSER_WEBAUTH_CBOR_CBOR_VALUES_H_
 #define CONTENT_BROWSER_WEBAUTH_CBOR_CBOR_VALUES_H_
 
-#include <stdint.h>
 #include <string>
 #include <tuple>
 #include <vector>
@@ -60,12 +59,12 @@
   using MapValue = base::flat_map<std::string, CBORValue, CTAPLess>;
 
   enum class Type {
-    NONE,
-    UNSIGNED,
-    BYTESTRING,
-    STRING,
-    ARRAY,
-    MAP,
+    UNSIGNED = 0,
+    BYTE_STRING = 2,
+    STRING = 3,
+    ARRAY = 4,
+    MAP = 5,
+    NONE = -1,
   };
 
   CBORValue(CBORValue&& that) noexcept;
@@ -102,7 +101,7 @@
   bool is_type(Type type) const { return type == type_; }
   bool is_none() const { return type() == Type::NONE; }
   bool is_unsigned() const { return type() == Type::UNSIGNED; }
-  bool is_bytestring() const { return type() == Type::BYTESTRING; }
+  bool is_bytestring() const { return type() == Type::BYTE_STRING; }
   bool is_string() const { return type() == Type::STRING; }
   bool is_array() const { return type() == Type::ARRAY; }
   bool is_map() const { return type() == Type::MAP; }
diff --git a/content/browser/webauth/cbor/cbor_values_unittest.cc b/content/browser/webauth/cbor/cbor_values_unittest.cc
index a0df69ad..7500850 100644
--- a/content/browser/webauth/cbor/cbor_values_unittest.cc
+++ b/content/browser/webauth/cbor/cbor_values_unittest.cc
@@ -59,7 +59,7 @@
 
 TEST(CBORValuesTest, ConstructBytestring) {
   CBORValue value(CBORValue::BinaryValue({0xF, 0x0, 0x0, 0xB, 0xA, 0x2}));
-  EXPECT_EQ(CBORValue::Type::BYTESTRING, value.type());
+  EXPECT_EQ(CBORValue::Type::BYTE_STRING, value.type());
   EXPECT_EQ(CBORValue::BinaryValue({0xF, 0x0, 0x0, 0xB, 0xA, 0x2}),
             value.GetBytestring());
 }
@@ -215,13 +215,13 @@
   const CBORValue::BinaryValue bytes({0xF, 0x0, 0x0, 0xB, 0xA, 0x2});
   CBORValue value(bytes);
   CBORValue moved_value(std::move(value));
-  EXPECT_EQ(CBORValue::Type::BYTESTRING, moved_value.type());
+  EXPECT_EQ(CBORValue::Type::BYTE_STRING, moved_value.type());
   EXPECT_EQ(bytes, moved_value.GetBytestring());
 
   CBORValue blank;
 
   blank = CBORValue(bytes);
-  EXPECT_EQ(CBORValue::Type::BYTESTRING, blank.type());
+  EXPECT_EQ(CBORValue::Type::BYTE_STRING, blank.type());
   EXPECT_EQ(bytes, blank.GetBytestring());
 }
 
@@ -267,4 +267,4 @@
   EXPECT_TRUE(test.GetUnsigned() == 1);
 }
 
-}  // namespace content
\ No newline at end of file
+}  // namespace content
diff --git a/content/browser/webauth/cbor/cbor_writer.cc b/content/browser/webauth/cbor/cbor_writer.cc
index 9ee55b21..514c38c 100644
--- a/content/browser/webauth/cbor/cbor_writer.cc
+++ b/content/browser/webauth/cbor/cbor_writer.cc
@@ -8,25 +8,10 @@
 
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_piece.h"
+#include "content/browser/webauth/cbor/cbor_binary.h"
 
 namespace content {
 
-namespace {
-
-// Mask selecting the last 5 bits  of the "initial byte" where
-// 'additional information is encoded.
-constexpr uint8_t kAdditionalInformationDataMask = 0x1F;
-// Indicates the integer is in the following byte.
-constexpr uint8_t kAdditionalInformation1Byte = 24u;
-// Indicates the integer is in the next 2 bytes.
-constexpr uint8_t kAdditionalInformation2Bytes = 25u;
-// Indicates the integer is in the next 4 bytes.
-constexpr uint8_t kAdditionalInformation4Bytes = 26u;
-// Indicates the integer is in the next 8 bytes.
-constexpr uint8_t kAdditionalInformation8Bytes = 27u;
-
-}  // namespace
-
 CBORWriter::~CBORWriter() {}
 
 // static
@@ -48,21 +33,21 @@
 
   switch (node.type()) {
     case CBORValue::Type::NONE: {
-      StartItem(CborMajorType::kByteString, 0);
+      StartItem(CBORValue::Type::BYTE_STRING, 0);
       return true;
     }
 
     // Represents unsigned integers.
     case CBORValue::Type::UNSIGNED: {
       uint64_t value = node.GetUnsigned();
-      StartItem(CborMajorType::kUnsigned, value);
+      StartItem(CBORValue::Type::UNSIGNED, value);
       return true;
     }
 
     // Represents a byte string.
-    case CBORValue::Type::BYTESTRING: {
+    case CBORValue::Type::BYTE_STRING: {
       const CBORValue::BinaryValue& bytes = node.GetBytestring();
-      StartItem(CborMajorType::kByteString,
+      StartItem(CBORValue::Type::BYTE_STRING,
                 base::strict_cast<uint64_t>(bytes.size()));
       // Add the bytes.
       encoded_cbor_->insert(encoded_cbor_->end(), bytes.begin(), bytes.end());
@@ -71,7 +56,7 @@
 
     case CBORValue::Type::STRING: {
       base::StringPiece string = node.GetString();
-      StartItem(CborMajorType::kString,
+      StartItem(CBORValue::Type::STRING,
                 base::strict_cast<uint64_t>(string.size()));
 
       // Add the characters.
@@ -82,7 +67,7 @@
     // Represents an array.
     case CBORValue::Type::ARRAY: {
       const CBORValue::ArrayValue& array = node.GetArray();
-      StartItem(CborMajorType::kArray, array.size());
+      StartItem(CBORValue::Type::ARRAY, array.size());
       for (const auto& value : array) {
         if (!EncodeCBOR(value, max_nesting_level - 1))
           return false;
@@ -93,7 +78,7 @@
     // Represents a map.
     case CBORValue::Type::MAP: {
       const CBORValue::MapValue& map = node.GetMap();
-      StartItem(CborMajorType::kMap, map.size());
+      StartItem(CBORValue::Type::MAP, map.size());
 
       for (const auto& value : map) {
         if (!EncodeCBOR(CBORValue(value.first), max_nesting_level - 1))
@@ -103,23 +88,25 @@
       }
       return true;
     }
+    default:
+      break;
   }
   NOTREACHED();
-  return true;
+  return false;
 }
 
-void CBORWriter::StartItem(CborMajorType type, uint64_t size) {
-  encoded_cbor_->push_back(
-      base::checked_cast<uint8_t>(static_cast<unsigned>(type) << 5));
+void CBORWriter::StartItem(CBORValue::Type type, uint64_t size) {
+  encoded_cbor_->push_back(base::checked_cast<uint8_t>(
+      static_cast<unsigned>(type) << impl::kMajorTypeBitShift));
   SetUint(size);
 }
 
 void CBORWriter::SetAdditionalInformation(uint8_t additional_information) {
   DCHECK(!encoded_cbor_->empty());
-  DCHECK_EQ(additional_information & kAdditionalInformationDataMask,
+  DCHECK_EQ(additional_information & impl::kAdditionalInformationMask,
             additional_information);
   encoded_cbor_->back() |=
-      (additional_information & kAdditionalInformationDataMask);
+      (additional_information & impl::kAdditionalInformationMask);
 }
 
 void CBORWriter::SetUint(uint64_t value) {
@@ -133,19 +120,19 @@
       SetAdditionalInformation(base::checked_cast<uint8_t>(value));
       break;
     case 1:
-      SetAdditionalInformation(kAdditionalInformation1Byte);
+      SetAdditionalInformation(impl::kAdditionalInformation1Byte);
       shift = 0;
       break;
     case 2:
-      SetAdditionalInformation(kAdditionalInformation2Bytes);
+      SetAdditionalInformation(impl::kAdditionalInformation2Bytes);
       shift = 1;
       break;
     case 4:
-      SetAdditionalInformation(kAdditionalInformation4Bytes);
+      SetAdditionalInformation(impl::kAdditionalInformation4Bytes);
       shift = 3;
       break;
     case 8:
-      SetAdditionalInformation(kAdditionalInformation8Bytes);
+      SetAdditionalInformation(impl::kAdditionalInformation8Bytes);
       shift = 7;
       break;
     default:
diff --git a/content/browser/webauth/cbor/cbor_writer.h b/content/browser/webauth/cbor/cbor_writer.h
index b8f40b3..8ea9651b 100644
--- a/content/browser/webauth/cbor/cbor_writer.h
+++ b/content/browser/webauth/cbor/cbor_writer.h
@@ -5,12 +5,12 @@
 #ifndef CONTENT_BROWSER_WEBAUTH_CBOR_CBOR_WRITER_H_
 #define CONTENT_BROWSER_WEBAUTH_CBOR_CBOR_WRITER_H_
 
-#include "content/browser/webauth/cbor/cbor_values.h"
-
+#include <stddef.h>
 #include <stdint.h>
 #include <vector>
 
 #include "base/optional.h"
+#include "content/browser/webauth/cbor/cbor_values.h"
 #include "content/common/content_export.h"
 
 // A basic Concise Binary Object Representation (CBOR) encoder as defined by
@@ -48,23 +48,13 @@
 // Current implementation of CBORWriter encoder meets all the requirements of
 // canonical CBOR.
 
-enum class CborMajorType {
-  kUnsigned = 0,    // Unsigned integer.
-  kNegative = 1,    // Negative integer. Unsupported by this implementation.
-  kByteString = 2,  // Byte string.
-  kString = 3,      // String.
-  kArray = 4,       // Array.
-  kMap = 5,         // Map.
-};
-
 namespace content {
-namespace {
-// Default that should be sufficiently large for most use cases.
-constexpr size_t kDefaultMaxNestingDepth = 16;
-}  // namespace
 
 class CONTENT_EXPORT CBORWriter {
  public:
+  // Default that should be sufficiently large for most use cases.
+  static constexpr size_t kDefaultMaxNestingDepth = 16;
+
   ~CBORWriter();
 
   // Returns the CBOR byte string representation of |node|, unless its nesting
@@ -85,7 +75,7 @@
   bool EncodeCBOR(const CBORValue& node, int max_nesting_level);
 
   // Encodes the type and size of the data being added.
-  void StartItem(CborMajorType type, uint64_t size);
+  void StartItem(CBORValue::Type type, uint64_t size);
 
   // Encodes the additional information for the data.
   void SetAdditionalInformation(uint8_t additional_information);
diff --git a/content/common/resource_messages.h b/content/common/resource_messages.h
index d8a3bf4..920ffb8 100644
--- a/content/common/resource_messages.h
+++ b/content/common/resource_messages.h
@@ -140,7 +140,6 @@
   IPC_STRUCT_TRAITS_MEMBER(headers)
   IPC_STRUCT_TRAITS_MEMBER(mime_type)
   IPC_STRUCT_TRAITS_MEMBER(charset)
-  IPC_STRUCT_TRAITS_MEMBER(has_major_certificate_errors)
   IPC_STRUCT_TRAITS_MEMBER(is_legacy_symantec_cert)
   IPC_STRUCT_TRAITS_MEMBER(cert_validity_start)
   IPC_STRUCT_TRAITS_MEMBER(content_length)
diff --git a/content/common/site_isolation_policy.cc b/content/common/site_isolation_policy.cc
index 0d277b0..773000b 100644
--- a/content/common/site_isolation_policy.cc
+++ b/content/common/site_isolation_policy.cc
@@ -9,6 +9,7 @@
 #include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/metrics/field_trial_params.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/strings/string_split.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
@@ -44,8 +45,13 @@
   std::string cmdline_arg =
       base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
           switches::kIsolateOrigins);
-  if (!cmdline_arg.empty())
-    return ParseIsolatedOrigins(cmdline_arg);
+  if (!cmdline_arg.empty()) {
+    std::vector<url::Origin> cmdline_origins =
+        ParseIsolatedOrigins(cmdline_arg);
+    UMA_HISTOGRAM_COUNTS_1000("SiteIsolation.IsolateOrigins.Size",
+                              cmdline_origins.size());
+    return cmdline_origins;
+  }
 
   if (base::FeatureList::IsEnabled(features::kIsolateOrigins)) {
     std::string field_trial_arg = base::GetFieldTrialParamValueByFeature(
diff --git a/content/network/url_loader.cc b/content/network/url_loader.cc
index 536cec49..57bc54d 100644
--- a/content/network/url_loader.cc
+++ b/content/network/url_loader.cc
@@ -60,11 +60,9 @@
     request->GetLoadTimingInfo(&response->head.load_timing);
 
   if (request->ssl_info().cert.get()) {
-    response->head.has_major_certificate_errors =
-        net::IsCertStatusError(request->ssl_info().cert_status) &&
-        !net::IsCertStatusMinorError(request->ssl_info().cert_status);
     response->head.is_legacy_symantec_cert =
-        !response->head.has_major_certificate_errors &&
+        (!net::IsCertStatusError(response->head.cert_status) ||
+         net::IsCertStatusMinorError(response->head.cert_status)) &&
         net::IsLegacySymantecCert(request->ssl_info().public_key_hashes);
     response->head.cert_validity_start =
         request->ssl_info().cert->valid_start();
diff --git a/content/public/common/resource_response.cc b/content/public/common/resource_response.cc
index e3e2a664..a26e5f59 100644
--- a/content/public/common/resource_response.cc
+++ b/content/public/common/resource_response.cc
@@ -18,8 +18,6 @@
   }
   new_response->head.mime_type = head.mime_type;
   new_response->head.charset = head.charset;
-  new_response->head.has_major_certificate_errors =
-      head.has_major_certificate_errors;
   new_response->head.is_legacy_symantec_cert = head.is_legacy_symantec_cert;
   new_response->head.cert_validity_start = head.cert_validity_start;
   new_response->head.content_length = head.content_length;
diff --git a/content/public/common/resource_response_info.cc b/content/public/common/resource_response_info.cc
index 8de8efad..0f01d5df 100644
--- a/content/public/common/resource_response_info.cc
+++ b/content/public/common/resource_response_info.cc
@@ -11,8 +11,7 @@
 namespace content {
 
 ResourceResponseInfo::ResourceResponseInfo()
-    : has_major_certificate_errors(false),
-      is_legacy_symantec_cert(false),
+    : is_legacy_symantec_cert(false),
       content_length(-1),
       encoded_data_length(-1),
       encoded_body_length(-1),
diff --git a/content/public/common/resource_response_info.h b/content/public/common/resource_response_info.h
index 3740425..16f5a8a5 100644
--- a/content/public/common/resource_response_info.h
+++ b/content/public/common/resource_response_info.h
@@ -51,9 +51,6 @@
   // response's mime type.  This may be a derived value.
   std::string charset;
 
-  // True if the resource was loaded in spite of certificate errors.
-  bool has_major_certificate_errors;
-
   // True if the resource was loaded with an otherwise-valid legacy Symantec
   // certificate which will be distrusted in future.
   bool is_legacy_symantec_cert;
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc
index 7801b9a..32a6c7c 100644
--- a/content/renderer/loader/web_url_loader_impl.cc
+++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -1118,7 +1118,9 @@
   response->SetMIMEType(WebString::FromUTF8(info.mime_type));
   response->SetTextEncodingName(WebString::FromUTF8(info.charset));
   response->SetExpectedContentLength(info.content_length);
-  response->SetHasMajorCertificateErrors(info.has_major_certificate_errors);
+  response->SetHasMajorCertificateErrors(
+      net::IsCertStatusError(info.cert_status) &&
+      !net::IsCertStatusMinorError(info.cert_status));
   response->SetIsLegacySymantecCert(info.is_legacy_symantec_cert);
   response->SetCertValidityStart(info.cert_validity_start);
   response->SetAppCacheID(info.appcache_id);
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index c1b60819..fa85893 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1452,6 +1452,7 @@
     "../browser/web_contents/web_contents_view_mac_unittest.mm",
     "../browser/web_contents/web_drag_dest_mac_unittest.mm",
     "../browser/web_contents/web_drag_source_mac_unittest.mm",
+    "../browser/webauth/cbor/cbor_reader_unittest.cc",
     "../browser/webauth/cbor/cbor_values_unittest.cc",
     "../browser/webauth/cbor/cbor_writer_unittest.cc",
     "../browser/websockets/websocket_manager_unittest.cc",
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor0 b/content/test/data/fuzzer_corpus/cbor_data/cbor0
new file mode 100644
index 0000000..f76dd23
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor0
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor1 b/content/test/data/fuzzer_corpus/cbor_data/cbor1
new file mode 100644
index 0000000..6b2aaa76
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor1
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor10 b/content/test/data/fuzzer_corpus/cbor_data/cbor10
new file mode 100644
index 0000000..fed1e13
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor10
@@ -0,0 +1 @@
+ÿÿÿÿÿÿÿÿ
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor11 b/content/test/data/fuzzer_corpus/cbor_data/cbor11
new file mode 100644
index 0000000..00a3f0c
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor11
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor12 b/content/test/data/fuzzer_corpus/cbor_data/cbor12
new file mode 100644
index 0000000..077457a
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor12
@@ -0,0 +1 @@
+;ÿÿÿÿÿÿÿÿ
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor13 b/content/test/data/fuzzer_corpus/cbor_data/cbor13
new file mode 100644
index 0000000..b4818a3
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor13
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor14 b/content/test/data/fuzzer_corpus/cbor_data/cbor14
new file mode 100644
index 0000000..0519ecba
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor14
@@ -0,0 +1 @@
+ 
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor15 b/content/test/data/fuzzer_corpus/cbor_data/cbor15
new file mode 100644
index 0000000..e8a0f876
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor15
@@ -0,0 +1 @@
+)
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor16 b/content/test/data/fuzzer_corpus/cbor_data/cbor16
new file mode 100644
index 0000000..bfefdad18
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor16
@@ -0,0 +1 @@
+8c
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor17 b/content/test/data/fuzzer_corpus/cbor_data/cbor17
new file mode 100644
index 0000000..5de2555
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor17
@@ -0,0 +1 @@
+9ç
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor18 b/content/test/data/fuzzer_corpus/cbor_data/cbor18
new file mode 100644
index 0000000..e43ae5af
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor18
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor19 b/content/test/data/fuzzer_corpus/cbor_data/cbor19
new file mode 100644
index 0000000..6935671d
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor19
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor2 b/content/test/data/fuzzer_corpus/cbor_data/cbor2
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor2
@@ -0,0 +1 @@
+
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor20 b/content/test/data/fuzzer_corpus/cbor_data/cbor20
new file mode 100644
index 0000000..ed788bb
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor20
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor21 b/content/test/data/fuzzer_corpus/cbor_data/cbor21
new file mode 100644
index 0000000..fc9ea00
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor21
@@ -0,0 +1 @@
+û?ñ™™™™™š
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor22 b/content/test/data/fuzzer_corpus/cbor_data/cbor22
new file mode 100644
index 0000000..5ac3929d
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor22
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor23 b/content/test/data/fuzzer_corpus/cbor_data/cbor23
new file mode 100644
index 0000000..735f467
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor23
@@ -0,0 +1 @@
+ù{ÿ
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor24 b/content/test/data/fuzzer_corpus/cbor_data/cbor24
new file mode 100644
index 0000000..f36a086e
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor24
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor25 b/content/test/data/fuzzer_corpus/cbor_data/cbor25
new file mode 100644
index 0000000..16f33457
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor25
@@ -0,0 +1 @@
+úÿÿ
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor26 b/content/test/data/fuzzer_corpus/cbor_data/cbor26
new file mode 100644
index 0000000..8e79bf5
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor26
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor27 b/content/test/data/fuzzer_corpus/cbor_data/cbor27
new file mode 100644
index 0000000..8e144ff
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor27
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor28 b/content/test/data/fuzzer_corpus/cbor_data/cbor28
new file mode 100644
index 0000000..16b0d434
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor28
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor29 b/content/test/data/fuzzer_corpus/cbor_data/cbor29
new file mode 100644
index 0000000..e5b8b4d
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor29
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor3 b/content/test/data/fuzzer_corpus/cbor_data/cbor3
new file mode 100644
index 0000000..c96ab3cc
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor3
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor30 b/content/test/data/fuzzer_corpus/cbor_data/cbor30
new file mode 100644
index 0000000..815adc3
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor30
@@ -0,0 +1 @@
+ûÀffffff
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor31 b/content/test/data/fuzzer_corpus/cbor_data/cbor31
new file mode 100644
index 0000000..2b119eb
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor31
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor32 b/content/test/data/fuzzer_corpus/cbor_data/cbor32
new file mode 100644
index 0000000..d73f58e3
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor32
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor33 b/content/test/data/fuzzer_corpus/cbor_data/cbor33
new file mode 100644
index 0000000..7c2eb64
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor33
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor34 b/content/test/data/fuzzer_corpus/cbor_data/cbor34
new file mode 100644
index 0000000..82965f3
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor34
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor35 b/content/test/data/fuzzer_corpus/cbor_data/cbor35
new file mode 100644
index 0000000..2a9ccaec
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor35
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor36 b/content/test/data/fuzzer_corpus/cbor_data/cbor36
new file mode 100644
index 0000000..a9e0eeb
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor36
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor37 b/content/test/data/fuzzer_corpus/cbor_data/cbor37
new file mode 100644
index 0000000..c90d682d
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor37
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor38 b/content/test/data/fuzzer_corpus/cbor_data/cbor38
new file mode 100644
index 0000000..802efe1
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor38
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor39 b/content/test/data/fuzzer_corpus/cbor_data/cbor39
new file mode 100644
index 0000000..7a1f61c
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor39
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor4 b/content/test/data/fuzzer_corpus/cbor_data/cbor4
new file mode 100644
index 0000000..a1910b3f6
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor4
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor40 b/content/test/data/fuzzer_corpus/cbor_data/cbor40
new file mode 100644
index 0000000..3a6e607
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor40
@@ -0,0 +1 @@

\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor41 b/content/test/data/fuzzer_corpus/cbor_data/cbor41
new file mode 100644
index 0000000..bb7d13c
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor41
@@ -0,0 +1 @@

\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor42 b/content/test/data/fuzzer_corpus/cbor_data/cbor42
new file mode 100644
index 0000000..f7a8cad
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor42
@@ -0,0 +1 @@

\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor43 b/content/test/data/fuzzer_corpus/cbor_data/cbor43
new file mode 100644
index 0000000..009080e8
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor43
@@ -0,0 +1 @@

\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor44 b/content/test/data/fuzzer_corpus/cbor_data/cbor44
new file mode 100644
index 0000000..04f7b5b
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor44
@@ -0,0 +1 @@

\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor45 b/content/test/data/fuzzer_corpus/cbor_data/cbor45
new file mode 100644
index 0000000..33c4e29
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor45
@@ -0,0 +1 @@
+ø
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor46 b/content/test/data/fuzzer_corpus/cbor_data/cbor46
new file mode 100644
index 0000000..a61a462
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor46
@@ -0,0 +1 @@
+øÿ
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor47 b/content/test/data/fuzzer_corpus/cbor_data/cbor47
new file mode 100644
index 0000000..d2fbff8
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor47
@@ -0,0 +1 @@
+Àt2013-03-21T20:04:00Z
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor48 b/content/test/data/fuzzer_corpus/cbor_data/cbor48
new file mode 100644
index 0000000..4ecf9468
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor48
@@ -0,0 +1 @@
+ÁQKg°
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor49 b/content/test/data/fuzzer_corpus/cbor_data/cbor49
new file mode 100644
index 0000000..c5c79cf
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor49
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor5 b/content/test/data/fuzzer_corpus/cbor_data/cbor5
new file mode 100644
index 0000000..d4e634a
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor5
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor50 b/content/test/data/fuzzer_corpus/cbor_data/cbor50
new file mode 100644
index 0000000..7d0120d
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor50
@@ -0,0 +1 @@
+×D
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor51 b/content/test/data/fuzzer_corpus/cbor_data/cbor51
new file mode 100644
index 0000000..2784fd8
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor51
@@ -0,0 +1 @@
+ØEdIETF
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor52 b/content/test/data/fuzzer_corpus/cbor_data/cbor52
new file mode 100644
index 0000000..b7d2601a
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor52
@@ -0,0 +1 @@
+Ø vhttp://www.example.com
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor53 b/content/test/data/fuzzer_corpus/cbor_data/cbor53
new file mode 100644
index 0000000..b516b2c
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor53
@@ -0,0 +1 @@
+@
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor54 b/content/test/data/fuzzer_corpus/cbor_data/cbor54
new file mode 100644
index 0000000..352e89a
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor54
@@ -0,0 +1 @@
+D
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor55 b/content/test/data/fuzzer_corpus/cbor_data/cbor55
new file mode 100644
index 0000000..64845fb7
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor55
@@ -0,0 +1 @@
+`
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor56 b/content/test/data/fuzzer_corpus/cbor_data/cbor56
new file mode 100644
index 0000000..7ec9a4b
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor56
@@ -0,0 +1 @@
+aa
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor57 b/content/test/data/fuzzer_corpus/cbor_data/cbor57
new file mode 100644
index 0000000..743669b
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor57
@@ -0,0 +1 @@
+dIETF
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor58 b/content/test/data/fuzzer_corpus/cbor_data/cbor58
new file mode 100644
index 0000000..cce6615
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor58
@@ -0,0 +1 @@
+b"\
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor59 b/content/test/data/fuzzer_corpus/cbor_data/cbor59
new file mode 100644
index 0000000..9055a92
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor59
@@ -0,0 +1 @@
+bü
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor6 b/content/test/data/fuzzer_corpus/cbor_data/cbor6
new file mode 100644
index 0000000..3b5c907
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor6
@@ -0,0 +1 @@
+d
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor60 b/content/test/data/fuzzer_corpus/cbor_data/cbor60
new file mode 100644
index 0000000..0868c9a
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor60
@@ -0,0 +1 @@
+c水
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor61 b/content/test/data/fuzzer_corpus/cbor_data/cbor61
new file mode 100644
index 0000000..8ea48a0
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor61
@@ -0,0 +1 @@
+d𐅑
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor62 b/content/test/data/fuzzer_corpus/cbor_data/cbor62
new file mode 100644
index 0000000..5416677
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor62
@@ -0,0 +1 @@

\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor63 b/content/test/data/fuzzer_corpus/cbor_data/cbor63
new file mode 100644
index 0000000..4cdf6ce
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor63
@@ -0,0 +1 @@
+ƒ
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor64 b/content/test/data/fuzzer_corpus/cbor_data/cbor64
new file mode 100644
index 0000000..80fd3949
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor64
@@ -0,0 +1 @@
+ƒ‚‚
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor65 b/content/test/data/fuzzer_corpus/cbor_data/cbor65
new file mode 100644
index 0000000..b449584
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor65
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor66 b/content/test/data/fuzzer_corpus/cbor_data/cbor66
new file mode 100644
index 0000000..eea1bf0
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor66
@@ -0,0 +1 @@

\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor67 b/content/test/data/fuzzer_corpus/cbor_data/cbor67
new file mode 100644
index 0000000..abc169a8
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor67
@@ -0,0 +1 @@
+¢
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor68 b/content/test/data/fuzzer_corpus/cbor_data/cbor68
new file mode 100644
index 0000000..81e38473
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor68
@@ -0,0 +1 @@
+¢aaab‚
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor69 b/content/test/data/fuzzer_corpus/cbor_data/cbor69
new file mode 100644
index 0000000..9b1d08c
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor69
@@ -0,0 +1 @@
+‚aa¡abac
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor7 b/content/test/data/fuzzer_corpus/cbor_data/cbor7
new file mode 100644
index 0000000..fda74fd
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor7
@@ -0,0 +1 @@
+è
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor70 b/content/test/data/fuzzer_corpus/cbor_data/cbor70
new file mode 100644
index 0000000..05bb07fc
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor70
@@ -0,0 +1 @@
+¥aaaAabaBacaCadaDaeaE
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor71 b/content/test/data/fuzzer_corpus/cbor_data/cbor71
new file mode 100644
index 0000000..2681a857
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor71
@@ -0,0 +1 @@
+_BCÿ
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor72 b/content/test/data/fuzzer_corpus/cbor_data/cbor72
new file mode 100644
index 0000000..d0daf28
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor72
@@ -0,0 +1 @@
+estreadmingÿ
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor73 b/content/test/data/fuzzer_corpus/cbor_data/cbor73
new file mode 100644
index 0000000..422ce24
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor73
@@ -0,0 +1 @@
+Ÿÿ
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor74 b/content/test/data/fuzzer_corpus/cbor_data/cbor74
new file mode 100644
index 0000000..f67cd57
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor74
@@ -0,0 +1 @@
+Ÿ‚Ÿÿÿ
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor75 b/content/test/data/fuzzer_corpus/cbor_data/cbor75
new file mode 100644
index 0000000..78343ed
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor75
@@ -0,0 +1 @@
+Ÿ‚‚ÿ
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor76 b/content/test/data/fuzzer_corpus/cbor_data/cbor76
new file mode 100644
index 0000000..a0f1ea2
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor76
@@ -0,0 +1 @@
+ƒ‚Ÿÿ
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor77 b/content/test/data/fuzzer_corpus/cbor_data/cbor77
new file mode 100644
index 0000000..dbbf8e5
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor77
@@ -0,0 +1 @@
+ƒŸÿ‚
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor78 b/content/test/data/fuzzer_corpus/cbor_data/cbor78
new file mode 100644
index 0000000..81c9910
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor78
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor79 b/content/test/data/fuzzer_corpus/cbor_data/cbor79
new file mode 100644
index 0000000..018602c
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor79
@@ -0,0 +1 @@
+¿aaabŸÿÿ
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor8 b/content/test/data/fuzzer_corpus/cbor_data/cbor8
new file mode 100644
index 0000000..91628195
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor8
Binary files differ
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor80 b/content/test/data/fuzzer_corpus/cbor_data/cbor80
new file mode 100644
index 0000000..151c13e
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor80
@@ -0,0 +1 @@
+‚aa¿abacÿ
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor81 b/content/test/data/fuzzer_corpus/cbor_data/cbor81
new file mode 100644
index 0000000..c0f4fd5e
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor81
@@ -0,0 +1 @@
+¿cFunõcAmt!ÿ
\ No newline at end of file
diff --git a/content/test/data/fuzzer_corpus/cbor_data/cbor9 b/content/test/data/fuzzer_corpus/cbor_data/cbor9
new file mode 100644
index 0000000..4cdcd7c
--- /dev/null
+++ b/content/test/data/fuzzer_corpus/cbor_data/cbor9
Binary files differ
diff --git a/content/test/fuzzer/BUILD.gn b/content/test/fuzzer/BUILD.gn
index 3907fe2..3df1822 100644
--- a/content/test/fuzzer/BUILD.gn
+++ b/content/test/fuzzer/BUILD.gn
@@ -99,3 +99,15 @@
   ]
   testonly = true
 }
+
+fuzzer_test("cbor_reader_fuzzer") {
+  sources = [
+    "cbor_reader_fuzzer.cc",
+  ]
+  deps = [
+    ":fuzzer_support",
+    "//content/browser:for_content_tests",
+  ]
+  seed_corpus = "../data/fuzzer_corpus/cbor_data/"
+  libfuzzer_options = [ "max_len=65535" ]
+}
diff --git a/content/test/fuzzer/cbor_reader_fuzzer.cc b/content/test/fuzzer/cbor_reader_fuzzer.cc
new file mode 100644
index 0000000..f457236
--- /dev/null
+++ b/content/test/fuzzer/cbor_reader_fuzzer.cc
@@ -0,0 +1,32 @@
+// Copyright 2017 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 <stdint.h>
+#include <algorithm>
+
+#include "content/browser/webauth/cbor/cbor_reader.h"  // nogncheck
+#include "content/browser/webauth/cbor/cbor_writer.h"  // nogncheck
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  std::vector<uint8_t> input(data, data + size);
+  base::Optional<CBORValue> cbor = CBORReader::Read(input);
+
+  if (cbor.has_value()) {
+    base::Optional<std::vector<uint8_t>> serialized_cbor =
+        CBORWriter::Write(cbor.value());
+    CHECK(serialized_cbor.has_value());
+    if (serialized_cbor.has_value()) {
+      CHECK(serialized_cbor.value().size() == input.size());
+      CHECK(memcmp(serialized_cbor.value().data(), input.data(),
+                   input.size()) == 0);
+    }
+  }
+  return 0;
+}
+
+}  // namespace content
diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json
index 179ee65..36acacc 100644
--- a/gpu/config/gpu_driver_bug_list.json
+++ b/gpu/config/gpu_driver_bug_list.json
@@ -2747,6 +2747,18 @@
       "features": [
         "depth_stencil_renderbuffer_resize_emulation"
       ]
+    },
+    {
+      "id": 251,
+      "description": "Vivante GPUs shader cache breaks rendering",
+      "cr_bugs": [780498],
+      "os": {
+        "type": "android"
+      },
+      "gl_extensions": ".*GL_VIV_shader_binary.*",
+      "features": [
+        "disable_program_cache"
+      ]
     }
   ]
 }
diff --git a/ios/chrome/browser/feature_engagement/BUILD.gn b/ios/chrome/browser/feature_engagement/BUILD.gn
index f2c59f8..74abe1f 100644
--- a/ios/chrome/browser/feature_engagement/BUILD.gn
+++ b/ios/chrome/browser/feature_engagement/BUILD.gn
@@ -37,6 +37,7 @@
     "//base",
     "//base/test:test_support",
     "//components/feature_engagement/public",
+    "//components/feature_engagement/test:test_support",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/test/app:test_support",
     "//ios/chrome/test/earl_grey:test_support",
diff --git a/ios/chrome/browser/feature_engagement/feature_engagement_egtest.mm b/ios/chrome/browser/feature_engagement/feature_engagement_egtest.mm
index d85f578..1f1e8f4 100644
--- a/ios/chrome/browser/feature_engagement/feature_engagement_egtest.mm
+++ b/ios/chrome/browser/feature_engagement/feature_engagement_egtest.mm
@@ -10,9 +10,9 @@
 #include "components/feature_engagement/public/event_constants.h"
 #include "components/feature_engagement/public/feature_constants.h"
 #include "components/feature_engagement/public/tracker.h"
+#include "components/feature_engagement/test/test_tracker.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/feature_engagement/tracker_factory.h"
-#include "ios/chrome/browser/feature_engagement/tracker_factory_util.h"
 #import "ios/chrome/test/app/chrome_test_util.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
@@ -29,14 +29,17 @@
 // Help feature to be shown.
 const int kMinChromeOpensRequired = 5;
 
-// The timeout for the load of the feature engagement tracker.
-const NSTimeInterval kWaitForTrackerLoadTimeout = 10.0;
-
 // Matcher for the Reading List Text Badge.
 id<GREYMatcher> ReadingListTextBadge() {
   return grey_accessibilityID(@"kReadingListTextBadgeAccessibilityIdentifier");
 }
 
+// Create a test FeatureEngagementTracker.
+std::unique_ptr<KeyedService> CreateTestFeatureEngagementTracker(
+    web::BrowserState* context) {
+  return feature_engagement::CreateTestTracker();
+}
+
 // Simulate a Chrome Opened event for the Feature Engagement Tracker.
 void SimulateChromeOpenedEvent() {
   feature_engagement::TrackerFactory::GetForBrowserState(
@@ -50,16 +53,7 @@
       chrome_test_util::GetOriginalBrowserState();
 
   feature_engagement::TrackerFactory::GetInstance()->SetTestingFactory(
-      browserState, feature_engagement::CreateFeatureEngagementTracker);
-
-  feature_engagement::Tracker* tracker =
-      feature_engagement::TrackerFactory::GetForBrowserState(browserState);
-  GREYAssert(
-      testing::WaitUntilConditionOrTimeout(kWaitForTrackerLoadTimeout,
-                                           ^{
-                                             return tracker->IsInitialized();
-                                           }),
-      @"Engagement Tracker did not load before timeout.");
+      browserState, CreateTestFeatureEngagementTracker);
 }
 
 // Enables the Badged Reading List help to be triggered for |feature_list|.
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/device-mode/default-background-color-cleared-expected.html b/third_party/WebKit/LayoutTests/http/tests/devtools/device-mode/default-background-color-cleared-expected.html
deleted file mode 100644
index b38f0f9..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/device-mode/default-background-color-cleared-expected.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<html>
-<head>
-
-<style>
-html {
-    margin: 0;
-}
-</style>
-
-</head>
-<body>
-<p>
-Tests that resetting Emulation.setDefaultBackgroundColorOverride clears the background color override.
-</p>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/device-mode/default-background-color-cleared.html b/third_party/WebKit/LayoutTests/http/tests/devtools/device-mode/default-background-color-cleared.html
deleted file mode 100644
index 83c61c76..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/device-mode/default-background-color-cleared.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<html>
-<head>
-
-<style>
-html {
-    margin: 0;
-}
-</style>
-
-<script src="../../inspector/inspector-test.js"></script>
-
-<script>
-function test() {
-  TestRunner.evaluateInPage('testRunner.dumpAsTextWithPixelResults();', () => {
-    TestRunner.EmulationAgent.invoke_setDefaultBackgroundColorOverride({color: {r: 0x12, g: 0x34, b: 0x56, a: 1.0}})
-        .then(backgroundColorSet);
-  });
-
-  function backgroundColorSet(messageObject) {
-    if (messageObject[Protocol.Error])
-      InspectorTest.log('FAIL: unexpected exception: ' + messageObject[Protocol.Error]);
-    TestRunner.EmulationAgent.invoke_setDefaultBackgroundColorOverride({}).then(backgroundColorCleared);
-  }
-
-  function backgroundColorCleared(messageObject) {
-    if (messageObject[Protocol.Error])
-      InspectorTest.log('FAIL: unexpected exception: ' + messageObject[Protocol.Error]);
-
-    // Complete the test without closing the inspector, so that the override stays active for the picture.
-    TestRunner.flushResults();
-    TestRunner.evaluateInPage('testRunner.notifyDone();');
-  }
-}
-</script>
-
-</head>
-<body onload="runTest()">
-<p>
-Tests that resetting Emulation.setDefaultBackgroundColorOverride clears the background color override.
-</p>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/device-mode/default-background-color-expected.html b/third_party/WebKit/LayoutTests/http/tests/devtools/device-mode/default-background-color-expected.html
deleted file mode 100644
index 378f6f99..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/device-mode/default-background-color-expected.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<html>
-<head>
-
-<style>
-html {
-    margin: 0;
-    background-color: #123456;
-}
-</style>
-
-</head>
-<body>
-<p>
-Tests that Emulation.setDefaultBackgroundColorOverride changes the background color of a page that does not specify one.
-</p>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/device-mode/default-background-color.html b/third_party/WebKit/LayoutTests/http/tests/devtools/device-mode/default-background-color.html
deleted file mode 100644
index 49b8349..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/device-mode/default-background-color.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<html>
-<head>
-
-<style>
-html {
-    margin: 0;
-}
-</style>
-
-<script src="../../inspector/inspector-test.js"></script>
-
-<script>
-function test() {
-  TestRunner.evaluateInPage('testRunner.dumpAsTextWithPixelResults();', () => {
-    TestRunner.EmulationAgent.invoke_setDefaultBackgroundColorOverride({color: {r: 0x12, g: 0x34, b: 0x56, a: 1.0}})
-        .then(backgroundColorSet);
-  });
-
-  function backgroundColorSet(messageObject) {
-    if (messageObject[Protocol.Error])
-      InspectorTest.log('FAIL: unexpected exception: ' + messageObject[Protocol.Error]);
-
-    // Complete the test without closing the inspector, so that the override stays active for the picture.
-    TestRunner.flushResults();
-    TestRunner.evaluateInPage('testRunner.notifyDone();');
-  }
-}
-</script>
-
-</head>
-<body onload="runTest()">
-<p>
-Tests that Emulation.setDefaultBackgroundColorOverride changes the background color of a page that does not specify one.
-</p>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/resources/bluetooth/bluetooth-helpers.js b/third_party/WebKit/LayoutTests/resources/bluetooth/bluetooth-helpers.js
index c161f3c..9dd3c97 100644
--- a/third_party/WebKit/LayoutTests/resources/bluetooth/bluetooth-helpers.js
+++ b/third_party/WebKit/LayoutTests/resources/bluetooth/bluetooth-helpers.js
@@ -36,8 +36,8 @@
 function bluetooth_test(func, name, properties) {
   Promise.resolve()
     .then(() => {
-      // Chromium Testing API
-      if (window.chrome !== undefined) return loadChromiumResources();
+      // Load Chromium specific resources when Mojo bindings are detected.
+      if (Mojo) return loadChromiumResources();
     })
     .then(() => promise_test(func, name, properties));
 }
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index d2401d3..e6f4983e 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -81669,6 +81669,15 @@
   </summary>
 </histogram>
 
+<histogram name="SiteIsolation.IsolateOrigins.Size" units="origins">
+  <owner>alexmos@chromium.org</owner>
+  <summary>
+    The number of currently enabled isolated origins.  This includes origins
+    specified via the --isolate-origins command-line flag as well as those
+    configured via enterprise policy.  Recorded on browser startup.
+  </summary>
+</histogram>
+
 <histogram name="SiteIsolation.OutOfProcessIframes">
   <owner>nasko@chromium.org</owner>
   <summary>
diff --git a/ui/app_list/views/app_list_view_unittest.cc b/ui/app_list/views/app_list_view_unittest.cc
index 5511614..a53a169 100644
--- a/ui/app_list/views/app_list_view_unittest.cc
+++ b/ui/app_list/views/app_list_view_unittest.cc
@@ -538,7 +538,7 @@
 
   // Type something in search box to transition to HALF state and populate
   // fake search results.
-  search_box_view()->search_box()->InsertText(base::UTF8ToUTF16("test"));
+  search_box_view()->search_box()->InsertText(base::ASCIIToUTF16("test"));
   EXPECT_EQ(app_list_view()->app_list_state(), AppListViewState::HALF);
   constexpr int kTileResults = 3;
   constexpr int kListResults = 2;
@@ -695,7 +695,7 @@
 
   // Type something in search box to transition to HALF state and populate
   // fake search results.
-  search_box_view()->search_box()->InsertText(base::UTF8ToUTF16("test"));
+  search_box_view()->search_box()->InsertText(base::ASCIIToUTF16("test"));
   EXPECT_EQ(app_list_view()->app_list_state(), AppListViewState::HALF);
   constexpr int kTileResults = 3;
   constexpr int kListResults = 2;
@@ -778,7 +778,7 @@
 
   // Type something in search box to transition to HALF state and populate
   // fake search results.
-  search_box_view()->search_box()->InsertText(base::UTF8ToUTF16("test"));
+  search_box_view()->search_box()->InsertText(base::ASCIIToUTF16("test"));
   const int kTileResults = 3;
   const int kListResults = 2;
   SetUpSearchResults(kTileResults, kListResults, true);
@@ -865,7 +865,7 @@
 // SearchBoxTextfield.
 TEST_F(AppListViewFocusTest, SearchBoxSelectionCoversWholeQueryOnFocus) {
   Show();
-  search_box_view()->search_box()->InsertText(base::UTF8ToUTF16("test"));
+  search_box_view()->search_box()->InsertText(base::ASCIIToUTF16("test"));
   EXPECT_EQ(app_list_view()->app_list_state(), AppListViewState::HALF);
   constexpr int kListResults = 1;
   SetUpSearchResults(0, kListResults, false);
@@ -913,7 +913,7 @@
 // not focused.
 TEST_F(AppListViewFocusTest, CtrlASelectsAllTextInSearchbox) {
   Show();
-  search_box_view()->search_box()->InsertText(base::UTF8ToUTF16("test"));
+  search_box_view()->search_box()->InsertText(base::ASCIIToUTF16("test"));
   EXPECT_EQ(app_list_view()->app_list_state(), AppListViewState::HALF);
   constexpr int kTileResults = 3;
   constexpr int kListResults = 2;
@@ -944,14 +944,14 @@
             search_box_view()->search_box()->GetSelectedRange());
 }
 
-// Tests that the first search result's view is always selected after search
-// results are updated, but the focus is always on search box.
+// Tests that the first search result's view is selected after search results
+// are updated when the focus is on search box.
 TEST_F(AppListViewFocusTest, FirstResultSelectedAfterSearchResultsUpdated) {
   Show();
 
   // Type something in search box to transition to HALF state and populate
   // fake list results.
-  search_box_view()->search_box()->InsertText(base::UTF8ToUTF16("test"));
+  search_box_view()->search_box()->InsertText(base::ASCIIToUTF16("test"));
   const int kListResults = 2;
   SetUpSearchResults(0, kListResults, false);
   const views::View* results_container =
@@ -988,6 +988,56 @@
             contents_view()->search_results_page_view()->first_result_view());
 }
 
+// Tests that the first search result's view is not selected after search
+// results are updated when the focus is on one of the search results (This
+// happens when the user quickly hits Tab key after typing query and before
+// search results are updated for the new query).
+TEST_F(AppListViewFocusTest, FirstResultNotSelectedAfterQuicklyHittingTab) {
+  Show();
+
+  // Type something in search box to transition to HALF state and populate
+  // fake list results.
+  search_box_view()->search_box()->InsertText(base::ASCIIToUTF16("test1"));
+  const int kListResults = 2;
+  SetUpSearchResults(0, kListResults, false);
+  const views::View* results_container =
+      contents_view()
+          ->search_result_list_view_for_test()
+          ->results_container_for_test();
+  views::View* first_result_view =
+      contents_view()->search_results_page_view()->first_result_view();
+  EXPECT_EQ(search_box_view()->search_box(), focused_view());
+  EXPECT_EQ(results_container->child_at(0), first_result_view);
+  EXPECT_TRUE(static_cast<SearchResultView*>(first_result_view)->selected());
+
+  // Type something else.
+  search_box_view()->search_box()->InsertText(base::ASCIIToUTF16("test2"));
+  EXPECT_EQ(search_box_view()->search_box(), focused_view());
+
+  // Simulate hitting Tab key to move focus to the close button, then to the
+  // first result before search results are updated.
+  SimulateKeyPress(ui::VKEY_TAB, false);
+  EXPECT_EQ(search_box_view()->close_button(), focused_view());
+  SimulateKeyPress(ui::VKEY_TAB, false);
+  EXPECT_EQ(results_container->child_at(0), focused_view());
+  EXPECT_TRUE(static_cast<SearchResultView*>(first_result_view)->selected());
+
+  // Update search results, both list and tile results are populated.
+  const int kTileResults = 3;
+  SetUpSearchResults(kTileResults, kListResults, false);
+  const std::vector<SearchResultTileItemView*>& tile_views =
+      contents_view()
+          ->search_result_tile_item_list_view_for_test()
+          ->tile_views_for_test();
+  first_result_view =
+      contents_view()->search_results_page_view()->first_result_view();
+  EXPECT_EQ(results_container->child_at(0), focused_view());
+  EXPECT_EQ(tile_views[0], first_result_view);
+  EXPECT_FALSE(
+      static_cast<SearchResultTileItemView*>(first_result_view)->selected());
+  EXPECT_TRUE(static_cast<SearchResultView*>(focused_view())->selected());
+}
+
 // Tests hitting Enter key when focus is on search box.
 // There are two behaviors:
 // 1. Activate the search box when it is inactive.
diff --git a/ui/app_list/views/search_result_answer_card_view.cc b/ui/app_list/views/search_result_answer_card_view.cc
index f4c7958d..bd38c32 100644
--- a/ui/app_list/views/search_result_answer_card_view.cc
+++ b/ui/app_list/views/search_result_answer_card_view.cc
@@ -223,11 +223,14 @@
              : nullptr;
 }
 
-views::View* SearchResultAnswerCardView::SetFirstResultSelected(bool selected) {
+views::View* SearchResultAnswerCardView::GetFirstResultView() {
+  return num_results() <= 0 ? nullptr : search_answer_container_view_;
+}
+
+void SearchResultAnswerCardView::SetFirstResultSelected(bool selected) {
   if (num_results() <= 0)
-    return nullptr;
+    return;
   search_answer_container_view_->SetSelected(selected);
-  return search_answer_container_view_;
 }
 
 views::View* SearchResultAnswerCardView::GetSearchAnswerContainerViewForTest()
diff --git a/ui/app_list/views/search_result_answer_card_view.h b/ui/app_list/views/search_result_answer_card_view.h
index 4efca808..cf6b883 100644
--- a/ui/app_list/views/search_result_answer_card_view.h
+++ b/ui/app_list/views/search_result_answer_card_view.h
@@ -30,7 +30,8 @@
   void UpdateSelectedIndex(int old_selected, int new_selected) override;
   bool OnKeyPressed(const ui::KeyEvent& event) override;
   views::View* GetSelectedView() const override;
-  views::View* SetFirstResultSelected(bool selected) override;
+  views::View* GetFirstResultView() override;
+  void SetFirstResultSelected(bool selected) override;
 
   views::View* GetSearchAnswerContainerViewForTest() const;
 
diff --git a/ui/app_list/views/search_result_container_view.h b/ui/app_list/views/search_result_container_view.h
index e1eedf68..e5bb4258 100644
--- a/ui/app_list/views/search_result_container_view.h
+++ b/ui/app_list/views/search_result_container_view.h
@@ -89,9 +89,12 @@
   // Returns selected view in this container view.
   virtual views::View* GetSelectedView() const = 0;
 
-  // Sets the first result in this container view selected/unselected. Returns
-  // the result's view.
-  virtual views::View* SetFirstResultSelected(bool selected) = 0;
+  // Returns the first result in the container view. Returns NULL if it does not
+  // exist.
+  virtual views::View* GetFirstResultView() = 0;
+
+  // Sets the first result in this container view selected/unselected.
+  virtual void SetFirstResultSelected(bool selected) = 0;
 
  private:
   // Schedules an Update call using |update_factory_|. Do nothing if there is a
diff --git a/ui/app_list/views/search_result_list_view.cc b/ui/app_list/views/search_result_list_view.cc
index 3c20d10c..598a290 100644
--- a/ui/app_list/views/search_result_list_view.cc
+++ b/ui/app_list/views/search_result_list_view.cc
@@ -171,14 +171,18 @@
              : nullptr;
 }
 
-views::View* SearchResultListView::SetFirstResultSelected(bool selected) {
+views::View* SearchResultListView::GetFirstResultView() {
+  DCHECK(results_container_->has_children());
+  return num_results() <= 0 ? nullptr : results_container_->child_at(0);
+}
+
+void SearchResultListView::SetFirstResultSelected(bool selected) {
   DCHECK(results_container_->has_children());
   if (num_results() <= 0)
-    return nullptr;
+    return;
   SearchResultView* search_result_view =
       static_cast<SearchResultView*>(results_container_->child_at(0));
   search_result_view->SetSelected(selected);
-  return search_result_view;
 }
 
 int SearchResultListView::DoUpdate() {
diff --git a/ui/app_list/views/search_result_list_view.h b/ui/app_list/views/search_result_list_view.h
index 2211b0c..378ee38 100644
--- a/ui/app_list/views/search_result_list_view.h
+++ b/ui/app_list/views/search_result_list_view.h
@@ -60,7 +60,8 @@
   void NotifyFirstResultYIndex(int y_index) override;
   int GetYSize() override;
   views::View* GetSelectedView() const override;
-  views::View* SetFirstResultSelected(bool selected) override;
+  views::View* GetFirstResultView() override;
+  void SetFirstResultSelected(bool selected) override;
 
   views::View* results_container_for_test() const { return results_container_; }
 
diff --git a/ui/app_list/views/search_result_page_view.cc b/ui/app_list/views/search_result_page_view.cc
index cf0074a..2ef7192 100644
--- a/ui/app_list/views/search_result_page_view.cc
+++ b/ui/app_list/views/search_result_page_view.cc
@@ -367,9 +367,20 @@
     SearchResultContainerView* old_first_container_view =
         result_container_views_[0];
     ReorderSearchResultContainers();
-    old_first_container_view->SetFirstResultSelected(false);
-    first_result_view_ =
-        result_container_views_[0]->SetFirstResultSelected(true);
+
+    views::View* focused_view = GetFocusManager()->GetFocusedView();
+    if (first_result_view_ != focused_view) {
+      // If the old first result is focused, do not clear the selection. (This
+      // happens when the user moved the focus before search results are
+      // updated.)
+      old_first_container_view->SetFirstResultSelected(false);
+    }
+    first_result_view_ = result_container_views_[0]->GetFirstResultView();
+    if (!Contains(focused_view)) {
+      // If one of the search result is focused, do not set the first result
+      // selected.
+      result_container_views_[0]->SetFirstResultSelected(true);
+    }
     return;
   }
 
diff --git a/ui/app_list/views/search_result_tile_item_list_view.cc b/ui/app_list/views/search_result_tile_item_list_view.cc
index b5bb56a..e770df4 100644
--- a/ui/app_list/views/search_result_tile_item_list_view.cc
+++ b/ui/app_list/views/search_result_tile_item_list_view.cc
@@ -102,13 +102,16 @@
                                                  : nullptr;
 }
 
-views::View* SearchResultTileItemListView::SetFirstResultSelected(
-    bool selected) {
+views::View* SearchResultTileItemListView::GetFirstResultView() {
+  DCHECK(!tile_views_.empty());
+  return num_results() <= 0 ? nullptr : tile_views_[0];
+}
+
+void SearchResultTileItemListView::SetFirstResultSelected(bool selected) {
   DCHECK(!tile_views_.empty());
   if (num_results() <= 0)
-    return nullptr;
+    return;
   tile_views_[0]->SetSelected(selected);
-  return tile_views_[0];
 }
 
 int SearchResultTileItemListView::DoUpdate() {
diff --git a/ui/app_list/views/search_result_tile_item_list_view.h b/ui/app_list/views/search_result_tile_item_list_view.h
index c58014a7e..87ef0f0 100644
--- a/ui/app_list/views/search_result_tile_item_list_view.h
+++ b/ui/app_list/views/search_result_tile_item_list_view.h
@@ -36,7 +36,8 @@
   void NotifyFirstResultYIndex(int y_index) override;
   int GetYSize() override;
   views::View* GetSelectedView() const override;
-  views::View* SetFirstResultSelected(bool selected) override;
+  views::View* GetFirstResultView() override;
+  void SetFirstResultSelected(bool selected) override;
 
   // Overridden from views::View:
   bool OnKeyPressed(const ui::KeyEvent& event) override;
diff --git a/ui/app_list/views/suggestions_container_view.cc b/ui/app_list/views/suggestions_container_view.cc
index 552b5f68..d624752 100644
--- a/ui/app_list/views/suggestions_container_view.cc
+++ b/ui/app_list/views/suggestions_container_view.cc
@@ -105,10 +105,12 @@
              : nullptr;
 }
 
-views::View* SuggestionsContainerView::SetFirstResultSelected(bool selected) {
+views::View* SuggestionsContainerView::GetFirstResultView() {
   return nullptr;
 }
 
+void SuggestionsContainerView::SetFirstResultSelected(bool selected) {}
+
 void SuggestionsContainerView::CreateAppsGrid(int apps_num) {
   DCHECK(search_result_tile_views_.empty());
   views::GridLayout* tiles_layout_manager =
diff --git a/ui/app_list/views/suggestions_container_view.h b/ui/app_list/views/suggestions_container_view.h
index b7af549..00afaf61 100644
--- a/ui/app_list/views/suggestions_container_view.h
+++ b/ui/app_list/views/suggestions_container_view.h
@@ -40,7 +40,8 @@
   void NotifyFirstResultYIndex(int y_index) override;
   int GetYSize() override;
   views::View* GetSelectedView() const override;
-  views::View* SetFirstResultSelected(bool selected) override;
+  views::View* GetFirstResultView() override;
+  void SetFirstResultSelected(bool selected) override;
 
  private:
   void CreateAppsGrid(int apps_num);