Commit 4ada238a authored by cmasone@google.com's avatar cmasone@google.com

OwnerManager, allows use of OwnerKeyUtils to take ownership of a device

    BUG=chromium-os:4485
    TEST=unit tests

Review URL: http://codereview.chromium.org/3058021

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@54199 0039d316-1c4b-4281-b951-d872f2087c98
parent 5066a78c
// Copyright (c) 2010 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 "chrome/browser/chromeos/login/owner_manager.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
namespace chromeos {
OwnerManager::OwnerManager()
: private_key_(NULL),
public_key_(NULL),
utils_(OwnerKeyUtils::Create()) {
}
OwnerManager::~OwnerManager() {}
bool OwnerManager::IsAlreadyOwned() {
return file_util::PathExists(utils_->GetOwnerKeyFilePath());
}
bool OwnerManager::StartLoadOwnerKeyAttempt() {
if (!IsAlreadyOwned()) {
LOG(ERROR) << "Device not yet owned";
return false;
}
ChromeThread::PostTask(
ChromeThread::FILE, FROM_HERE,
NewRunnableMethod(this, &OwnerManager::LoadOwnerKey));
return true;
}
bool OwnerManager::StartTakeOwnershipAttempt() {
if (IsAlreadyOwned()) {
LOG(ERROR) << "Device is already owned";
return false;
}
ChromeThread::PostTask(
ChromeThread::FILE, FROM_HERE,
NewRunnableMethod(this, &OwnerManager::GenerateKeysAndExportPublic));
return true;
}
bool OwnerManager::StartSigningAttempt(const std::string& data, Delegate* d) {
if (!IsAlreadyOwned()) {
LOG(ERROR) << "Device not yet owned";
return false;
}
ChromeThread::ID thread_id;
if (!ChromeThread::GetCurrentThreadIdentifier(&thread_id))
thread_id = ChromeThread::UI;
ChromeThread::PostTask(
ChromeThread::FILE, FROM_HERE,
NewRunnableMethod(this, &OwnerManager::Sign, thread_id, data, d));
return true;
}
bool OwnerManager::StartVerifyAttempt(const std::string& data,
const std::string& signature,
Delegate* d) {
if (!IsAlreadyOwned()) {
LOG(ERROR) << "Device not yet owned";
return false;
}
ChromeThread::ID thread_id;
if (!ChromeThread::GetCurrentThreadIdentifier(&thread_id))
thread_id = ChromeThread::UI;
ChromeThread::PostTask(
ChromeThread::FILE, FROM_HERE,
NewRunnableMethod(this,
&OwnerManager::Verify,
thread_id,
data,
signature,
d));
return true;
}
void OwnerManager::LoadOwnerKey() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
public_key_ = utils_->ImportPublicKey(utils_->GetOwnerKeyFilePath());
// Whether we loaded the public key or not, send a notification indicating
// that we're done with this attempt. We send along the key if we
// got it, NULL if not.
ChromeThread::PostTask(
ChromeThread::UI, FROM_HERE,
NewRunnableMethod(this,
&OwnerManager::SendNotification,
NotificationType::OWNER_KEY_FETCH_ATTEMPT_COMPLETE,
Details<SECKEYPublicKey*>(&public_key_)));
}
void OwnerManager::GenerateKeysAndExportPublic() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
public_key_ = NULL;
private_key_ = NULL;
if (utils_->GenerateKeyPair(&private_key_, &public_key_)) {
// If we generated the keys successfully, export them.
ChromeThread::PostTask(
ChromeThread::UI, FROM_HERE,
NewRunnableMethod(this, &OwnerManager::ExportKey));
} else {
// If we didn't generate the key, send along NULL with the notification
// that we're done with this attempt.
ChromeThread::PostTask(
ChromeThread::UI, FROM_HERE,
NewRunnableMethod(this,
&OwnerManager::SendNotification,
NotificationType::OWNER_KEY_FETCH_ATTEMPT_COMPLETE,
Details<SECKEYPublicKey*>(&public_key_)));
}
}
void OwnerManager::ExportKey() {
if (!utils_->ExportPublicKeyViaDbus(public_key_)) {
utils_->DestroyKeys(private_key_, public_key_);
private_key_ = NULL;
public_key_ = NULL;
}
// Whether we generated the keys or not, send a notification indicating
// that we're done with this attempt. We send along the public key if we
// got it, NULL if not.
ChromeThread::PostTask(
ChromeThread::UI, FROM_HERE,
NewRunnableMethod(this,
&OwnerManager::SendNotification,
NotificationType::OWNER_KEY_FETCH_ATTEMPT_COMPLETE,
Details<SECKEYPublicKey*>(&public_key_)));
}
bool OwnerManager::EnsurePublicKey() {
if (!public_key_)
LoadOwnerKey();
return public_key_ != NULL;
}
bool OwnerManager::EnsurePrivateKey() {
if (!EnsurePublicKey())
return false;
if (!private_key_)
private_key_ = utils_->FindPrivateKey(public_key_);
return private_key_ != NULL;
}
void OwnerManager::Sign(const ChromeThread::ID thread_id,
const std::string& data,
Delegate* d) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
// If it's not the case that we can get both keys...
if (!(EnsurePublicKey() && EnsurePrivateKey())) {
ChromeThread::PostTask(
thread_id, FROM_HERE,
NewRunnableMethod(this,
&OwnerManager::CallDelegate,
d, KEY_UNAVAILABLE, std::string()));
return;
}
// TODO(cmasone): Sign |data| with |private_key_|, return
// appropriate errors via CallDelegate.
ChromeThread::PostTask(
thread_id, FROM_HERE,
NewRunnableMethod(this,
&OwnerManager::CallDelegate,
d, SUCCESS, data));
}
void OwnerManager::Verify(const ChromeThread::ID thread_id,
const std::string& data,
const std::string& signature,
Delegate* d) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
if (!EnsurePublicKey()) {
ChromeThread::PostTask(
thread_id, FROM_HERE,
NewRunnableMethod(this,
&OwnerManager::CallDelegate,
d, KEY_UNAVAILABLE, std::string()));
return;
}
LOG(INFO) << "Starting verify attempt";
// TODO(cmasone): Verify |signature| over |data| with |public_key_|, return
// appropriate errors via CallDelegate.
ChromeThread::PostTask(
thread_id, FROM_HERE,
NewRunnableMethod(this,
&OwnerManager::CallDelegate,
d, SUCCESS, std::string()));
}
void OwnerManager::SendNotification(NotificationType type,
const NotificationDetails& details) {
NotificationService::current()->Notify(
type,
NotificationService::AllSources(),
details);
}
} // namespace chromeos
// Copyright (c) 2010 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 CHROME_BROWSER_CHROMEOS_LOGIN_OWNER_MANAGER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_OWNER_MANAGER_H_
#pragma once
#include "base/basictypes.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/chromeos/login/owner_key_utils.h"
#include "chrome/browser/chrome_thread.h"
class FilePath;
class NotificationDetails;
class NotificationType;
namespace chromeos {
// This class allows the registration of an Owner of a Chromium OS device.
// It handles generating the appropriate keys and storing them in the
// appropriate locations.
class OwnerManager : public base::RefCountedThreadSafe<OwnerManager> {
public:
// Return codes for public/private key operations.
enum KeyOpCode {
SUCCESS,
KEY_UNAVAILABLE, // The necessary key isn't available yet.
OPERATION_FAILED // The crypto operation failed.
};
class Delegate {
public:
// Upon completion of a key operation, this method will be called.
// |return_code| indicates what happened, |payload| will be used to pass
// back any artifacts of the operation. For example, if the operation
// was a signature attempt, the signature blob would come back in |payload|.
virtual void OnKeyOpComplete(const KeyOpCode return_code,
const std::string& payload) = 0;
};
OwnerManager();
virtual ~OwnerManager();
bool IsAlreadyOwned();
// If the device has been owned already, posts a task to the FILE thread to
// fetch the public key off disk.
// Returns true if the attempt was initiated, false otherwise.
//
// Sends out a OWNER_KEY_FETCH_ATTEMPT_COMPLETE notification on completion.
// Notification comes with a Details<SECKEYPublicKey*> that contains a pointer
// to the public key, or NULL if the fetch attempt failed.
bool StartLoadOwnerKeyAttempt();
// If the device has not yet been owned, posts a task to the FILE
// thread to generate the owner's keys and put them in the right
// places. Keeps them in memory as well, for later use.
// Returns true if the attempt was initiated, false otherwise.
//
// Sends out a OWNER_KEY_FETCH_ATTEMPT_COMPLETE notification on completion.
// Notification comes with a Details<SECKEYPublicKey*> that contains a pointer
// to the public key, or NULL if the fetch attempt failed.
bool StartTakeOwnershipAttempt();
// Initiate an attempt to sign |data| with |private_key_|. Will call
// d->OnKeyOpComplete() when done. Upon success, the signature will be passed
// as the |payload| argument to d->OnKeyOpComplete().
// Returns true if the attempt was initiated, false otherwise.
//
// If you call this on a well-known thread, you'll be called back on that
// thread. Otherwise, you'll get called back on the UI thread.
bool StartSigningAttempt(const std::string& data, Delegate* d);
// Initiate an attempt to verify that |signature| is valid over |data| with
// |public_key_|. When the attempt is completed, an appropriate KeyOpCode
// will be passed to d->OnKeyOpComplete().
// Returns true if the attempt was initiated, false otherwise.
//
// If you call this on a well-known thread, you'll be called back on that
// thread. Otherwise, you'll get called back on the UI thread.
bool StartVerifyAttempt(const std::string& data,
const std::string& signature,
Delegate* d);
private:
// Pulls the owner's public key off disk and into memory.
//
// Call this on the FILE thread.
void LoadOwnerKey();
// Generates the owner's keys in the default NSS token. Also stores
// them in |public_key_| and |private_key_|. When done, causes the
// public key to get exported via DBus.
//
// Call this on the FILE thread.
void GenerateKeysAndExportPublic();
// Exports |public_key_| via DBus.
//
// Call this on the UI thread (because of DBus usage).
void ExportKey();
bool EnsurePublicKey();
bool EnsurePrivateKey();
// Do the actual work of signing |data| with |private_key_|. First,
// ensures that we have the keys we need. Then, computes the signature.
//
// On success, calls d->OnKeyOpComplete() on |thread_id| with a
// successful return code, passing the signaure blob in |payload|.
// On failure, calls d->OnKeyOpComplete() on |thread_id| with an appropriate
// error and passes an empty string for |payload|.
void Sign(const ChromeThread::ID thread_id,
const std::string& data,
Delegate* d);
// Do the actual work of verifying that |signature| is valid over
// |data| with |public_key_|. First, ensures we have the key we
// need, then does the verify.
//
// On success, calls d->OnKeyOpComplete() on |thread_id| with a
// successful return code, passing an empty string for |payload|.
// On failure, calls d->OnKeyOpComplete() on |thread_id| with an appropriate
// error code, passing an empty string for |payload|.
void Verify(const ChromeThread::ID thread_id,
const std::string& data,
const std::string& signature,
Delegate* d);
// A helper method to send a notification on another thread.
void SendNotification(NotificationType type,
const NotificationDetails& details);
// A helper method to call back a delegte on another thread.
void CallDelegate(Delegate* d,
const KeyOpCode return_code,
const std::string& payload) {
d->OnKeyOpComplete(return_code, payload);
}
SECKEYPrivateKey* private_key_;
SECKEYPublicKey* public_key_;
scoped_ptr<OwnerKeyUtils> utils_;
friend class OwnerManagerTest;
DISALLOW_COPY_AND_ASSIGN(OwnerManager);
};
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_LOGIN_OWNER_MANAGER_H_
This diff is collapsed.
...@@ -492,6 +492,8 @@ ...@@ -492,6 +492,8 @@
'browser/chromeos/login/oobe_progress_bar.h', 'browser/chromeos/login/oobe_progress_bar.h',
'browser/chromeos/login/owner_key_utils.cc', 'browser/chromeos/login/owner_key_utils.cc',
'browser/chromeos/login/owner_key_utils.h', 'browser/chromeos/login/owner_key_utils.h',
'browser/chromeos/login/owner_manager.cc',
'browser/chromeos/login/owner_manager.h',
'browser/chromeos/login/password_changed_view.cc', 'browser/chromeos/login/password_changed_view.cc',
'browser/chromeos/login/password_changed_view.h', 'browser/chromeos/login/password_changed_view.h',
'browser/chromeos/login/registration_screen.cc', 'browser/chromeos/login/registration_screen.cc',
......
...@@ -739,6 +739,7 @@ ...@@ -739,6 +739,7 @@
'browser/chromeos/login/google_authenticator_unittest.cc', 'browser/chromeos/login/google_authenticator_unittest.cc',
'browser/chromeos/login/mock_auth_response_handler.cc', 'browser/chromeos/login/mock_auth_response_handler.cc',
'browser/chromeos/login/owner_key_utils_unittest.cc', 'browser/chromeos/login/owner_key_utils_unittest.cc',
'browser/chromeos/login/owner_manager_unittest.cc',
'browser/chromeos/notifications/desktop_notifications_unittest.cc', 'browser/chromeos/notifications/desktop_notifications_unittest.cc',
'browser/chromeos/offline/offline_load_page_unittest.cc', 'browser/chromeos/offline/offline_load_page_unittest.cc',
'browser/chromeos/options/language_config_model_unittest.cc', 'browser/chromeos/options/language_config_model_unittest.cc',
......
...@@ -1068,6 +1068,10 @@ class NotificationType { ...@@ -1068,6 +1068,10 @@ class NotificationType {
// in chrome/browser/chromeos/network_state_notifier.h. // in chrome/browser/chromeos/network_state_notifier.h.
// TODO(oshima): Port this to all platforms. // TODO(oshima): Port this to all platforms.
NETWORK_STATE_CHANGED, NETWORK_STATE_CHANGED,
// Sent when an attempt to acquire the public key of the owner of a chromium
// os device has completed. Details are a boolean value indicating success.
OWNER_KEY_FETCH_ATTEMPT_COMPLETE,
#endif #endif
// Sent before the repost form warning is brought up. // Sent before the repost form warning is brought up.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment