| Index: chromeos/login/auth/cryptohome_authenticator.cc
|
| diff --git a/chromeos/login/auth/cryptohome_authenticator.cc b/chromeos/login/auth/cryptohome_authenticator.cc
|
| index fffa2164d6c9428e3849ec655205aabb57e0bf2b..d00cf29f1aa14af10c3b2326b4ba179dd755a084 100644
|
| --- a/chromeos/login/auth/cryptohome_authenticator.cc
|
| +++ b/chromeos/login/auth/cryptohome_authenticator.cc
|
| @@ -4,6 +4,7 @@
|
|
|
| #include "chromeos/login/auth/cryptohome_authenticator.h"
|
|
|
| +#include "base/basictypes.h"
|
| #include "base/bind.h"
|
| #include "base/files/file_path.h"
|
| #include "base/location.h"
|
| @@ -30,6 +31,14 @@ namespace {
|
| // The label used for the key derived from the user's GAIA credentials.
|
| 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.
|
| // Returns the keys unmodified otherwise.
|
| scoped_ptr<Key> TransformKeyIfNeeded(const Key& key,
|
| @@ -73,14 +82,25 @@ void TriggerResolveWithLoginTimeMarker(
|
| TriggerResolve(attempt, resolver, success, return_code);
|
| }
|
|
|
| -void TriggerResolveWithHashAndLoginTimeMarker(
|
| - const std::string& marker_name,
|
| - AuthAttemptState* attempt,
|
| - scoped_refptr<CryptohomeAuthenticator> resolver,
|
| - bool success,
|
| - cryptohome::MountError return_code,
|
| - const std::string& mount_hash) {
|
| - chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(marker_name, false);
|
| +// Records an error in accessing the user's cryptohome with the given key and
|
| +// calls resolver->Resolve() after adding a login time marker.
|
| +void RecordKeyErrorAndResolve(AuthAttemptState* attempt,
|
| + scoped_refptr<CryptohomeAuthenticator> resolver) {
|
| + chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker("CryptohomeMount-End",
|
| + false);
|
| + attempt->RecordCryptohomeStatus(false /* success */,
|
| + 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);
|
| if (success)
|
| attempt->RecordUsernameHash(mount_hash);
|
| @@ -89,20 +109,23 @@ void TriggerResolveWithHashAndLoginTimeMarker(
|
| resolver->Resolve();
|
| }
|
|
|
| -// Calls cryptohome's mount method.
|
| -void Mount(AuthAttemptState* attempt,
|
| - scoped_refptr<CryptohomeAuthenticator> resolver,
|
| - bool ephemeral,
|
| - bool create_if_nonexistent,
|
| - const std::string& system_salt) {
|
| - chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(
|
| - "CryptohomeMount-Start", false);
|
| +// Calls cryptohome's MountEx() method. The key in |attempt->user_context| must
|
| +// not be a plain text password. If the user provided a plain text password,
|
| +// that password must be transformed to another key type (by salted hashing)
|
| +// before calling this method.
|
| +void DoMount(AuthAttemptState* attempt,
|
| + scoped_refptr<CryptohomeAuthenticator> resolver,
|
| + bool ephemeral,
|
| + 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
|
| // that returns directly would not generate 2 OnLoginSucces() calls.
|
| 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
|
| // 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
|
| @@ -123,10 +146,127 @@ void Mount(AuthAttemptState* attempt,
|
| cryptohome::Identification(attempt->user_context.GetUserID()),
|
| cryptohome::Authorization(auth_key),
|
| mount,
|
| - base::Bind(&TriggerResolveWithHashAndLoginTimeMarker,
|
| - "CryptohomeMount-End",
|
| + base::Bind(&OnMount, attempt, resolver));
|
| +}
|
| +
|
| +// 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,
|
| - resolver));
|
| + resolver,
|
| + ephemeral,
|
| + create_if_nonexistent));
|
| }
|
|
|
| // Calls cryptohome's mount method for guest and also get the user hash from
|
| @@ -252,12 +392,10 @@ void CryptohomeAuthenticator::AuthenticateToLogin(
|
| // Reset the verified flag.
|
| owner_is_verified_ = false;
|
|
|
| - SystemSaltGetter::Get()->GetSystemSalt(
|
| - base::Bind(&Mount,
|
| - current_state_.get(),
|
| - scoped_refptr<CryptohomeAuthenticator>(this),
|
| - false /* ephemeral */,
|
| - false /* create_if_nonexistent */));
|
| + StartMount(current_state_.get(),
|
| + scoped_refptr<CryptohomeAuthenticator>(this),
|
| + false /* ephemeral */,
|
| + false /* create_if_nonexistent */);
|
| }
|
|
|
| void CryptohomeAuthenticator::CompleteLogin(Profile* profile,
|
| @@ -272,12 +410,10 @@ void CryptohomeAuthenticator::CompleteLogin(Profile* profile,
|
| // Reset the verified flag.
|
| owner_is_verified_ = false;
|
|
|
| - SystemSaltGetter::Get()->GetSystemSalt(
|
| - base::Bind(&Mount,
|
| - current_state_.get(),
|
| - scoped_refptr<CryptohomeAuthenticator>(this),
|
| - false /* ephemeral */,
|
| - false /* create_if_nonexistent */));
|
| + StartMount(current_state_.get(),
|
| + scoped_refptr<CryptohomeAuthenticator>(this),
|
| + false /* ephemeral */,
|
| + false /* create_if_nonexistent */);
|
|
|
| // 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
|
| @@ -312,12 +448,10 @@ void CryptohomeAuthenticator::LoginAsSupervisedUser(
|
| false, // online_complete
|
| false)); // user_is_new
|
| remove_user_data_on_failure_ = false;
|
| - SystemSaltGetter::Get()->GetSystemSalt(
|
| - base::Bind(&Mount,
|
| - current_state_.get(),
|
| - scoped_refptr<CryptohomeAuthenticator>(this),
|
| - false /* ephemeral */,
|
| - false /* create_if_nonexistent */));
|
| + StartMount(current_state_.get(),
|
| + scoped_refptr<CryptohomeAuthenticator>(this),
|
| + false /* ephemeral */,
|
| + false /* create_if_nonexistent */);
|
| }
|
|
|
| void CryptohomeAuthenticator::LoginRetailMode() {
|
| @@ -361,12 +495,10 @@ void CryptohomeAuthenticator::LoginAsPublicSession(
|
| false)); // user_is_new
|
| remove_user_data_on_failure_ = false;
|
| ephemeral_mount_attempted_ = true;
|
| - SystemSaltGetter::Get()->GetSystemSalt(
|
| - base::Bind(&Mount,
|
| - current_state_.get(),
|
| - scoped_refptr<CryptohomeAuthenticator>(this),
|
| - true /* ephemeral */,
|
| - true /* create_if_nonexistent */));
|
| + StartMount(current_state_.get(),
|
| + scoped_refptr<CryptohomeAuthenticator>(this),
|
| + true /* ephemeral */,
|
| + true /* create_if_nonexistent */);
|
| }
|
|
|
| void CryptohomeAuthenticator::LoginAsKioskAccount(
|
| @@ -569,12 +701,10 @@ void CryptohomeAuthenticator::Resolve() {
|
| create_if_nonexistent = true;
|
| case RECOVER_MOUNT:
|
| current_state_->ResetCryptohomeStatus();
|
| - SystemSaltGetter::Get()->GetSystemSalt(
|
| - base::Bind(&Mount,
|
| - current_state_.get(),
|
| - scoped_refptr<CryptohomeAuthenticator>(this),
|
| - false /*ephemeral*/,
|
| - create_if_nonexistent));
|
| + StartMount(current_state_.get(),
|
| + scoped_refptr<CryptohomeAuthenticator>(this),
|
| + false /*ephemeral*/,
|
| + create_if_nonexistent);
|
| break;
|
| case NEED_OLD_PW:
|
| task_runner_->PostTask(
|
|
|