Index: chrome/browser/chromeos/login/auth/cryptohome_authenticator_unittest.cc |
diff --git a/chrome/browser/chromeos/login/auth/cryptohome_authenticator_unittest.cc b/chrome/browser/chromeos/login/auth/cryptohome_authenticator_unittest.cc |
index 634cd41e4c485768ab4aa95b96cacd7c5da9f5d4..454ffdc3a5a59166bca25b4b54a46b85a44261c8 100644 |
--- a/chrome/browser/chromeos/login/auth/cryptohome_authenticator_unittest.cc |
+++ b/chrome/browser/chromeos/login/auth/cryptohome_authenticator_unittest.cc |
@@ -6,11 +6,14 @@ |
#include <string> |
+#include "base/basictypes.h" |
#include "base/command_line.h" |
#include "base/files/file_path.h" |
#include "base/files/file_util.h" |
#include "base/memory/scoped_ptr.h" |
+#include "base/memory/scoped_vector.h" |
#include "base/message_loop/message_loop.h" |
+#include "base/run_loop.h" |
#include "base/strings/string_util.h" |
#include "base/strings/stringprintf.h" |
#include "chrome/browser/chromeos/login/users/fake_user_manager.h" |
@@ -31,6 +34,7 @@ |
#include "chromeos/cryptohome/mock_homedir_methods.h" |
#include "chromeos/cryptohome/system_salt_getter.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/fake_cryptohome_client.h" |
#include "chromeos/login/auth/key.h" |
@@ -52,12 +56,19 @@ |
using ::testing::Invoke; |
using ::testing::Return; |
+using ::testing::WithArg; |
using ::testing::_; |
namespace chromeos { |
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. |
const uint8 kOwnerPrivateKey[] = { |
0x30, 0x82, 0x01, 0x53, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, |
@@ -132,10 +143,9 @@ class CryptohomeAuthenticatorTest : public testing::Test { |
ProfileHelper::Get()->SetUserToProfileMappingForTesting(user, &profile_); |
- transformed_key_ = *user_context_.GetKey(); |
- transformed_key_.Transform(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, |
- SystemSaltGetter::ConvertRawSaltToHexString( |
- FakeCryptohomeClient::GetStubSystemSalt())); |
+ CreateTransformedKey(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, |
+ SystemSaltGetter::ConvertRawSaltToHexString( |
+ FakeCryptohomeClient::GetStubSystemSalt())); |
} |
virtual ~CryptohomeAuthenticatorTest() {} |
@@ -173,6 +183,12 @@ class CryptohomeAuthenticatorTest : public testing::Test { |
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 out; |
FILE* tmp_file = base::CreateAndOpenTemporaryFile(&out); |
@@ -240,6 +256,57 @@ class CryptohomeAuthenticatorTest : public testing::Test { |
.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) { |
auth->Resolve(); |
base::MessageLoop::current()->RunUntilIdle(); |
@@ -263,8 +330,11 @@ class CryptohomeAuthenticatorTest : public testing::Test { |
content::TestBrowserThreadBundle thread_bundle_; |
UserContext user_context_; |
+ UserContext user_context_with_transformed_key_; |
Key transformed_key_; |
+ ScopedVector<cryptohome::RetrievedKeyData> key_data_; |
+ |
ScopedDeviceSettingsTestHelper device_settings_test_helper_; |
ScopedTestCrosSettings test_cros_settings_; |
@@ -283,6 +353,14 @@ class CryptohomeAuthenticatorTest : public testing::Test { |
FakeCryptohomeClient* fake_cryptohome_client_; |
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) { |
@@ -533,7 +611,7 @@ TEST_F(CryptohomeAuthenticatorTest, DriveRetailModeLoginButFail) { |
} |
TEST_F(CryptohomeAuthenticatorTest, DriveDataResync) { |
- UserContext expected_user_context(user_context_); |
+ UserContext expected_user_context(user_context_with_transformed_key_); |
expected_user_context.SetUserIDHash( |
cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername); |
ExpectLoginSuccess(expected_user_context); |
@@ -548,20 +626,8 @@ TEST_F(CryptohomeAuthenticatorTest, DriveDataResync) { |
// Set up mock homedir methods to respond successfully to a cryptohome create |
// attempt. |
- const cryptohome::KeyDefinition auth_key(transformed_key_.GetSecret(), |
- std::string(), |
- 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); |
+ ExpectGetKeyDataExCall(scoped_ptr<int64>(), scoped_ptr<std::string>()); |
+ ExpectMountExCall(true /* expect_create_attempt */); |
state_->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone()); |
SetAttemptState(auth_.get(), state_.release()); |
@@ -598,7 +664,7 @@ TEST_F(CryptohomeAuthenticatorTest, DriveRequestOldPassword) { |
} |
TEST_F(CryptohomeAuthenticatorTest, DriveDataRecover) { |
- UserContext expected_user_context(user_context_); |
+ UserContext expected_user_context(user_context_with_transformed_key_); |
expected_user_context.SetUserIDHash( |
cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername); |
ExpectLoginSuccess(expected_user_context); |
@@ -615,14 +681,8 @@ TEST_F(CryptohomeAuthenticatorTest, DriveDataRecover) { |
// Set up mock homedir methods to respond successfully to a cryptohome mount |
// attempt. |
- const cryptohome::KeyDefinition auth_key(transformed_key_.GetSecret(), |
- std::string(), |
- cryptohome::PRIV_DEFAULT); |
- EXPECT_CALL(*mock_homedir_methods_, |
- MountEx(cryptohome::Identification(user_context_.GetUserID()), |
- cryptohome::Authorization(auth_key), |
- cryptohome::MountParameters(false /* ephemeral */), |
- _)); |
+ ExpectGetKeyDataExCall(scoped_ptr<int64>(), scoped_ptr<std::string>()); |
+ ExpectMountExCall(false /* expect_create_attempt */); |
state_->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone()); |
SetAttemptState(auth_.get(), state_.release()); |
@@ -676,7 +736,7 @@ TEST_F(CryptohomeAuthenticatorTest, ResolveCreateNew) { |
} |
TEST_F(CryptohomeAuthenticatorTest, DriveCreateForNewUser) { |
- UserContext expected_user_context(user_context_); |
+ UserContext expected_user_context(user_context_with_transformed_key_); |
expected_user_context.SetUserIDHash( |
cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername); |
ExpectLoginSuccess(expected_user_context); |
@@ -684,19 +744,8 @@ TEST_F(CryptohomeAuthenticatorTest, DriveCreateForNewUser) { |
// Set up mock homedir methods to respond successfully to a cryptohome create |
// attempt. |
- const cryptohome::KeyDefinition auth_key(transformed_key_.GetSecret(), |
- std::string(), |
- 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, |
- _)); |
+ ExpectGetKeyDataExCall(scoped_ptr<int64>(), scoped_ptr<std::string>()); |
+ ExpectMountExCall(true /* expect_create_attempt */); |
// Set up state as though a cryptohome mount attempt has occurred |
// and been rejected because the user doesn't exist; additionally, |
@@ -749,4 +798,43 @@ TEST_F(CryptohomeAuthenticatorTest, DriveUnlock) { |
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 |