[login_manager] Allow new owner keys to be pushed with StorePolicy

To handle initial enrollment and emergency key rotation (the current key has been compromised), we will allow any policy stored before the user has begun her session to clobber the existing key/policy.

To perform normal key rotation, we'll validate the signature on the key blob in the policy with the currently registered key and, iff it checks out, replace the stored key.

BUG=13746
TEST=Unit tests, and login_RemoteOwnership (to be landed soon), and login_OwnershipApi

Change-Id: Id4c6e8f3d37224a03ac631ff19bb6daa04ff20eb

Review URL: http://codereview.chromium.org/6793055
diff --git a/Makefile b/Makefile
index 67653de..4498f27 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
diff --git a/mock_owner_key.h b/mock_owner_key.h
index c6dcbb2..824da9c 100644
--- a/mock_owner_key.h
+++ b/mock_owner_key.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -19,14 +19,18 @@
  public:
   MockOwnerKey() : OwnerKey(FilePath("")) {}
   virtual ~MockOwnerKey() {}
+  MOCK_CONST_METHOD1(Equals, bool(const std::string&));
+  MOCK_CONST_METHOD1(VEquals, bool(const std::vector<uint8>&));
   MOCK_METHOD0(HaveCheckedDisk, bool());
   MOCK_METHOD0(IsPopulated, bool());
   MOCK_METHOD0(PopulateFromDiskIfPossible, bool());
   MOCK_METHOD1(PopulateFromBuffer, bool(const std::vector<uint8>&));
   MOCK_METHOD1(PopulateFromKeypair, bool(base::RSAPrivateKey*));
   MOCK_METHOD0(Persist, bool());
-  MOCK_METHOD4(Verify, bool(const char*, uint32, const char*, uint32));
-  MOCK_METHOD3(Sign, bool(const char*, uint32, std::vector<uint8>*));
+  MOCK_METHOD3(Rotate, bool(const std::vector<uint8>&, const uint8*, uint32));
+  MOCK_METHOD1(ClobberCompromisedKey, void(const std::vector<uint8>&));
+  MOCK_METHOD4(Verify, bool(const uint8*, uint32, const uint8*, uint32));
+  MOCK_METHOD3(Sign, bool(const uint8*, uint32, std::vector<uint8>*));
   MOCK_METHOD1(StartGeneration, int(ChildJobInterface*));
 };
 }  // namespace login_manager
diff --git a/nss_util.cc b/nss_util.cc
index 1f2f963..d87e9b2 100644
--- a/nss_util.cc
+++ b/nss_util.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -66,7 +66,7 @@
 }
 
 // static
