blob: f0d0bae2de000bb0ca773245bedfb3e0b29d142d [file] [log] [blame]
// Copyright 2020 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/tpm_bound_to_pcr_auth_block.h"
#include <map>
#include <string>
#include <base/optional.h>
#include <brillo/secure_blob.h>
#include "cryptohome/crypto.h"
#include "cryptohome/crypto_error.h"
#include "cryptohome/cryptohome_metrics.h"
#include "cryptohome/cryptolib.h"
#include "cryptohome/tpm.h"
#include "cryptohome/tpm_auth_block_utils.h"
#include "cryptohome/tpm_init.h"
#include "cryptohome/vault_keyset.pb.h"
namespace cryptohome {
TpmBoundToPcrAuthBlock::TpmBoundToPcrAuthBlock(Tpm* tpm, TpmInit* tpm_init)
: tpm_(tpm), tpm_init_(tpm_init), utils_(tpm, tpm_init) {
CHECK(tpm != nullptr);
CHECK(tpm_init != nullptr);
}
bool TpmBoundToPcrAuthBlock::Derive(const AuthInput& auth_input,
const AuthBlockState& state,
KeyBlobs* key_out_data,
CryptoError* error) {
const SerializedVaultKeyset& serialized = state.vault_keyset.value();
if (!utils_.CheckTPMReadiness(serialized, error))
return false;
key_out_data->vkk_iv = brillo::SecureBlob(kAesBlockSize);
key_out_data->vkk_key = brillo::SecureBlob(kDefaultAesKeySize);
bool locked_to_single_user = auth_input.locked_to_single_user.value_or(false);
brillo::SecureBlob salt(serialized.salt().begin(), serialized.salt().end());
std::string tpm_key_str = locked_to_single_user
? serialized.extended_tpm_key()
: serialized.tpm_key();
brillo::SecureBlob tpm_key(tpm_key_str.begin(), tpm_key_str.end());
if (!DecryptTpmBoundToPcr(auth_input.user_input.value(), tpm_key, salt, error,
&key_out_data->vkk_iv.value(),
&key_out_data->vkk_key.value())) {
return false;
}
key_out_data->chaps_iv = key_out_data->vkk_iv;
key_out_data->authorization_data_iv = key_out_data->vkk_iv;
key_out_data->wrapped_reset_seed = brillo::SecureBlob();
key_out_data->wrapped_reset_seed.value().assign(
serialized.wrapped_reset_seed().begin(),
serialized.wrapped_reset_seed().end());
if (!serialized.has_tpm_public_key_hash() && error) {
*error = CryptoError::CE_NO_PUBLIC_KEY_HASH;
}
return true;
}
bool TpmBoundToPcrAuthBlock::DecryptTpmBoundToPcr(
const brillo::SecureBlob& vault_key,
const brillo::SecureBlob& tpm_key,
const brillo::SecureBlob& salt,
CryptoError* error,
brillo::SecureBlob* vkk_iv,
brillo::SecureBlob* vkk_key) const {
brillo::SecureBlob pass_blob(kDefaultPassBlobSize);
if (!CryptoLib::DeriveSecretsScrypt(vault_key, salt, {&pass_blob, vkk_iv})) {
return false;
}
Tpm::TpmRetryAction retry_action;
for (int i = 0; i < kTpmDecryptMaxRetries; ++i) {
std::map<uint32_t, std::string> pcr_map({{kTpmSingleUserPCR, ""}});
retry_action = tpm_->UnsealWithAuthorization(
tpm_init_->GetCryptohomeKey(), tpm_key, pass_blob, pcr_map, vkk_key);
if (retry_action == Tpm::kTpmRetryNone)
return true;
if (!TpmAuthBlockUtils::TpmErrorIsRetriable(retry_action))
break;
// If the error is retriable, reload the key first.
if (!tpm_init_->ReloadCryptohomeKey()) {
LOG(ERROR) << "Unable to reload Cryptohome key.";
break;
}
}
LOG(ERROR) << "Failed to unwrap VKK with creds.";
*error = TpmAuthBlockUtils::TpmErrorToCrypto(retry_action);
return false;
}
} // namespace cryptohome