blob: 2beca267fad4a3e3503896ef735d541c1ba8bc93 [file] [log] [blame]
// Copyright 2014 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 "chromeos/login/auth/extended_authenticator_impl.h"
#include <stddef.h>
#include "base/bind.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "chromeos/cryptohome/async_method_caller.h"
#include "chromeos/cryptohome/cryptohome_parameters.h"
#include "chromeos/cryptohome/cryptohome_util.h"
#include "chromeos/cryptohome/homedir_methods.h"
#include "chromeos/cryptohome/system_salt_getter.h"
#include "chromeos/dbus/cryptohome/cryptohome_client.h"
#include "chromeos/login/auth/auth_status_consumer.h"
#include "chromeos/login/auth/cryptohome_parameter_utils.h"
#include "chromeos/login/auth/key.h"
#include "chromeos/login/auth/login_event_recorder.h"
#include "chromeos/login/auth/user_context.h"
#include "components/account_id/account_id.h"
#include "crypto/sha2.h"
#include "google_apis/gaia/gaia_auth_util.h"
namespace chromeos {
namespace {
void RecordStartMarker(const std::string& marker) {
std::string full_marker = "Cryptohome-";
full_marker.append(marker);
full_marker.append("-Start");
chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(full_marker, false);
}
void RecordEndMarker(const std::string& marker) {
std::string full_marker = "Cryptohome-";
full_marker.append(marker);
full_marker.append("-End");
chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(full_marker, false);
}
} // namespace
// static
scoped_refptr<ExtendedAuthenticatorImpl> ExtendedAuthenticatorImpl::Create(
NewAuthStatusConsumer* consumer) {
auto extended_authenticator =
base::WrapRefCounted(new ExtendedAuthenticatorImpl(consumer));
SystemSaltGetter::Get()->GetSystemSalt(base::BindOnce(
&ExtendedAuthenticatorImpl::OnSaltObtained, extended_authenticator));
return extended_authenticator;
}
// static
scoped_refptr<ExtendedAuthenticatorImpl> ExtendedAuthenticatorImpl::Create(
AuthStatusConsumer* consumer) {
auto extended_authenticator =
base::WrapRefCounted(new ExtendedAuthenticatorImpl(consumer));
SystemSaltGetter::Get()->GetSystemSalt(base::BindOnce(
&ExtendedAuthenticatorImpl::OnSaltObtained, extended_authenticator));
return extended_authenticator;
}
ExtendedAuthenticatorImpl::ExtendedAuthenticatorImpl(
NewAuthStatusConsumer* consumer)
: salt_obtained_(false), consumer_(consumer), old_consumer_(NULL) {
}
ExtendedAuthenticatorImpl::ExtendedAuthenticatorImpl(
AuthStatusConsumer* consumer)
: salt_obtained_(false), consumer_(NULL), old_consumer_(consumer) {
}
void ExtendedAuthenticatorImpl::SetConsumer(AuthStatusConsumer* consumer) {
old_consumer_ = consumer;
}
void ExtendedAuthenticatorImpl::AuthenticateToMount(
const UserContext& context,
ResultCallback success_callback) {
TransformKeyIfNeeded(
context, base::BindOnce(&ExtendedAuthenticatorImpl::DoAuthenticateToMount,
this, std::move(success_callback)));
}
void ExtendedAuthenticatorImpl::AuthenticateToCheck(
const UserContext& context,
base::OnceClosure success_callback) {
TransformKeyIfNeeded(
context, base::BindOnce(&ExtendedAuthenticatorImpl::DoAuthenticateToCheck,
this, std::move(success_callback)));
}
void ExtendedAuthenticatorImpl::AddKey(const UserContext& context,
const cryptohome::KeyDefinition& key,
bool clobber_if_exists,
base::OnceClosure success_callback) {
TransformKeyIfNeeded(
context, base::BindOnce(&ExtendedAuthenticatorImpl::DoAddKey, this, key,
clobber_if_exists, std::move(success_callback)));
}
void ExtendedAuthenticatorImpl::UpdateKeyAuthorized(
const UserContext& context,
const cryptohome::KeyDefinition& key,
const std::string& signature,
base::OnceClosure success_callback) {
TransformKeyIfNeeded(
context,
base::BindOnce(&ExtendedAuthenticatorImpl::DoUpdateKeyAuthorized, this,
key, signature, std::move(success_callback)));
}
void ExtendedAuthenticatorImpl::RemoveKey(const UserContext& context,
const std::string& key_to_remove,
base::OnceClosure success_callback) {
TransformKeyIfNeeded(
context, base::BindOnce(&ExtendedAuthenticatorImpl::DoRemoveKey, this,
key_to_remove, std::move(success_callback)));
}
void ExtendedAuthenticatorImpl::TransformKeyIfNeeded(
const UserContext& user_context,
ContextCallback callback) {
if (user_context.GetKey()->GetKeyType() != Key::KEY_TYPE_PASSWORD_PLAIN) {
std::move(callback).Run(user_context);
return;
}
if (!salt_obtained_) {
system_salt_callbacks_.push_back(
base::BindOnce(&ExtendedAuthenticatorImpl::TransformKeyIfNeeded, this,
user_context, std::move(callback)));
return;
}
UserContext transformed_context = user_context;
transformed_context.GetKey()->Transform(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF,
system_salt_);
std::move(callback).Run(transformed_context);
}
ExtendedAuthenticatorImpl::~ExtendedAuthenticatorImpl() = default;
void ExtendedAuthenticatorImpl::OnSaltObtained(const std::string& system_salt) {
salt_obtained_ = true;
system_salt_ = system_salt;
for (auto& callback : system_salt_callbacks_)
std::move(callback).Run();
system_salt_callbacks_.clear();
}
void ExtendedAuthenticatorImpl::DoAuthenticateToMount(
ResultCallback success_callback,
const UserContext& user_context) {
RecordStartMarker("MountEx");
const Key* const key = user_context.GetKey();
CryptohomeClient::Get()->MountEx(
cryptohome::CreateAccountIdentifierFromAccountId(
user_context.GetAccountId()),
cryptohome::CreateAuthorizationRequest(key->GetLabel(), key->GetSecret()),
cryptohome::MountRequest(),
base::BindOnce(&ExtendedAuthenticatorImpl::OnMountComplete, this,
"MountEx", user_context, std::move(success_callback)));
}
void ExtendedAuthenticatorImpl::DoAuthenticateToCheck(
base::OnceClosure success_callback,
const UserContext& user_context) {
RecordStartMarker("CheckKeyEx");
cryptohome::HomedirMethods::GetInstance()->CheckKeyEx(
cryptohome::Identification(user_context.GetAccountId()),
cryptohome::CreateAuthorizationRequestFromKeyDef(
cryptohome_parameter_utils::CreateAuthorizationKeyDefFromUserContext(
user_context)),
cryptohome::CheckKeyRequest(),
base::BindOnce(&ExtendedAuthenticatorImpl::OnOperationComplete, this,
"CheckKeyEx", user_context, std::move(success_callback)));
}
void ExtendedAuthenticatorImpl::DoAddKey(const cryptohome::KeyDefinition& key,
bool clobber_if_exists,
base::OnceClosure success_callback,
const UserContext& user_context) {
RecordStartMarker("AddKeyEx");
cryptohome::AddKeyRequest request;
cryptohome::KeyDefinitionToKey(key, request.mutable_key());
request.set_clobber_if_exists(clobber_if_exists);
const Key* const auth_key = user_context.GetKey();
cryptohome::HomedirMethods::GetInstance()->AddKeyEx(
cryptohome::Identification(user_context.GetAccountId()),
cryptohome::CreateAuthorizationRequest(auth_key->GetLabel(),
auth_key->GetSecret()),
request,
base::BindOnce(&ExtendedAuthenticatorImpl::OnOperationComplete, this,
"AddKeyEx", user_context, std::move(success_callback)));
}
void ExtendedAuthenticatorImpl::DoUpdateKeyAuthorized(
const cryptohome::KeyDefinition& key,
const std::string& signature,
base::OnceClosure success_callback,
const UserContext& user_context) {
RecordStartMarker("UpdateKeyAuthorized");
const Key* const auth_key = user_context.GetKey();
cryptohome::UpdateKeyRequest request;
cryptohome::KeyDefinitionToKey(key, request.mutable_changes());
request.set_authorization_signature(signature);
cryptohome::HomedirMethods::GetInstance()->UpdateKeyEx(
cryptohome::Identification(user_context.GetAccountId()),
cryptohome::CreateAuthorizationRequest(auth_key->GetLabel(),
auth_key->GetSecret()),
request,
base::BindOnce(&ExtendedAuthenticatorImpl::OnOperationComplete, this,
"UpdateKeyAuthorized", user_context,
std::move(success_callback)));
}
void ExtendedAuthenticatorImpl::DoRemoveKey(const std::string& key_to_remove,
base::OnceClosure success_callback,
const UserContext& user_context) {
RecordStartMarker("RemoveKeyEx");
cryptohome::RemoveKeyRequest request;
request.mutable_key()->mutable_data()->set_label(key_to_remove);
const Key* const auth_key = user_context.GetKey();
cryptohome::HomedirMethods::GetInstance()->RemoveKeyEx(
cryptohome::Identification(user_context.GetAccountId()),
cryptohome::CreateAuthorizationRequest(auth_key->GetLabel(),
auth_key->GetSecret()),
request,
base::BindOnce(&ExtendedAuthenticatorImpl::OnOperationComplete, this,
"RemoveKeyEx", user_context, std::move(success_callback)));
}
void ExtendedAuthenticatorImpl::OnMountComplete(
const std::string& time_marker,
const UserContext& user_context,
ResultCallback success_callback,
base::Optional<cryptohome::BaseReply> reply) {
cryptohome::MountError return_code =
cryptohome::MountExReplyToMountError(reply);
RecordEndMarker(time_marker);
if (return_code == cryptohome::MOUNT_ERROR_NONE) {
const std::string& mount_hash =
cryptohome::MountExReplyToMountHash(reply.value());
if (success_callback)
std::move(success_callback).Run(mount_hash);
if (old_consumer_) {
UserContext copy = user_context;
copy.SetUserIDHash(mount_hash);
old_consumer_->OnAuthSuccess(copy);
}
return;
}
LOG(ERROR) << "MountEx failed. Error: " << return_code;
AuthState state = FAILED_MOUNT;
if (return_code == cryptohome::MOUNT_ERROR_TPM_COMM_ERROR ||
return_code == cryptohome::MOUNT_ERROR_TPM_DEFEND_LOCK ||
return_code == cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) {
state = FAILED_TPM;
}
if (return_code == cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST)
state = NO_MOUNT;
if (consumer_)
consumer_->OnAuthenticationFailure(state);
if (old_consumer_) {
AuthFailure failure(AuthFailure::COULD_NOT_MOUNT_CRYPTOHOME);
old_consumer_->OnAuthFailure(failure);
}
}
void ExtendedAuthenticatorImpl::OnOperationComplete(
const std::string& time_marker,
const UserContext& user_context,
base::OnceClosure success_callback,
bool success,
cryptohome::MountError return_code) {
RecordEndMarker(time_marker);
if (return_code == cryptohome::MOUNT_ERROR_NONE) {
if (success_callback)
std::move(success_callback).Run();
if (old_consumer_)
old_consumer_->OnAuthSuccess(user_context);
return;
}
LOG(ERROR) << "Extended authenticator cryptohome error, code: "
<< return_code;
AuthState state = FAILED_MOUNT;
if (return_code == cryptohome::MOUNT_ERROR_TPM_COMM_ERROR ||
return_code == cryptohome::MOUNT_ERROR_TPM_DEFEND_LOCK ||
return_code == cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) {
state = FAILED_TPM;
}
if (return_code == cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST)
state = NO_MOUNT;
if (consumer_)
consumer_->OnAuthenticationFailure(state);
if (old_consumer_) {
AuthFailure failure(AuthFailure::UNLOCK_FAILED);
old_consumer_->OnAuthFailure(failure);
}
}
} // namespace chromeos