-void NssUtil::KeyFromBuffer(const std::string& buf, std::vector<uint8>* out) {
+void NssUtil::BlobFromBuffer(const std::string& buf, std::vector<uint8>* out) {
   out->resize(buf.length());
   if (out->size() == 0)
     return;
diff --git a/nss_util.h b/nss_util.h
index f3e6873..bd53777 100644
--- a/nss_util.h
+++ b/nss_util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -40,7 +40,7 @@
   // Factory (the default) this creates and returns a new NssUtil.
   static NssUtil* Create();
 
-  static void KeyFromBuffer(const std::string& buf, std::vector<uint8>* out);
+  static void BlobFromBuffer(const std::string& buf, std::vector<uint8>* out);
 
   virtual bool OpenUserDB() = 0;
 
diff --git a/owner_key.cc b/owner_key.cc
index 541161e..b06ecdd 100644
--- a/owner_key.cc
+++ b/owner_key.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -28,11 +28,22 @@
 OwnerKey::OwnerKey(const FilePath& key_file)
     : key_file_(key_file),
       have_checked_disk_(false),
+      have_replaced_(false),
       utils_(new SystemUtils) {
 }
 
 OwnerKey::~OwnerKey() {}
 
+bool OwnerKey::Equals(const std::string& key_der) const {
+  return VEquals(std::vector<uint8>(key_der.c_str(),
+                                    key_der.c_str() + key_der.length()));
+}
+
+bool OwnerKey::VEquals(const std::vector<uint8>& key_der) const {
+  return ((key_.empty() == key_der.empty()) &&
+          memcmp(&key_der[0], &key_[0], key_.size()) == 0);
+}
+
 bool OwnerKey::HaveCheckedDisk() { return have_checked_disk_; }
 
 bool OwnerKey::IsPopulated() { return !key_.empty(); }
@@ -88,7 +99,7 @@
 bool OwnerKey::Persist() {
   // It is a programming error to call this before checking for the key on disk.
   CHECK(have_checked_disk_) << "Haven't checked disk for owner key yet!";
-  if (file_util::PathExists(key_file_)) {
+  if (!have_replaced_ && file_util::PathExists(key_file_)) {
     LOG(ERROR) << "Tried to overwrite owner key!";
     return false;
   }
@@ -103,17 +114,44 @@
   return true;
 }
 
-bool OwnerKey::Verify(const char* data,
+bool OwnerKey::Rotate(const std::vector<uint8>& public_key_der,
+                      const std::vector<uint8>& signature) {
+  if (!IsPopulated()) {
+    LOG(ERROR) << "Don't yet have an owner key!";
+    return false;
+  }
+  if (Verify(&public_key_der[0],
+             public_key_der.size(),
+             &signature[0],
+             signature.size())) {
+    key_ = public_key_der;
+    have_replaced_ = true;
+    return true;
+  }
+  LOG(ERROR) << "Invalid signature on new key!";
+  return false;
+}
+
+void OwnerKey::ClobberCompromisedKey(const std::vector<uint8>& public_key_der) {
+  // It is a programming error to call this before checking for the key on disk.
+  CHECK(have_checked_disk_) << "Haven't checked disk for owner key yet!";
+  // It is a programming error to call this without a key already loaded.
+  CHECK(IsPopulated()) << "Don't yet have an owner key!";
+
+  key_ = public_key_der;
+  have_replaced_ = true;
+}
+
+bool OwnerKey::Verify(const uint8* data,
                       uint32 data_len,
-                      const char* signature,
+                      const uint8* signature,
                       uint32 sig_len) {
   scoped_ptr<NssUtil> util(NssUtil::Create());
-
   if (!util->Verify(kAlgorithm,
                     sizeof(kAlgorithm),
-                    reinterpret_cast<const uint8*>(signature),
+                    signature,
                     sig_len,
-                    reinterpret_cast<const uint8*>(data),
+                    data,
                     data_len,
                     &key_[0],
                     key_.size())) {
@@ -123,17 +161,14 @@
   return true;
 }
 
-bool OwnerKey::Sign(const char* data,
+bool OwnerKey::Sign(const uint8* data,
                     uint32 data_len,
                     std::vector<uint8>* OUT_signature) {
   scoped_ptr<NssUtil> util(NssUtil::Create());
   scoped_ptr<base::RSAPrivateKey> private_key(util->GetPrivateKey(key_));
   if (!private_key.get())
     return false;
-  if (!util->Sign(reinterpret_cast<const uint8*>(data),
-                  data_len,
-                  OUT_signature,
-                  private_key.get())) {
+  if (!util->Sign(data, data_len, OUT_signature, private_key.get())) {
     LOG(ERROR) << "Signing of " << data << " failed";
     return false;
   }
diff --git a/owner_key.h b/owner_key.h
index a10039e..c35112f 100644
--- a/owner_key.h
+++ b/owner_key.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -32,6 +32,8 @@
   explicit OwnerKey(const FilePath& key_file);
   virtual ~OwnerKey();
 
+  virtual bool Equals(const std::string& key_der) const;
+  virtual bool VEquals(const std::vector<uint8>& key_der) const;
   virtual bool HaveCheckedDisk();
   virtual bool IsPopulated();
 
@@ -58,18 +60,30 @@
   // writing data.
   virtual bool Persist();
 
+  // Load key material from |public_key_der|, as long as |sig| is a valid
+  // signature over |public_key_der| with |key_|.
+  // We will _deny_ such an attempt if we do not have a key loaded.
+  // If you're trying to set a key for the first time, use PopulateFromBuffer()
+  virtual bool Rotate(const std::vector<uint8>& public_key_der,
+                      const std::vector<uint8>& signature);
+
+  // THIS IS ONLY INTENDED TO BE USED WHEN THE CURRENTLY REGISTERED KEY HAS BEEN
+  // COMPROMISED OR LOST AND WE ARE RECOVERING.
+  // Load key material from |public_key_der| into key_.
+  virtual void ClobberCompromisedKey(const std::vector<uint8>& public_key_der);
+
   // Verify that |signature| is a valid sha1 w/ RSA signature over the data in
   // |data| with |key_|.
   // Returns false if the sig is invalid, or there's an error.
-  virtual bool Verify(const char* data,
+  virtual bool Verify(const uint8* data,
                       uint32 data_len,
-                      const char* signature,
+                      const uint8* signature,
                       uint32 sig_len);
 
   // Generate |OUT_signature|, a valid sha1 w/ RSA signature over the data in
   // |data| that can be verified with |key_|.
   // Returns false if the sig is invalid, or there's an error.
-  virtual bool Sign(const char* data,
+  virtual bool Sign(const uint8* data,
                     uint32 data_len,
                     std::vector<uint8>* OUT_signature);
 
@@ -86,6 +100,7 @@
 
   const FilePath key_file_;
   bool have_checked_disk_;
+  bool have_replaced_;
   std::vector<uint8> key_;
   scoped_ptr<SystemUtils> utils_;
 
diff --git a/owner_key_unittest.cc b/owner_key_unittest.cc
index 553584a..1135506 100644
--- a/owner_key_unittest.cc
+++ b/owner_key_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -38,6 +38,30 @@
   DISALLOW_COPY_AND_ASSIGN(OwnerKeyTest);
 };
 
+TEST_F(OwnerKeyTest, Equals) {
+  // Set up an empty key
+  StartUnowned();
+  OwnerKey key(tmpfile_);
+  ASSERT_TRUE(key.PopulateFromDiskIfPossible());
+  ASSERT_TRUE(key.HaveCheckedDisk());
+  ASSERT_FALSE(key.IsPopulated());
+
+  // Trivial case.
+  EXPECT_TRUE(key.VEquals(std::vector<uint8>()));
+
+  // Ensure that 0-length keys don't cause us to return true for everything.
+  std::vector<uint8> fake(1, 1);
+  EXPECT_FALSE(key.VEquals(fake));
+
+  // Populate the key.
+  ASSERT_TRUE(key.PopulateFromBuffer(fake));
+  ASSERT_TRUE(key.HaveCheckedDisk());
+  ASSERT_TRUE(key.IsPopulated());
+
+  // Real comparison.
+  EXPECT_TRUE(key.VEquals(fake));
+}
+
 TEST_F(OwnerKeyTest, LoadKey) {
   OwnerKey key(tmpfile_);
   ASSERT_FALSE(key.HaveCheckedDisk());
@@ -120,7 +144,7 @@
   base::EnsureNSSInit();
   base::OpenPersistentNSSDB();
   scoped_ptr<base::RSAPrivateKey> pair(
-      base::RSAPrivateKey::CreateSensitive(2048));
+      base::RSAPrivateKey::CreateSensitive(512));
   ASSERT_NE(pair.get(), reinterpret_cast<base::RSAPrivateKey*>(NULL));
 
   ASSERT_TRUE(key.PopulateFromDiskIfPossible());
@@ -134,11 +158,64 @@
   ASSERT_TRUE(key.IsPopulated());
 
   std::string data("whatever");
+  const uint8* data_p = reinterpret_cast<const uint8*>(data.c_str());
   std::vector<uint8> signature;
-  EXPECT_TRUE(key.Sign(data.c_str(), data.length(), &signature));
-  EXPECT_TRUE(key.Verify(data.c_str(),
+  EXPECT_TRUE(key.Sign(data_p, data.length(), &signature));
+  EXPECT_TRUE(key.Verify(data_p,
                          data.length(),
-                         reinterpret_cast<const char*>(&signature[0]),
+                         &signature[0],
                          signature.size()));
 }
+
+TEST_F(OwnerKeyTest, RotateKey) {
+  StartUnowned();
+  OwnerKey key(tmpfile_);
+
+  base::EnsureNSSInit();
+  base::OpenPersistentNSSDB();
+  scoped_ptr<base::RSAPrivateKey> pair(
+      base::RSAPrivateKey::CreateSensitive(512));
+  ASSERT_NE(pair.get(), reinterpret_cast<base::RSAPrivateKey*>(NULL));
+
+  ASSERT_TRUE(key.PopulateFromDiskIfPossible());
+  ASSERT_TRUE(key.HaveCheckedDisk());
+  ASSERT_FALSE(key.IsPopulated());
+
+  std::vector<uint8> to_export;
+  ASSERT_TRUE(pair->ExportPublicKey(&to_export));
+  ASSERT_TRUE(key.PopulateFromBuffer(to_export));
+  ASSERT_TRUE(key.HaveCheckedDisk());
+  ASSERT_TRUE(key.IsPopulated());
+  ASSERT_TRUE(key.Persist());
+
+  OwnerKey key2(tmpfile_);
+  ASSERT_TRUE(key2.PopulateFromDiskIfPossible());
+  ASSERT_TRUE(key2.HaveCheckedDisk());
+  ASSERT_TRUE(key2.IsPopulated());
+
+  scoped_ptr<base::RSAPrivateKey> new_pair(
+      base::RSAPrivateKey::CreateSensitive(512));
+  ASSERT_NE(new_pair.get(), reinterpret_cast<base::RSAPrivateKey*>(NULL));
+  std::vector<uint8> new_export;
+  ASSERT_TRUE(new_pair->ExportPublicKey(&new_export));
+
+  std::vector<uint8> signature;
+  ASSERT_TRUE(key2.Sign(&new_export[0], new_export.size(), &signature));
+  ASSERT_TRUE(key2.Rotate(new_export, signature));
+  ASSERT_TRUE(key2.Persist());
+}
+
+TEST_F(OwnerKeyTest, ClobberKey) {
+  OwnerKey key(tmpfile_);
+
+  ASSERT_TRUE(key.PopulateFromDiskIfPossible());
+  ASSERT_TRUE(key.HaveCheckedDisk());
+  ASSERT_TRUE(key.IsPopulated());
+
+  std::vector<uint8> fake(1, 1);
+  key.ClobberCompromisedKey(fake);
+  ASSERT_TRUE(key.VEquals(fake));
+  ASSERT_TRUE(key.Persist());
+}
+
 }  // namespace login_manager
diff --git a/session_manager_service.cc b/session_manager_service.cc
index a5e9c27..25afa85 100644
--- a/session_manager_service.cc
+++ b/session_manager_service.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2010 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -550,7 +550,7 @@
 
 void SessionManagerService::ValidateAndStoreOwnerKey(const std::string& buf) {
   std::vector<uint8> pub_key;
-  NssUtil::KeyFromBuffer(buf, &pub_key);
+  NssUtil::BlobFromBuffer(buf, &pub_key);
 
   if (!CurrentUserHasOwnerKey(pub_key, NULL)) {
     SendSignal(chromium::kOwnerKeySetSignal, false);
@@ -745,30 +745,63 @@
 gboolean SessionManagerService::StorePolicy(GArray* policy_blob,
                                             DBusGMethodInvocation* context) {
   std::string policy_str(policy_blob->data, policy_blob->len);
-  GError* error = NULL;
   enterprise_management::PolicyFetchResponse policy;
   if (!policy.ParseFromString(policy_str) ||
       !policy.has_policy_data() ||
       !policy.has_policy_data_signature()) {
     const char msg[] = "Unable to parse policy protobuf.";
     LOG(ERROR) << msg;
-    SetGError(&error, CHROMEOS_LOGIN_ERROR_DECODE_FAIL, msg);
-    dbus_g_method_return_error(context, error);
-    g_error_free(error);
+    SetAndSendGError(CHROMEOS_LOGIN_ERROR_DECODE_FAIL, context, msg);
     return FALSE;
   }
+
+  // Determine if the policy has pushed a new owner key and, if so, set it and
+  // schedule a task to persist it to disk.
+  if (policy.has_new_public_key() && !key_->Equals(policy.new_public_key())) {
+    // The policy contains a new key, and it is different from |key_|.
+    std::vector<uint8> der;
+    nss_->BlobFromBuffer(policy.new_public_key(), &der);
+
+    if (session_started_) {
+      bool rotated = false;
+      if (policy.has_new_public_key_signature()) {
+        // Graceful key rotation.
+        std::vector<uint8> sig;
+        nss_->BlobFromBuffer(policy.new_public_key_signature(), &sig);
+        rotated = key_->Rotate(der, sig);
+      }
+      if (!rotated) {
+        const char msg[] = "Failed attempted key rotation!";
+        LOG(ERROR) << msg;
+        SetAndSendGError(CHROMEOS_LOGIN_ERROR_ILLEGAL_PUBKEY, context, msg);
+        return FALSE;
+      }
+    } else {
+      // Force a new key, regardless of whether we have one or not.
+      if (key_->IsPopulated()) {
+        key_->ClobberCompromisedKey(der);
+        LOG(INFO) << "Clobbered existing key outside of session";
+      } else {
+        CHECK(key_->PopulateFromBuffer(der));  // Should be unable to fail.
+        LOG(INFO) << "Setting key outside of session";
+      }
+    }
+    // If here, need to persit new key to disk.  Already loaded key into memory.
+    io_thread_.message_loop()->PostTask(
+        FROM_HERE, NewRunnableMethod(this, &SessionManagerService::PersistKey));
+  }
+
+  // Validate signature on policy and persist to disk
   const std::string& sig = policy.policy_data_signature();
   SessionManagerService::SigReturnCode verify_result =
       VerifyHelper(policy.policy_data(), sig.c_str(), sig.length());
   if (verify_result == NO_KEY) {
-    const char msg[] = "Attempt to store policy before owner's key is set.";
-    LOG(ERROR) << msg;
-    SetGError(&error, CHROMEOS_LOGIN_ERROR_NO_OWNER_KEY, msg);
+    NOTREACHED() << "Should have set the key earlier in this function!";
     return FALSE;
   } else if (verify_result == SIGNATURE_FAIL) {
     const char msg[] = "Signature could not be verified in StorePolicy.";
     LOG(ERROR) << msg;
-    SetGError(&error, CHROMEOS_LOGIN_ERROR_VERIFY_FAIL, msg);
+    SetAndSendGError(CHROMEOS_LOGIN_ERROR_VERIFY_FAIL, context, msg);
     return FALSE;
   }
   policy_->Set(policy);
@@ -1000,6 +1033,15 @@
   g_set_error(error, CHROMEOS_LOGIN_ERROR, code, "Login error: %s", message);
 }
 
+// static
+void SessionManagerService::SetAndSendGError(ChromeOSLoginError code,
+                                             DBusGMethodInvocation* context,
+                                             const char* msg) {
+  GError* error = NULL;
+  SetGError(&error, code, msg);
+  dbus_g_method_return_error(context, error);
+  g_error_free(error);
+}
 
 ///////////////////////////////////////////////////////////////////////////////
 // Utility Methods
@@ -1102,10 +1144,7 @@
   std::string was_signed = base::StringPrintf("%s=%s",
                                               kDeviceOwnerPref,
                                               value.c_str());
-  if (!key_->Verify(was_signed.c_str(),
-                    was_signed.length(),
-                    decoded.c_str(),
-                    decoded.length())) {
+  if (VerifyHelper(was_signed, decoded.c_str(), decoded.length()) != SUCCESS) {
     const char msg[] = "Owner pref signature could not be verified.";
     LOG(ERROR) << msg;
     SetGError(error, CHROMEOS_LOGIN_ERROR_VERIFY_FAIL, msg);
@@ -1203,7 +1242,8 @@
   std::string to_sign = base::StringPrintf("%s=%s",
                                            kDeviceOwnerPref,
                                            current_user_.c_str());
-  if (!key_->Sign(to_sign.c_str(), to_sign.length(), &signature)) {
+  const uint8* data = reinterpret_cast<const uint8*>(to_sign.c_str());
+  if (!key_->Sign(data, to_sign.length(), &signature)) {
     LOG_IF(ERROR, error) << err_msg;
     LOG_IF(WARNING, !error) << err_msg;
     SetGError(error, CHROMEOS_LOGIN_ERROR_ILLEGAL_PUBKEY, err_msg.c_str());
@@ -1221,7 +1261,8 @@
                                                  const std::string& err_msg,
                                                  GError** error) {
   std::vector<uint8> signature;
-  if (!key_->Sign(current_user_.c_str(), current_user_.length(), &signature)) {
+  const uint8* data = reinterpret_cast<const uint8*>(current_user_.c_str());
+  if (!key_->Sign(data, current_user_.length(), &signature)) {
     LOG_IF(ERROR, error) << err_msg;
     LOG_IF(WARNING, !error) << err_msg;
     SetGError(error, CHROMEOS_LOGIN_ERROR_ILLEGAL_PUBKEY, err_msg.c_str());
@@ -1260,8 +1301,12 @@
                                     uint32 sig_len) {
   if (!key_->IsPopulated())
     return NO_KEY;
-  if (!key_->Verify(data.c_str(), data.length(), sig, sig_len))
+  if (!key_->Verify(reinterpret_cast<const uint8*>(data.c_str()),
+                    data.length(),
+                    reinterpret_cast<const uint8*>(sig),
+                    sig_len)) {
     return SIGNATURE_FAIL;
+  }
   return SUCCESS;
 }
 
diff --git a/session_manager_service.h b/session_manager_service.h
index 6f66098..6f4fba4 100644
--- a/session_manager_service.h
+++ b/session_manager_service.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2010 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -379,6 +379,11 @@
                         ChromeOSLoginError code,
                         const char* message);
 
+  // Initializes |error| with |code| and |message|.
+  static void SetAndSendGError(ChromeOSLoginError code,
+                               DBusGMethodInvocation* context,
+                               const char* message);
+
   // Setup any necessary signal handlers.
   void SetupHandlers();
 
diff --git a/session_manager_unittest.cc b/session_manager_unittest.cc
index f27e653..daa6343 100644
--- a/session_manager_unittest.cc
+++ b/session_manager_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2010 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -49,6 +49,10 @@
 using ::testing::StrEq;
 using ::testing::_;
 
+MATCHER_P(CastEq, str, "") {                                            \
+  return std::string(reinterpret_cast<const char*>(arg)) == str;        \
+}
+
 static const char kCheckedFile[] = "/tmp/checked_file";
 static const char kUptimeFile[] = "/tmp/uptime-chrome-exec";
 static const char kDiskFile[] = "/tmp/disk-chrome-exec";
@@ -177,6 +181,7 @@
     EXPECT_CALL(*key, HaveCheckedDisk())
         .WillOnce(Return(true));
     EXPECT_CALL(*key, IsPopulated())
+        .WillOnce(Return(true))
         .WillOnce(Return(true));
   }
 
@@ -241,7 +246,7 @@
         .RetiresOnSaturation();
     EXPECT_CALL(*store, Set(_, email_string, _))
         .Times(1);
-    EXPECT_CALL(*key, Sign(StrEq(email_string), email_string.length(), _))
+    EXPECT_CALL(*key, Sign(CastEq(email_string), email_string.length(), _))
         .WillOnce(Return(true))
         .RetiresOnSaturation();
     EXPECT_CALL(*store, Whitelist(email_string, _))
@@ -262,7 +267,7 @@
         .Times(AtMost(1))
         .WillRepeatedly(Return(true));
     EXPECT_CALL(*key, IsPopulated())
-        .Times(AtMost(1))
+        .Times(AtMost(2))
         .WillRepeatedly(Return(true));
   }
 
@@ -812,7 +817,7 @@
   MockUtils();
 
   std::vector<uint8> pub_key;
-  NssUtil::KeyFromBuffer(kPropValue, &pub_key);
+  NssUtil::BlobFromBuffer(kPropValue, &pub_key);
 
   MockPrefStore* store = new MockPrefStore;
   MockOwnerKey* key = new MockOwnerKey;
@@ -876,8 +881,8 @@
       .WillOnce(Return(true));
   EXPECT_CALL(*key, IsPopulated())
       .WillOnce(Return(true));
-  EXPECT_CALL(*key, Verify(StrEq(kFakeEmail), strlen(kFakeEmail),
-                           fake_sig_->data, fake_sig_->len))
+  EXPECT_CALL(*key, Verify(CastEq(kFakeEmail), strlen(kFakeEmail),
+                           CastEq(fake_sig_->data), fake_sig_->len))
       .WillOnce(Return(false));
   manager_->test_api().set_ownerkey(key);
 
@@ -903,8 +908,8 @@
       .WillOnce(Return(true));
   EXPECT_CALL(*key, IsPopulated())
       .WillOnce(Return(true));
-  EXPECT_CALL(*key, Verify(StrEq(kFakeEmail), strlen(kFakeEmail),
-                           fake_sig_->data, fake_sig_->len))
+  EXPECT_CALL(*key, Verify(CastEq(kFakeEmail), strlen(kFakeEmail),
+                           CastEq(fake_sig_->data), fake_sig_->len))
       .WillOnce(Return(true));
 
   manager_->test_api().set_ownerkey(key);
@@ -939,8 +944,8 @@
       .WillOnce(Return(true));
   EXPECT_CALL(*key, IsPopulated())
       .WillOnce(Return(true));
-  EXPECT_CALL(*key, Verify(StrEq(kFakeEmail), strlen(kFakeEmail),
-                           fake_sig_->data, fake_sig_->len))
+  EXPECT_CALL(*key, Verify(CastEq(kFakeEmail), strlen(kFakeEmail),
+                           CastEq(fake_sig_->data), fake_sig_->len))
       .WillOnce(Return(true));
 
   manager_->test_api().set_ownerkey(key);
@@ -1064,6 +1069,8 @@
   enterprise_management::PolicyFetchResponse fake_policy;
   fake_policy.set_policy_data(kPropName);
   fake_policy.set_policy_data_signature(kPropValue);
+  fake_policy.set_new_public_key(kPropName);
+  fake_policy.set_new_public_key_signature(kPropValue);
   MockChildJob* job = CreateTrivialMockJob(MAYBE_NEVER);
 
   MockPrefStore* store = new MockPrefStore;
@@ -1071,10 +1078,17 @@
   MockDevicePolicy* policy = new MockDevicePolicy;
   EXPECT_CALL(*key, PopulateFromDiskIfPossible())
       .WillOnce(Return(true));
-  EXPECT_CALL(*key, IsPopulated())
+  EXPECT_CALL(*key, PopulateFromBuffer(_))
       .WillOnce(Return(true));
-  EXPECT_CALL(*key, Verify(StrEq(kPropName), strlen(kPropName),
-                           StrEq(kPropValue), strlen(kPropValue)))
+  EXPECT_CALL(*key, IsPopulated())
+      .WillOnce(Return(false))
+      .WillOnce(Return(true));
+  EXPECT_CALL(*key, Verify(CastEq(kPropName), strlen(kPropName),
+                           CastEq(kPropValue), strlen(kPropValue)))
+      .WillOnce(Return(true));
+  EXPECT_CALL(*key, Equals(StrEq(kPropName)))
+      .WillOnce(Return(false));
+  EXPECT_CALL(*key, Persist())
       .WillOnce(Return(true));
   manager_->test_api().set_ownerkey(key);
 
@@ -1089,6 +1103,12 @@
       .Times(1);
   manager_->test_api().set_policy(policy);
 
+  EXPECT_CALL(*(utils_.get()),
+              SendSignalToChromium(chromium::kOwnerKeySetSignal,
+                                   StrEq("success")))
+      .Times(1);
+  MockUtils();
+
   std::string pol_str = fake_policy.SerializeAsString();
   ASSERT_FALSE(pol_str.empty());
   GArray* policy_array = CreateArray(pol_str.c_str(), pol_str.length());
@@ -1127,8 +1147,8 @@
       .WillOnce(Return(true));
   EXPECT_CALL(*key, IsPopulated())
       .WillOnce(Return(true));
-  EXPECT_CALL(*key, Verify(StrEq(property_), property_.length(),
-                           fake_sig_->data, fake_sig_->len))
+  EXPECT_CALL(*key, Verify(CastEq(property_), property_.length(),
+                           CastEq(fake_sig_->data), fake_sig_->len))
       .WillOnce(Return(false));
   manager_->test_api().set_ownerkey(key);
 
@@ -1157,8 +1177,8 @@
       .WillOnce(Return(true));
   EXPECT_CALL(*key, IsPopulated())
       .WillOnce(Return(true));
-  EXPECT_CALL(*key, Verify(StrEq(property_), property_.length(),
-                           fake_sig_->data, fake_sig_->len))
+  EXPECT_CALL(*key, Verify(CastEq(property_), property_.length(),
+                           CastEq(fake_sig_->data), fake_sig_->len))
       .WillOnce(Return(true));
   manager_->test_api().set_ownerkey(key);