Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(142)

Unified Diff: chromeos/login/auth/cryptohome_authenticator.cc

Issue 517653002: Make CryptohomeAuthenticator's Login*() methods work with pre-hashed keys (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@d_3_367847_add_sha256_key_type
Patch Set: Addressed comments. Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chromeos/login/auth/cryptohome_authenticator.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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(
« no previous file with comments | « chromeos/login/auth/cryptohome_authenticator.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698