blob: 7ca9a6b2a1dc71e68f0a171ceffeed7edd280ffb [file] [log] [blame]
// Copyright 2018 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <cstring>
#include <string>
#include <utility>
#include <base/check.h>
#include <base/functional/bind.h>
#include <base/functional/callback_helpers.h>
#include <base/logging.h>
#include <base/message_loop/message_pump_type.h>
#include <brillo/secure_blob.h>
#include <libhwsec/frontend/bootlockbox/frontend.h>
#include <libhwsec-foundation/status/status_chain_macros.h>
#include "bootlockbox/hwsec_space.h"
#include "bootlockbox/hwsec_space_impl.h"
#include "libhwsec/error/tpm_error.h"
namespace bootlockbox {
SpaceState HwsecSpaceImpl::DefineSpace() {
ASSIGN_OR_RETURN(hwsec::BootLockboxFrontend::StorageState state,
hwsec_->GetSpaceState(),
_.WithStatus<hwsec::TPMError>("Failed to get space state")
.LogError()
.As(SpaceState::kSpaceNeedPowerwash));
if (state.writable) {
return SpaceState::kSpaceUninitialized;
}
if (!state.preparable) {
LOG(ERROR) << "Cannot prepare space with unprepareable state.";
return SpaceState::kSpaceError;
}
RETURN_IF_ERROR(hwsec_->PrepareSpace(kSpaceSize))
.WithStatus<hwsec::TPMError>("Failed to prepare space")
.LogError()
.As(SpaceState::kSpaceUndefined);
return SpaceState::kSpaceUninitialized;
}
bool HwsecSpaceImpl::WriteSpace(const std::string& digest) {
if (digest.size() != SHA256_DIGEST_LENGTH) {
LOG(ERROR) << "Wrong digest size, expected: " << SHA256_DIGEST_LENGTH
<< " got: " << digest.size();
return false;
}
BootLockboxSpace space;
space.version = kSpaceVersion;
space.flags = 0;
memcpy(space.digest, digest.data(), SHA256_DIGEST_LENGTH);
brillo::Blob nvram_data(kSpaceSize);
memcpy(nvram_data.data(), &space, kSpaceSize);
RETURN_IF_ERROR(hwsec_->StoreSpace(nvram_data))
.WithStatus<hwsec::TPMError>("Failed to store space")
.LogError()
.As(false);
return true;
}
SpaceState HwsecSpaceImpl::ReadSpace(std::string* digest) {
ASSIGN_OR_RETURN(hwsec::BootLockboxFrontend::StorageState state,
hwsec_->GetSpaceState(),
_.WithStatus<hwsec::TPMError>("Failed to get space state")
.LogError()
.As(SpaceState::kSpaceNeedPowerwash));
if (!state.readable && state.preparable) {
return SpaceState::kSpaceUndefined;
}
ASSIGN_OR_RETURN(brillo::Blob nvram_data, hwsec_->LoadSpace(),
_.WithStatus<hwsec::TPMError>("Failed to read space")
.LogError()
.As(SpaceState::kSpaceError));
if (nvram_data.size() != kSpaceSize) {
LOG(ERROR) << "Error reading nvram space, invalid data length, expected:"
<< kSpaceSize << ", got " << nvram_data.size();
return SpaceState::kSpaceError;
}
std::string nvram_data_str = brillo::BlobToString(nvram_data);
if (nvram_data_str == std::string(kSpaceSize, '\0') ||
nvram_data_str == std::string(kSpaceSize, 0xff)) {
LOG(ERROR) << "Empty nvram data.";
return SpaceState::kSpaceUninitialized;
}
BootLockboxSpace space;
memcpy(&space, nvram_data.data(), kSpaceSize);
if (space.version != kSpaceVersion) {
LOG(ERROR) << "Error reading nvram space, invalid version";
return SpaceState::kSpaceError;
}
digest->assign(reinterpret_cast<const char*>(space.digest),
SHA256_DIGEST_LENGTH);
return SpaceState::kSpaceNormal;
}
bool HwsecSpaceImpl::LockSpace() {
RETURN_IF_ERROR(hwsec_->LockSpace())
.WithStatus<hwsec::TPMError>("Failed to lock space")
.LogError()
.As(false);
return true;
}
void HwsecSpaceImpl::RegisterOwnershipTakenCallback(
base::OnceClosure callback) {
hwsec_->WaitUntilReady(base::IgnoreArgs<hwsec::Status>(std::move(callback)));
}
} // namespace bootlockbox