// Copyright (c) 2011 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/cros/cryptohome_library.h"
#include "base/command_line.h"
#include "base/hash_tables.h"
#include "base/message_loop.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/common/chrome_switches.h"
#include "content/browser/browser_thread.h"
namespace chromeos {
// This class handles the interaction with the ChromeOS cryptohome library APIs.
class CryptohomeLibraryImpl : public CryptohomeLibrary {
public:
CryptohomeLibraryImpl() {
if (CrosLibrary::Get()->EnsureLoaded())
Init();
}
virtual ~CryptohomeLibraryImpl() {}
bool CheckKey(const std::string& user_email, const std::string& passhash) {
return chromeos::CryptohomeCheckKey(user_email.c_str(), passhash.c_str());
}
bool AsyncCheckKey(const std::string& user_email,
const std::string& passhash,
Delegate* d) {
return CacheCallback(
chromeos::CryptohomeAsyncCheckKey(user_email.c_str(), passhash.c_str()),
d,
"Couldn't initiate async check of user's key.");
}
bool MigrateKey(const std::string& user_email,
const std::string& old_hash,
const std::string& new_hash) {
return chromeos::CryptohomeMigrateKey(user_email.c_str(),
old_hash.c_str(),
new_hash.c_str());
}
bool AsyncMigrateKey(const std::string& user_email,
const std::string& old_hash,
const std::string& new_hash,
Delegate* d) {
return CacheCallback(
chromeos::CryptohomeAsyncMigrateKey(user_email.c_str(),
old_hash.c_str(),
new_hash.c_str()),
d,
"Couldn't initiate aync migration of user's key");
}
bool Mount(const std::string& user_email,
const std::string& passhash,
int* error_code) {
return chromeos::CryptohomeMountAllowFail(user_email.c_str(),
passhash.c_str(),
error_code);
}
bool AsyncMount(const std::string& user_email,
const std::string& passhash,
const bool create_if_missing,
Delegate* d) {
return CacheCallback(
chromeos::CryptohomeAsyncMountSafe(user_email.c_str(),
passhash.c_str(),
create_if_missing,
false,
NULL),
d,
"Couldn't initiate async mount of cryptohome.");
}
bool MountForBwsi(int* error_code) {
return chromeos::CryptohomeMountGuest(error_code);
}
bool AsyncMountForBwsi(Delegate* d) {
return CacheCallback(chromeos::CryptohomeAsyncMountGuest(),
d,
"Couldn't initiate async mount of cryptohome.");
}
bool Unmount() {
return chromeos::CryptohomeUnmount();
}
bool Remove(const std::string& user_email) {
return chromeos::CryptohomeRemove(user_email.c_str());
}
bool AsyncRemove(const std::string& user_email, Delegate* d) {
return CacheCallback(
chromeos::CryptohomeAsyncRemove(user_email.c_str()),
d,
"Couldn't initiate async removal of cryptohome.");
}
bool IsMounted() {
return chromeos::CryptohomeIsMounted();
}
CryptohomeBlob GetSystemSalt() {
CryptohomeBlob system_salt;
char* salt_buf;
int salt_len;
bool result = chromeos::CryptohomeGetSystemSaltSafe(&salt_buf, &salt_len);
if (result) {
system_salt.resize(salt_len);
if ((int)system_salt.size() == salt_len) {
memcpy(&system_salt[0], static_cast<const void*>(salt_buf),
salt_len);
} else {
system_salt.clear();
}
}
return system_salt;
}
bool AsyncDoAutomaticFreeDiskSpaceControl(Delegate* d) {
return CacheCallback(
chromeos::CryptohomeAsyncDoAutomaticFreeDiskSpaceControl(),
d,
"Couldn't do automatic free disk space control.");
}
bool TpmIsReady() {
return chromeos::CryptohomeTpmIsReady();
}
bool TpmIsEnabled() {
return chromeos::CryptohomeTpmIsEnabled();
}
bool TpmIsOwned() {
return chromeos::CryptohomeTpmIsOwned();
}
bool TpmIsBeingOwned() {
return chromeos::CryptohomeTpmIsBeingOwned();
}
bool TpmGetPassword(std::string* password) {
char *password_buf;
bool result = chromeos::CryptohomeTpmGetPasswordSafe(&password_buf);
*password = password_buf;
chromeos::CryptohomeFreeString(password_buf);
return result;
}
void TpmCanAttemptOwnership() {
chromeos::CryptohomeTpmCanAttemptOwnership();
}
void TpmClearStoredPassword() {
chromeos::CryptohomeTpmClearStoredPassword();
}
bool InstallAttributesGet(const std::string& name, std::string* value) {
char* local_value;
bool done =
chromeos::CryptohomeInstallAttributesGet(name.c_str(), &local_value);
if (done) {
*value = local_value;
chromeos::CryptohomeFreeString(local_value);
}
return done;
}
bool InstallAttributesSet(const std::string& name, const std::string& value) {
return chromeos::CryptohomeInstallAttributesSet(name.c_str(),
value.c_str());
}
int InstallAttributesCount() {
return chromeos::CryptohomeInstallAttributesCount();
}
bool InstallAttributesFinalize() {
return chromeos::CryptohomeInstallAttributesFinalize();
}
bool InstallAttributesIsReady() {
return chromeos::CryptohomeInstallAttributesIsReady();
}
bool InstallAttributesIsSecure() {
return chromeos::CryptohomeInstallAttributesIsSecure();
}
bool InstallAttributesIsInvalid() {
return chromeos::CryptohomeInstallAttributesIsInvalid();
}
bool InstallAttributesIsFirstInstall() {
return chromeos::CryptohomeInstallAttributesIsFirstInstall();
}
void Pkcs11GetTpmTokenInfo(std::string* label, std::string* user_pin) {
chromeos::CryptohomePkcs11GetTpmTokenInfo(label, user_pin);
}
bool Pkcs11IsTpmTokenReady() {
return chromeos::CryptohomePkcs11IsTpmTokenReady();
}
private:
static void Handler(const chromeos::CryptohomeAsyncCallStatus& event,
void* cryptohome_library) {
CryptohomeLibraryImpl* library =
reinterpret_cast<CryptohomeLibraryImpl*>(cryptohome_library);
library->Dispatch(event);
}
void Init() {
cryptohome_connection_ = chromeos::CryptohomeMonitorSession(&Handler, this);
}
void Dispatch(const chromeos::CryptohomeAsyncCallStatus& event) {
const CallbackMap::iterator callback = callback_map_.find(event.async_id);
if (callback == callback_map_.end()) {
LOG(ERROR) << "Received signal for unknown async_id " << event.async_id;
return;
}
if (callback->second)
callback->second->OnComplete(event.return_status, event.return_code);
callback_map_.erase(callback);
}
bool CacheCallback(int async_id, Delegate* d, const char* error) {
if (async_id == 0) {
LOG(ERROR) << error;
return false;
}
VLOG(1) << "Adding handler for " << async_id;
callback_map_[async_id] = d;
return true;
}
typedef base::hash_map<int, Delegate*> CallbackMap;
mutable CallbackMap callback_map_;
void* cryptohome_connection_;
DISALLOW_COPY_AND_ASSIGN(CryptohomeLibraryImpl);
};
class CryptohomeLibraryStubImpl : public CryptohomeLibrary {
public:
CryptohomeLibraryStubImpl()
: locked_(false) {}
virtual ~CryptohomeLibraryStubImpl() {}
bool CheckKey(const std::string& user_email, const std::string& passhash) {
return true;
}
bool AsyncCheckKey(const std::string& user_email,
const std::string& passhash,
Delegate* callback) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
NewRunnableFunction(&DoStubCallback, callback));
return true;
}
bool MigrateKey(const std::string& user_email,
const std::string& old_hash,
const std::string& new_hash) {
return true;
}
bool AsyncMigrateKey(const std::string& user_email,
const std::string& old_hash,
const std::string& new_hash,
Delegate* callback) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
NewRunnableFunction(&DoStubCallback, callback));
return true;
}
bool Mount(const std::string& user_email,
const std::string& passhash,
int* error_code) {
// For testing password change.
if (user_email ==
CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kLoginUserWithNewPassword)) {
*error_code = kCryptohomeMountErrorKeyFailure;
return false;
}
return true;
}
bool AsyncMount(const std::string& user_email,
const std::string& passhash,
const bool create_if_missing,
Delegate* callback) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
NewRunnableFunction(&DoStubCallback, callback));
return true;
}
bool MountForBwsi(int* error_code) {
return true;
}
bool AsyncMountForBwsi(Delegate* callback) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
NewRunnableFunction(&DoStubCallback, callback));
return true;
}
bool Unmount() {
return true;
}
bool Remove(const std::string& user_email) {
return true;
}
bool AsyncRemove(const std::string& user_email, Delegate* callback) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
NewRunnableFunction(&DoStubCallback, callback));
return true;
}
bool IsMounted() {
return true;
}
CryptohomeBlob GetSystemSalt() {
CryptohomeBlob salt = CryptohomeBlob();
salt.push_back(0);
salt.push_back(0);
return salt;
}
bool AsyncDoAutomaticFreeDiskSpaceControl(Delegate* callback) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
NewRunnableFunction(&DoStubCallback, callback));
return true;
}
// Tpm begin ready after 20-th call.
bool TpmIsReady() {
static int counter = 0;
return ++counter > 20;
}
bool TpmIsEnabled() {
return true;
}
bool TpmIsOwned() {
return true;
}
bool TpmIsBeingOwned() {
return true;
}
bool TpmGetPassword(std::string* password) {
*password = "Stub-TPM-password";
return true;
}
void TpmCanAttemptOwnership() {}
void TpmClearStoredPassword() {}
bool InstallAttributesGet(const std::string& name, std::string* value) {
if (install_attrs_.find(name) != install_attrs_.end()) {
*value = install_attrs_[name];
return true;
}
return false;
}
bool InstallAttributesSet(const std::string& name, const std::string& value) {
install_attrs_[name] = value;
return true;
}
int InstallAttributesCount() {
return install_attrs_.size();
}
bool InstallAttributesFinalize() {
locked_ = true;
return true;
}
bool InstallAttributesIsReady() {
return true;
}
bool InstallAttributesIsSecure() {
return false;
}
bool InstallAttributesIsInvalid() {
return false;
}
bool InstallAttributesIsFirstInstall() {
return !locked_;
}
void Pkcs11GetTpmTokenInfo(std::string* label,
std::string* user_pin) {
*label = "Stub TPM Token";
*user_pin = "012345";
}
bool Pkcs11IsTpmTokenReady() { return true; }
private:
static void DoStubCallback(Delegate* callback) {
if (callback)
callback->OnComplete(true, kCryptohomeMountErrorNone);
}
std::map<std::string, std::string> install_attrs_;
bool locked_;
DISALLOW_COPY_AND_ASSIGN(CryptohomeLibraryStubImpl);
};
CryptohomeLibrary::CryptohomeLibrary() {}
CryptohomeLibrary::~CryptohomeLibrary() {}
// static
CryptohomeLibrary* CryptohomeLibrary::GetImpl(bool stub) {
if (stub)
return new CryptohomeLibraryStubImpl();
else
return new CryptohomeLibraryImpl();
}
} // namespace chromeos