Commit 37e866f4 authored by bartfab's avatar bartfab Committed by Commit bot

Make CryptohomeAuthenticator's Login*() methods work with pre-hashed keys

When a user's cryptohome directory is created with a pre-hashed key,
the credentials provided need to be hashed in the same way whenever the
crypthome is to be unlocked/mounted. This CL updates the Login*() methods
in CryptohomeAuthenticator to retrieve key metadata and apply the correct
hashing algorithm to the given credentials. Follow-up CLs will update
the other CryptohomeAuthenticator methods to also work with pre-hashed
keys.

BUG=367847
TEST=Extended unit tests

Review URL: https://codereview.chromium.org/517653002

Cr-Commit-Position: refs/heads/master@{#293227}
parent 8d054025
...@@ -6,11 +6,14 @@ ...@@ -6,11 +6,14 @@
#include <string> #include <string>
#include "base/basictypes.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "chrome/browser/chromeos/login/users/fake_user_manager.h" #include "chrome/browser/chromeos/login/users/fake_user_manager.h"
...@@ -31,6 +34,7 @@ ...@@ -31,6 +34,7 @@
#include "chromeos/cryptohome/mock_homedir_methods.h" #include "chromeos/cryptohome/mock_homedir_methods.h"
#include "chromeos/cryptohome/system_salt_getter.h" #include "chromeos/cryptohome/system_salt_getter.h"
#include "chromeos/dbus/cros_disks_client.h" #include "chromeos/dbus/cros_disks_client.h"
#include "chromeos/dbus/cryptohome/rpc.pb.h"
#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/fake_cryptohome_client.h" #include "chromeos/dbus/fake_cryptohome_client.h"
#include "chromeos/login/auth/key.h" #include "chromeos/login/auth/key.h"
...@@ -52,12 +56,19 @@ ...@@ -52,12 +56,19 @@
using ::testing::Invoke; using ::testing::Invoke;
using ::testing::Return; using ::testing::Return;
using ::testing::WithArg;
using ::testing::_; using ::testing::_;
namespace chromeos { namespace chromeos {
namespace { namespace {
// Label under which the user's key is stored.
const char kCryptohomeGAIAKeyLabel[] = "gaia";
// Salt used by pre-hashed key.
const char kSalt[] = "SALT $$";
// An owner key in PKCS#8 PrivateKeyInfo for testing owner checks. // An owner key in PKCS#8 PrivateKeyInfo for testing owner checks.
const uint8 kOwnerPrivateKey[] = { const uint8 kOwnerPrivateKey[] = {
0x30, 0x82, 0x01, 0x53, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x30, 0x82, 0x01, 0x53, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
...@@ -132,10 +143,9 @@ class CryptohomeAuthenticatorTest : public testing::Test { ...@@ -132,10 +143,9 @@ class CryptohomeAuthenticatorTest : public testing::Test {
ProfileHelper::Get()->SetUserToProfileMappingForTesting(user, &profile_); ProfileHelper::Get()->SetUserToProfileMappingForTesting(user, &profile_);
transformed_key_ = *user_context_.GetKey(); CreateTransformedKey(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF,
transformed_key_.Transform(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, SystemSaltGetter::ConvertRawSaltToHexString(
SystemSaltGetter::ConvertRawSaltToHexString( FakeCryptohomeClient::GetStubSystemSalt()));
FakeCryptohomeClient::GetStubSystemSalt()));
} }
virtual ~CryptohomeAuthenticatorTest() {} virtual ~CryptohomeAuthenticatorTest() {}
...@@ -173,6 +183,12 @@ class CryptohomeAuthenticatorTest : public testing::Test { ...@@ -173,6 +183,12 @@ class CryptohomeAuthenticatorTest : public testing::Test {
mock_homedir_methods_ = NULL; mock_homedir_methods_ = NULL;
} }
void CreateTransformedKey(Key::KeyType type, const std::string& salt) {
user_context_with_transformed_key_ = user_context_;
user_context_with_transformed_key_.GetKey()->Transform(type, salt);
transformed_key_ = *user_context_with_transformed_key_.GetKey();
}
base::FilePath PopulateTempFile(const char* data, int data_len) { base::FilePath PopulateTempFile(const char* data, int data_len) {
base::FilePath out; base::FilePath out;
FILE* tmp_file = base::CreateAndOpenTemporaryFile(&out); FILE* tmp_file = base::CreateAndOpenTemporaryFile(&out);
...@@ -240,6 +256,57 @@ class CryptohomeAuthenticatorTest : public testing::Test { ...@@ -240,6 +256,57 @@ class CryptohomeAuthenticatorTest : public testing::Test {
.RetiresOnSaturation(); .RetiresOnSaturation();
} }
void ExpectGetKeyDataExCall(scoped_ptr<int64> key_type,
scoped_ptr<std::string> salt) {
key_data_.clear();
key_data_.push_back(new cryptohome::RetrievedKeyData(
cryptohome::RetrievedKeyData::TYPE_PASSWORD,
kCryptohomeGAIAKeyLabel,
1));
key_data_.front()->privileges = cryptohome::PRIV_DEFAULT;
key_data_.front()->authorization_types.push_back(
cryptohome::RetrievedKeyData::AUTHORIZATION_TYPE_HMACSHA256);
if (key_type) {
scoped_ptr<cryptohome::RetrievedKeyData::ProviderData> provider_data(
new cryptohome::RetrievedKeyData::ProviderData("type"));
provider_data->number = key_type.Pass();
key_data_.front()->provider_data.push_back(provider_data.release());
}
if (salt) {
scoped_ptr<cryptohome::RetrievedKeyData::ProviderData> provider_data(
new cryptohome::RetrievedKeyData::ProviderData("salt"));
provider_data->bytes = salt.Pass();
key_data_.front()->provider_data.push_back(provider_data.release());
}
EXPECT_CALL(*mock_homedir_methods_, GetKeyDataEx(
cryptohome::Identification(user_context_.GetUserID()),
kCryptohomeGAIAKeyLabel,
_))
.WillOnce(WithArg<2>(Invoke(
this,
&CryptohomeAuthenticatorTest::InvokeGetDataExCallback)));
}
void ExpectMountExCall(bool expect_create_attempt) {
const cryptohome::KeyDefinition auth_key(transformed_key_.GetSecret(),
std::string(),
cryptohome::PRIV_DEFAULT);
cryptohome::MountParameters mount(false /* ephemeral */);
if (expect_create_attempt) {
mount.create_keys.push_back(cryptohome::KeyDefinition(
transformed_key_.GetSecret(),
kCryptohomeGAIAKeyLabel,
cryptohome::PRIV_DEFAULT));
}
EXPECT_CALL(*mock_homedir_methods_,
MountEx(cryptohome::Identification(user_context_.GetUserID()),
cryptohome::Authorization(auth_key),
mount,
_))
.Times(1)
.RetiresOnSaturation();
}
void RunResolve(CryptohomeAuthenticator* auth) { void RunResolve(CryptohomeAuthenticator* auth) {
auth->Resolve(); auth->Resolve();
base::MessageLoop::current()->RunUntilIdle(); base::MessageLoop::current()->RunUntilIdle();
...@@ -263,8 +330,11 @@ class CryptohomeAuthenticatorTest : public testing::Test { ...@@ -263,8 +330,11 @@ class CryptohomeAuthenticatorTest : public testing::Test {
content::TestBrowserThreadBundle thread_bundle_; content::TestBrowserThreadBundle thread_bundle_;
UserContext user_context_; UserContext user_context_;
UserContext user_context_with_transformed_key_;
Key transformed_key_; Key transformed_key_;
ScopedVector<cryptohome::RetrievedKeyData> key_data_;
ScopedDeviceSettingsTestHelper device_settings_test_helper_; ScopedDeviceSettingsTestHelper device_settings_test_helper_;
ScopedTestCrosSettings test_cros_settings_; ScopedTestCrosSettings test_cros_settings_;
...@@ -283,6 +353,14 @@ class CryptohomeAuthenticatorTest : public testing::Test { ...@@ -283,6 +353,14 @@ class CryptohomeAuthenticatorTest : public testing::Test {
FakeCryptohomeClient* fake_cryptohome_client_; FakeCryptohomeClient* fake_cryptohome_client_;
scoped_refptr<ownership::MockOwnerKeyUtil> owner_key_util_; scoped_refptr<ownership::MockOwnerKeyUtil> owner_key_util_;
private:
void InvokeGetDataExCallback(
const cryptohome::HomedirMethods::GetKeyDataCallback& callback) {
callback.Run(true /* success */,
cryptohome::MOUNT_ERROR_NONE,
key_data_.Pass());
}
}; };
TEST_F(CryptohomeAuthenticatorTest, OnAuthSuccess) { TEST_F(CryptohomeAuthenticatorTest, OnAuthSuccess) {
...@@ -533,7 +611,7 @@ TEST_F(CryptohomeAuthenticatorTest, DriveRetailModeLoginButFail) { ...@@ -533,7 +611,7 @@ TEST_F(CryptohomeAuthenticatorTest, DriveRetailModeLoginButFail) {
} }
TEST_F(CryptohomeAuthenticatorTest, DriveDataResync) { TEST_F(CryptohomeAuthenticatorTest, DriveDataResync) {
UserContext expected_user_context(user_context_); UserContext expected_user_context(user_context_with_transformed_key_);
expected_user_context.SetUserIDHash( expected_user_context.SetUserIDHash(
cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername); cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername);
ExpectLoginSuccess(expected_user_context); ExpectLoginSuccess(expected_user_context);
...@@ -548,20 +626,8 @@ TEST_F(CryptohomeAuthenticatorTest, DriveDataResync) { ...@@ -548,20 +626,8 @@ TEST_F(CryptohomeAuthenticatorTest, DriveDataResync) {
// Set up mock homedir methods to respond successfully to a cryptohome create // Set up mock homedir methods to respond successfully to a cryptohome create
// attempt. // attempt.
const cryptohome::KeyDefinition auth_key(transformed_key_.GetSecret(), ExpectGetKeyDataExCall(scoped_ptr<int64>(), scoped_ptr<std::string>());
std::string(), ExpectMountExCall(true /* expect_create_attempt */);
cryptohome::PRIV_DEFAULT);
cryptohome::MountParameters mount(false /* ephemeral */);
mount.create_keys.push_back(cryptohome::KeyDefinition(
transformed_key_.GetSecret(),
"gaia",
cryptohome::PRIV_DEFAULT));
EXPECT_CALL(*mock_homedir_methods_,
MountEx(cryptohome::Identification(user_context_.GetUserID()),
cryptohome::Authorization(auth_key),
mount,
_))
.Times(1);
state_->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone()); state_->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone());
SetAttemptState(auth_.get(), state_.release()); SetAttemptState(auth_.get(), state_.release());
...@@ -598,7 +664,7 @@ TEST_F(CryptohomeAuthenticatorTest, DriveRequestOldPassword) { ...@@ -598,7 +664,7 @@ TEST_F(CryptohomeAuthenticatorTest, DriveRequestOldPassword) {
} }
TEST_F(CryptohomeAuthenticatorTest, DriveDataRecover) { TEST_F(CryptohomeAuthenticatorTest, DriveDataRecover) {
UserContext expected_user_context(user_context_); UserContext expected_user_context(user_context_with_transformed_key_);
expected_user_context.SetUserIDHash( expected_user_context.SetUserIDHash(
cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername); cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername);
ExpectLoginSuccess(expected_user_context); ExpectLoginSuccess(expected_user_context);
...@@ -615,14 +681,8 @@ TEST_F(CryptohomeAuthenticatorTest, DriveDataRecover) { ...@@ -615,14 +681,8 @@ TEST_F(CryptohomeAuthenticatorTest, DriveDataRecover) {
// Set up mock homedir methods to respond successfully to a cryptohome mount // Set up mock homedir methods to respond successfully to a cryptohome mount
// attempt. // attempt.
const cryptohome::KeyDefinition auth_key(transformed_key_.GetSecret(), ExpectGetKeyDataExCall(scoped_ptr<int64>(), scoped_ptr<std::string>());
std::string(), ExpectMountExCall(false /* expect_create_attempt */);
cryptohome::PRIV_DEFAULT);
EXPECT_CALL(*mock_homedir_methods_,
MountEx(cryptohome::Identification(user_context_.GetUserID()),
cryptohome::Authorization(auth_key),
cryptohome::MountParameters(false /* ephemeral */),
_));
state_->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone()); state_->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone());
SetAttemptState(auth_.get(), state_.release()); SetAttemptState(auth_.get(), state_.release());
...@@ -676,7 +736,7 @@ TEST_F(CryptohomeAuthenticatorTest, ResolveCreateNew) { ...@@ -676,7 +736,7 @@ TEST_F(CryptohomeAuthenticatorTest, ResolveCreateNew) {
} }
TEST_F(CryptohomeAuthenticatorTest, DriveCreateForNewUser) { TEST_F(CryptohomeAuthenticatorTest, DriveCreateForNewUser) {
UserContext expected_user_context(user_context_); UserContext expected_user_context(user_context_with_transformed_key_);
expected_user_context.SetUserIDHash( expected_user_context.SetUserIDHash(
cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername); cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername);
ExpectLoginSuccess(expected_user_context); ExpectLoginSuccess(expected_user_context);
...@@ -684,19 +744,8 @@ TEST_F(CryptohomeAuthenticatorTest, DriveCreateForNewUser) { ...@@ -684,19 +744,8 @@ TEST_F(CryptohomeAuthenticatorTest, DriveCreateForNewUser) {
// Set up mock homedir methods to respond successfully to a cryptohome create // Set up mock homedir methods to respond successfully to a cryptohome create
// attempt. // attempt.
const cryptohome::KeyDefinition auth_key(transformed_key_.GetSecret(), ExpectGetKeyDataExCall(scoped_ptr<int64>(), scoped_ptr<std::string>());
std::string(), ExpectMountExCall(true /* expect_create_attempt */);
cryptohome::PRIV_DEFAULT);
cryptohome::MountParameters mount(false /* ephemeral */);
mount.create_keys.push_back(cryptohome::KeyDefinition(
transformed_key_.GetSecret(),
"gaia",
cryptohome::PRIV_DEFAULT));
EXPECT_CALL(*mock_homedir_methods_,
MountEx(cryptohome::Identification(user_context_.GetUserID()),
cryptohome::Authorization(auth_key),
mount,
_));
// Set up state as though a cryptohome mount attempt has occurred // Set up state as though a cryptohome mount attempt has occurred
// and been rejected because the user doesn't exist; additionally, // and been rejected because the user doesn't exist; additionally,
...@@ -749,4 +798,43 @@ TEST_F(CryptohomeAuthenticatorTest, DriveUnlock) { ...@@ -749,4 +798,43 @@ TEST_F(CryptohomeAuthenticatorTest, DriveUnlock) {
base::MessageLoop::current()->Run(); base::MessageLoop::current()->Run();
} }
TEST_F(CryptohomeAuthenticatorTest, DriveLoginWithPreHashedPassword) {
CreateTransformedKey(Key::KEY_TYPE_SALTED_SHA256, kSalt);
UserContext expected_user_context(user_context_with_transformed_key_);
expected_user_context.SetUserIDHash(
cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername);
ExpectLoginSuccess(expected_user_context);
FailOnLoginFailure();
// Set up mock homedir methods to respond with key metadata indicating that a
// pre-hashed key was used to create the cryptohome and allow a successful
// mount when this pre-hashed key is used.
ExpectGetKeyDataExCall(
make_scoped_ptr(new int64(Key::KEY_TYPE_SALTED_SHA256)),
make_scoped_ptr(new std::string(kSalt)));
ExpectMountExCall(false /* expect_create_attempt */);
auth_->AuthenticateToLogin(NULL, user_context_);
base::RunLoop().Run();
}
TEST_F(CryptohomeAuthenticatorTest, FailLoginWithMissingSalt) {
CreateTransformedKey(Key::KEY_TYPE_SALTED_SHA256, kSalt);
FailOnLoginSuccess();
ExpectLoginFailure(AuthFailure(AuthFailure::COULD_NOT_MOUNT_CRYPTOHOME));
// Set up mock homedir methods to respond with key metadata indicating that a
// pre-hashed key was used to create the cryptohome but without the required
// salt.
ExpectGetKeyDataExCall(
make_scoped_ptr(new int64(Key::KEY_TYPE_SALTED_SHA256)),
scoped_ptr<std::string>());
auth_->AuthenticateToLogin(NULL, user_context_);
base::RunLoop().Run();
}
} // namespace chromeos } // namespace chromeos
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "chromeos/cryptohome/mock_homedir_methods.h" #include "chromeos/cryptohome/mock_homedir_methods.h"
#include "base/memory/scoped_vector.h"
#include "chromeos/cryptohome/cryptohome_parameters.h"
#include "chromeos/cryptohome/mock_async_method_caller.h" #include "chromeos/cryptohome/mock_async_method_caller.h"
using ::testing::Invoke; using ::testing::Invoke;
...@@ -20,6 +22,8 @@ MockHomedirMethods::~MockHomedirMethods() {} ...@@ -20,6 +22,8 @@ MockHomedirMethods::~MockHomedirMethods() {}
void MockHomedirMethods::SetUp(bool success, MountError return_code) { void MockHomedirMethods::SetUp(bool success, MountError return_code) {
success_ = success; success_ = success;
return_code_ = return_code; return_code_ = return_code;
ON_CALL(*this, GetKeyDataEx(_, _, _)).WillByDefault(
WithArgs<2>(Invoke(this, &MockHomedirMethods::DoGetDataCallback)));
ON_CALL(*this, CheckKeyEx(_, _, _)).WillByDefault( ON_CALL(*this, CheckKeyEx(_, _, _)).WillByDefault(
WithArgs<2>(Invoke(this, &MockHomedirMethods::DoCallback))); WithArgs<2>(Invoke(this, &MockHomedirMethods::DoCallback)));
ON_CALL(*this, MountEx(_, _, _, _)).WillByDefault( ON_CALL(*this, MountEx(_, _, _, _)).WillByDefault(
...@@ -36,6 +40,10 @@ void MockHomedirMethods::DoCallback(const Callback& callback) { ...@@ -36,6 +40,10 @@ void MockHomedirMethods::DoCallback(const Callback& callback) {
callback.Run(success_, return_code_); callback.Run(success_, return_code_);
} }
void MockHomedirMethods::DoGetDataCallback(const GetKeyDataCallback& callback) {
callback.Run(success_, return_code_, ScopedVector<RetrievedKeyData>());
}
void MockHomedirMethods::DoMountCallback(const MountCallback& callback) { void MockHomedirMethods::DoMountCallback(const MountCallback& callback) {
callback.Run( callback.Run(
success_, return_code_, MockAsyncMethodCaller::kFakeSanitizedUsername); success_, return_code_, MockAsyncMethodCaller::kFakeSanitizedUsername);
......
...@@ -57,6 +57,7 @@ class CHROMEOS_EXPORT MockHomedirMethods : public HomedirMethods { ...@@ -57,6 +57,7 @@ class CHROMEOS_EXPORT MockHomedirMethods : public HomedirMethods {
MountError return_code_; MountError return_code_;
void DoCallback(const Callback& callback); void DoCallback(const Callback& callback);
void DoGetDataCallback(const GetKeyDataCallback& callback);
void DoMountCallback(const MountCallback& callback); void DoMountCallback(const MountCallback& callback);
DISALLOW_COPY_AND_ASSIGN(MockHomedirMethods); DISALLOW_COPY_AND_ASSIGN(MockHomedirMethods);
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "chromeos/login/auth/cryptohome_authenticator.h" #include "chromeos/login/auth/cryptohome_authenticator.h"
#include "base/basictypes.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/location.h" #include "base/location.h"
...@@ -30,6 +31,14 @@ namespace { ...@@ -30,6 +31,14 @@ namespace {
// The label used for the key derived from the user's GAIA credentials. // The label used for the key derived from the user's GAIA credentials.
const char kCryptohomeGAIAKeyLabel[] = "gaia"; const char kCryptohomeGAIAKeyLabel[] = "gaia";
// The name under which the type of key generated from the user's GAIA
// credentials is stored.
const char kKeyProviderDataTypeName[] = "type";
// The name under which the salt used to generate a key from the user's GAIA
// credentials is stored.
const char kKeyProviderDataSaltName[] = "salt";
// Hashes |key| with |system_salt| if it its type is KEY_TYPE_PASSWORD_PLAIN. // Hashes |key| with |system_salt| if it its type is KEY_TYPE_PASSWORD_PLAIN.
// Returns the keys unmodified otherwise. // Returns the keys unmodified otherwise.
scoped_ptr<Key> TransformKeyIfNeeded(const Key& key, scoped_ptr<Key> TransformKeyIfNeeded(const Key& key,
...@@ -73,14 +82,25 @@ void TriggerResolveWithLoginTimeMarker( ...@@ -73,14 +82,25 @@ void TriggerResolveWithLoginTimeMarker(
TriggerResolve(attempt, resolver, success, return_code); TriggerResolve(attempt, resolver, success, return_code);
} }
void TriggerResolveWithHashAndLoginTimeMarker( // Records an error in accessing the user's cryptohome with the given key and
const std::string& marker_name, // calls resolver->Resolve() after adding a login time marker.
AuthAttemptState* attempt, void RecordKeyErrorAndResolve(AuthAttemptState* attempt,
scoped_refptr<CryptohomeAuthenticator> resolver, scoped_refptr<CryptohomeAuthenticator> resolver) {
bool success, chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker("CryptohomeMount-End",
cryptohome::MountError return_code, false);
const std::string& mount_hash) { attempt->RecordCryptohomeStatus(false /* success */,
chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(marker_name, false); cryptohome::MOUNT_ERROR_KEY_FAILURE);
resolver->Resolve();
}
// Callback invoked when cryptohome's MountEx() method has finished.
void OnMount(AuthAttemptState* attempt,
scoped_refptr<CryptohomeAuthenticator> resolver,
bool success,
cryptohome::MountError return_code,
const std::string& mount_hash) {
chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker("CryptohomeMount-End",
false);
attempt->RecordCryptohomeStatus(success, return_code); attempt->RecordCryptohomeStatus(success, return_code);
if (success) if (success)
attempt->RecordUsernameHash(mount_hash); attempt->RecordUsernameHash(mount_hash);
...@@ -89,20 +109,23 @@ void TriggerResolveWithHashAndLoginTimeMarker( ...@@ -89,20 +109,23 @@ void TriggerResolveWithHashAndLoginTimeMarker(
resolver->Resolve(); resolver->Resolve();
} }
// Calls cryptohome's mount method. // Calls cryptohome's MountEx() method. The key in |attempt->user_context| must
void Mount(AuthAttemptState* attempt, // not be a plain text password. If the user provided a plain text password,
scoped_refptr<CryptohomeAuthenticator> resolver, // that password must be transformed to another key type (by salted hashing)
bool ephemeral, // before calling this method.
bool create_if_nonexistent, void DoMount(AuthAttemptState* attempt,
const std::string& system_salt) { scoped_refptr<CryptohomeAuthenticator> resolver,
chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker( bool ephemeral,
"CryptohomeMount-Start", false); bool create_if_nonexistent) {
const Key* key = attempt->user_context.GetKey();
// If the |key| is a plain text password, crash rather than attempting to
// mount the cryptohome with a plain text password.
CHECK_NE(Key::KEY_TYPE_PASSWORD_PLAIN, key->GetKeyType());
// Set state that username_hash is requested here so that test implementation // Set state that username_hash is requested here so that test implementation
// that returns directly would not generate 2 OnLoginSucces() calls. // that returns directly would not generate 2 OnLoginSucces() calls.
attempt->UsernameHashRequested(); attempt->UsernameHashRequested();
scoped_ptr<Key> key =
TransformKeyIfNeeded(*attempt->user_context.GetKey(), system_salt);
// Set the authentication's key label to an empty string, which is a wildcard // Set the authentication's key label to an empty string, which is a wildcard
// allowing any key to match. This is necessary because cryptohomes created by // allowing any key to match. This is necessary because cryptohomes created by
// Chrome OS M38 and older will have a legacy key with no label while those // Chrome OS M38 and older will have a legacy key with no label while those
...@@ -123,10 +146,127 @@ void Mount(AuthAttemptState* attempt, ...@@ -123,10 +146,127 @@ void Mount(AuthAttemptState* attempt,
cryptohome::Identification(attempt->user_context.GetUserID()), cryptohome::Identification(attempt->user_context.GetUserID()),
cryptohome::Authorization(auth_key), cryptohome::Authorization(auth_key),
mount, mount,
base::Bind(&TriggerResolveWithHashAndLoginTimeMarker, base::Bind(&OnMount, attempt, resolver));
"CryptohomeMount-End", }
// Callback invoked when the system salt has been retrieved. Transforms the key
// in |attempt->user_context| using Chrome's default hashing algorithm and the
// system salt, then calls MountEx().
void OnGetSystemSalt(AuthAttemptState* attempt,
scoped_refptr<CryptohomeAuthenticator> resolver,
bool ephemeral,
bool create_if_nonexistent,
const std::string& system_salt) {
DCHECK_EQ(Key::KEY_TYPE_PASSWORD_PLAIN,
attempt->user_context.GetKey()->GetKeyType());
attempt->user_context.GetKey()->Transform(
Key::KEY_TYPE_SALTED_SHA256_TOP_HALF,
system_salt);
DoMount(attempt, resolver, ephemeral, create_if_nonexistent);
}
// Callback invoked when cryptohome's GetKeyDataEx() method has finished.
// * If GetKeyDataEx() returned metadata indicating the hashing algorithm and
// salt that were used to generate the key for this user's cryptohome,
// transforms the key in |attempt->user_context| with the same parameters.
// * Otherwise, starts the retrieval of the system salt so that the key in
// |attempt->user_context| can be transformed with Chrome's default hashing
// algorithm and the system salt.
// The resulting key is then passed to cryptohome's MountEx().
void OnGetKeyDataEx(AuthAttemptState* attempt,
scoped_refptr<CryptohomeAuthenticator> resolver,
bool ephemeral,
bool create_if_nonexistent,
bool success,
cryptohome::MountError return_code,
ScopedVector<cryptohome::RetrievedKeyData> key_data) {
if (success) {
if (key_data.size() == 1) {
cryptohome::RetrievedKeyData* key_data_entry = key_data.front();
DCHECK_EQ(kCryptohomeGAIAKeyLabel, key_data_entry->label);
// Extract the key type and salt from |key_data|, if present.
scoped_ptr<int64> type;
scoped_ptr<std::string> salt;
for (ScopedVector<cryptohome::RetrievedKeyData::ProviderData>::
const_iterator it = key_data_entry->provider_data.begin();
it != key_data_entry->provider_data.end(); ++it) {
if ((*it)->name == kKeyProviderDataTypeName) {
if ((*it)->number)
type.reset(new int64(*(*it)->number));
else
NOTREACHED();
} else if ((*it)->name == kKeyProviderDataSaltName) {
if ((*it)->bytes)
salt.reset(new std::string(*(*it)->bytes));
else
NOTREACHED();
}
}
if (type) {
if (*type < 0 || *type >= Key::KEY_TYPE_COUNT) {
LOG(ERROR) << "Invalid key type: " << *type;
RecordKeyErrorAndResolve(attempt, resolver);
return;
}
if (!salt) {
LOG(ERROR) << "Missing salt.";
RecordKeyErrorAndResolve(attempt, resolver);
return;
}
attempt->user_context.GetKey()->Transform(
static_cast<Key::KeyType>(*type),
*salt);
DoMount(attempt, resolver, ephemeral, create_if_nonexistent);
return;
}
} else {
LOG(ERROR) << "GetKeyDataEx() returned " << key_data.size()
<< " entries.";
}
}
SystemSaltGetter::Get()->GetSystemSalt(base::Bind(&OnGetSystemSalt,
attempt,
resolver,
ephemeral,
create_if_nonexistent));
}
// Starts the process that will mount a user's cryptohome.
// * If the key in |attempt->user_context| is not a plain text password,
// cryptohome's MountEx() method is called directly with the key.
// * Otherwise, the key must be transformed (by salted hashing) before being
// passed to MountEx(). In that case, cryptohome's GetKeyDataEx() method is
// called to retrieve metadata indicating the hashing algorithm and salt that
// were used to generate the key for this user's cryptohome and the key is
// transformed accordingly before calling MountEx().
void StartMount(AuthAttemptState* attempt,
scoped_refptr<CryptohomeAuthenticator> resolver,
bool ephemeral,
bool create_if_nonexistent) {
chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(
"CryptohomeMount-Start", false);
if (attempt->user_context.GetKey()->GetKeyType() !=
Key::KEY_TYPE_PASSWORD_PLAIN) {
DoMount(attempt, resolver, ephemeral, create_if_nonexistent);
return;
}
cryptohome::HomedirMethods::GetInstance()->GetKeyDataEx(
cryptohome::Identification(attempt->user_context.GetUserID()),
kCryptohomeGAIAKeyLabel,
base::Bind(&OnGetKeyDataEx,
attempt, attempt,
resolver)); resolver,
ephemeral,
create_if_nonexistent));
} }
// Calls cryptohome's mount method for guest and also get the user hash from // Calls cryptohome's mount method for guest and also get the user hash from
...@@ -252,12 +392,10 @@ void CryptohomeAuthenticator::AuthenticateToLogin( ...@@ -252,12 +392,10 @@ void CryptohomeAuthenticator::AuthenticateToLogin(
// Reset the verified flag. // Reset the verified flag.
owner_is_verified_ = false; owner_is_verified_ = false;
SystemSaltGetter::Get()->GetSystemSalt( StartMount(current_state_.get(),
base::Bind(&Mount, scoped_refptr<CryptohomeAuthenticator>(this),
current_state_.get(), false /* ephemeral */,
scoped_refptr<CryptohomeAuthenticator>(this), false /* create_if_nonexistent */);
false /* ephemeral */,
false /* create_if_nonexistent */));
} }
void CryptohomeAuthenticator::CompleteLogin(Profile* profile, void CryptohomeAuthenticator::CompleteLogin(Profile* profile,
...@@ -272,12 +410,10 @@ void CryptohomeAuthenticator::CompleteLogin(Profile* profile, ...@@ -272,12 +410,10 @@ void CryptohomeAuthenticator::CompleteLogin(Profile* profile,
// Reset the verified flag. // Reset the verified flag.
owner_is_verified_ = false; owner_is_verified_ = false;
SystemSaltGetter::Get()->GetSystemSalt( StartMount(current_state_.get(),
base::Bind(&Mount, scoped_refptr<CryptohomeAuthenticator>(this),
current_state_.get(), false /* ephemeral */,
scoped_refptr<CryptohomeAuthenticator>(this), false /* create_if_nonexistent */);
false /* ephemeral */,
false /* create_if_nonexistent */));
// For login completion from extension, we just need to resolve the current // For login completion from extension, we just need to resolve the current
// auth attempt state, the rest of OAuth related tasks will be done in // auth attempt state, the rest of OAuth related tasks will be done in
...@@ -312,12 +448,10 @@ void CryptohomeAuthenticator::LoginAsSupervisedUser( ...@@ -312,12 +448,10 @@ void CryptohomeAuthenticator::LoginAsSupervisedUser(
false, // online_complete false, // online_complete
false)); // user_is_new false)); // user_is_new
remove_user_data_on_failure_ = false; remove_user_data_on_failure_ = false;
SystemSaltGetter::Get()->GetSystemSalt( StartMount(current_state_.get(),
base::Bind(&Mount, scoped_refptr<CryptohomeAuthenticator>(this),
current_state_.get(), false /* ephemeral */,
scoped_refptr<CryptohomeAuthenticator>(this), false /* create_if_nonexistent */);
false /* ephemeral */,
false /* create_if_nonexistent */));
} }
void CryptohomeAuthenticator::LoginRetailMode() { void CryptohomeAuthenticator::LoginRetailMode() {
...@@ -361,12 +495,10 @@ void CryptohomeAuthenticator::LoginAsPublicSession( ...@@ -361,12 +495,10 @@ void CryptohomeAuthenticator::LoginAsPublicSession(
false)); // user_is_new false)); // user_is_new
remove_user_data_on_failure_ = false; remove_user_data_on_failure_ = false;
ephemeral_mount_attempted_ = true; ephemeral_mount_attempted_ = true;
SystemSaltGetter::Get()->GetSystemSalt( StartMount(current_state_.get(),
base::Bind(&Mount, scoped_refptr<CryptohomeAuthenticator>(this),
current_state_.get(), true /* ephemeral */,
scoped_refptr<CryptohomeAuthenticator>(this), true /* create_if_nonexistent */);
true /* ephemeral */,
true /* create_if_nonexistent */));
} }
void CryptohomeAuthenticator::LoginAsKioskAccount( void CryptohomeAuthenticator::LoginAsKioskAccount(
...@@ -569,12 +701,10 @@ void CryptohomeAuthenticator::Resolve() { ...@@ -569,12 +701,10 @@ void CryptohomeAuthenticator::Resolve() {
create_if_nonexistent = true; create_if_nonexistent = true;
case RECOVER_MOUNT: case RECOVER_MOUNT:
current_state_->ResetCryptohomeStatus(); current_state_->ResetCryptohomeStatus();
SystemSaltGetter::Get()->GetSystemSalt( StartMount(current_state_.get(),
base::Bind(&Mount, scoped_refptr<CryptohomeAuthenticator>(this),
current_state_.get(), false /*ephemeral*/,
scoped_refptr<CryptohomeAuthenticator>(this), create_if_nonexistent);
false /*ephemeral*/,
create_if_nonexistent));
break; break;
case NEED_OLD_PW: case NEED_OLD_PW:
task_runner_->PostTask( task_runner_->PostTask(
......
...@@ -7,9 +7,9 @@ ...@@ -7,9 +7,9 @@
#include <string> #include <string>
#include "base/basictypes.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/gtest_prod_util.h" #include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "base/task_runner.h" #include "base/task_runner.h"
......
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