blob: d497dc58bc6d40f3395a76fbfd4b217091dfa074 [file] [log] [blame]
// Copyright 2021 The Chromium OS 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 "cryptohome/cryptohome_key_loader.h"
#include "cryptohome/cryptolib.h"
#include "cryptohome/platform.h"
using base::FilePath;
using brillo::SecureBlob;
namespace cryptohome {
namespace {
constexpr char kDefaultCryptohomeKeyFile[] = "/home/.shadow/cryptohome.key";
constexpr unsigned int kDefaultTpmRsaKeyBits = 2048;
} // namespace
CryptohomeKeyLoader::CryptohomeKeyLoader(Tpm* tpm, Platform* platform)
: tpm_(tpm), platform_(platform) {}
CryptohomeKeyLoader::~CryptohomeKeyLoader() {}
bool CryptohomeKeyLoader::CreateCryptohomeKey() {
if (!tpm_->IsEnabled() || !tpm_->IsOwned()) {
LOG(WARNING) << "Canceled creating cryptohome key - TPM is not ready.";
return false;
}
SecureBlob n;
SecureBlob p;
if (!CryptoLib::CreateRsaKey(kDefaultTpmRsaKeyBits, &n, &p)) {
LOG(ERROR) << "Error creating RSA key";
return false;
}
SecureBlob wrapped_key;
if (!tpm_->WrapRsaKey(n, p, &wrapped_key)) {
LOG(ERROR) << "Couldn't wrap cryptohome key";
return false;
}
if (!SaveCryptohomeKey(wrapped_key)) {
LOG(ERROR) << "Couldn't save cryptohome key";
return false;
}
LOG(INFO) << "Created new cryptohome key.";
return true;
}
bool CryptohomeKeyLoader::SaveCryptohomeKey(const SecureBlob& wrapped_key) {
const FilePath key_file(kDefaultCryptohomeKeyFile);
bool ok = platform_->WriteSecureBlobToFileAtomicDurable(key_file, wrapped_key,
0600);
if (!ok)
LOG(ERROR) << "Error writing key file of desired size: "
<< wrapped_key.size();
return ok;
}
Tpm::TpmRetryAction CryptohomeKeyLoader::LoadCryptohomeKey(
ScopedKeyHandle* key_handle) {
CHECK(key_handle);
// First, try loading the key from the key file.
{
SecureBlob raw_key;
const FilePath key_file(kDefaultCryptohomeKeyFile);
if (platform_->ReadFileToSecureBlob(key_file, &raw_key)) {
Tpm::TpmRetryAction retry_action =
tpm_->LoadWrappedKey(raw_key, key_handle);
if (retry_action == Tpm::kTpmRetryNone ||
tpm_->IsTransient(retry_action)) {
return retry_action;
}
}
}
// Then try loading the key by the UUID (this is a legacy upgrade path).
SecureBlob raw_key;
if (!tpm_->LegacyLoadCryptohomeKey(key_handle, &raw_key)) {
return Tpm::kTpmRetryFailNoRetry;
}
// Save the cryptohome key to the well-known location.
if (!SaveCryptohomeKey(raw_key)) {
LOG(ERROR) << "Couldn't save cryptohome key";
return Tpm::kTpmRetryFailNoRetry;
}
return Tpm::kTpmRetryNone;
}
bool CryptohomeKeyLoader::LoadOrCreateCryptohomeKey(
ScopedKeyHandle* key_handle) {
CHECK(key_handle);
// Try to load the cryptohome key.
Tpm::TpmRetryAction retry_action = LoadCryptohomeKey(key_handle);
if (retry_action != Tpm::kTpmRetryNone && !tpm_->IsTransient(retry_action)) {
// The key couldn't be loaded, and it wasn't due to a transient error,
// so we must create the key.
if (CreateCryptohomeKey()) {
retry_action = LoadCryptohomeKey(key_handle);
}
}
return retry_action == Tpm::kTpmRetryNone;
}
bool CryptohomeKeyLoader::HasCryptohomeKey() {
return (cryptohome_key_.value() != kInvalidKeyHandle);
}
TpmKeyHandle CryptohomeKeyLoader::GetCryptohomeKey() {
return cryptohome_key_.value();
}
bool CryptohomeKeyLoader::ReloadCryptohomeKey() {
CHECK(HasCryptohomeKey());
// Release the handle first, we know this handle doesn't contain a loaded key
// since ReloadCryptohomeKey only called after we failed to use it.
// Otherwise we may flush the newly loaded key and fail to use it again,
// if it is loaded to the same handle.
// TODO(crbug.com/687330): change to closing the handle and ignoring errors
// once checking for stale virtual handles is implemented in trunksd.
cryptohome_key_.release();
if (LoadCryptohomeKey(&cryptohome_key_) != Tpm::kTpmRetryNone) {
LOG(ERROR) << "Error reloading Cryptohome key.";
return false;
}
return true;
}
void CryptohomeKeyLoader::Init() {
if (!LoadOrCreateCryptohomeKey(&cryptohome_key_)) {
LOG(ERROR) << __func__ << ": failed to load or create cryptohome key";
}
}
} // namespace cryptohome