blob: 6532edb13158735b9822265f189572edfc72699e [file] [log] [blame] [edit]
// Copyright 2024 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flex_id/flex_state_key.h"
#include "flex_id/utils.h"
#include <optional>
#include <base/files/file_util.h>
#include <base/files/important_file_writer.h>
#include <base/logging.h>
#include <base/rand_util.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_util.h>
#include <brillo/data_encoding.h>
namespace flex_id {
namespace {
constexpr char kPreservedFlexStateKeyFile[] =
"mnt/stateful_partition/unencrypted/preserve/flex/flex_state_key";
constexpr char kFlexStateKeyFile[] = "var/lib/flex_id/flex_state_key";
const int kFlexStateKeyLength = 64;
} // namespace
FlexStateKeyGenerator::FlexStateKeyGenerator(const base::FilePath& base_path) {
base_path_ = base_path;
}
std::optional<std::string> FlexStateKeyGenerator::ReadFlexStateKey() {
std::optional<std::string> flex_state_key;
const base::FilePath flex_state_key_path =
base_path_.Append(kFlexStateKeyFile);
if (!(flex_state_key = ReadAndTrimFile(flex_state_key_path))) {
LOG(WARNING) << "Couldn't read flex_state_key file.";
return std::nullopt;
}
if (flex_state_key.value().empty()) {
LOG(WARNING) << "Read a blank flex_state_key file.";
return std::nullopt;
}
return flex_state_key;
}
std::optional<std::string> FlexStateKeyGenerator::TryPreservedFlexStateKey() {
std::optional<std::string> preserved_flex_state_key;
const base::FilePath preserved_flex_state_key_path =
base_path_.Append(kPreservedFlexStateKeyFile);
if (!(preserved_flex_state_key =
ReadAndTrimFile(preserved_flex_state_key_path))) {
return std::nullopt;
}
if (preserved_flex_state_key.value().empty()) {
return std::nullopt;
}
return preserved_flex_state_key;
}
std::optional<std::string> FlexStateKeyGenerator::GenerateFlexStateKey() {
std::optional<std::string> flex_state_key;
uint8_t flex_state_key_raw[kFlexStateKeyLength];
std::string flex_state_key_hex;
base::RandBytes(flex_state_key_raw);
flex_state_key_hex = base::ToLowerASCII(base::HexEncode(flex_state_key_raw));
flex_state_key = flex_state_key_hex;
return flex_state_key;
}
bool FlexStateKeyGenerator::WriteFlexStateKey(
const std::string& flex_state_key) {
const base::FilePath flex_state_key_file_path =
base_path_.Append(kFlexStateKeyFile);
if (base::CreateDirectory(flex_state_key_file_path.DirName())) {
return base::ImportantFileWriter::WriteFileAtomically(
flex_state_key_file_path, flex_state_key + "\n");
}
return false;
}
std::optional<std::string>
FlexStateKeyGenerator::GenerateAndSaveFlexStateKey() {
std::optional<std::string> flex_state_key;
// Check for existing flex_state_key and exit early.
if ((flex_state_key = ReadFlexStateKey())) {
LOG(INFO) << "Found existing flex_state_key: " << flex_state_key.value();
return flex_state_key;
}
// Generate a new flex_state_key.
if ((flex_state_key = TryPreservedFlexStateKey())) {
LOG(INFO) << "Using preserved flex_state_key for flex_state_key: "
<< flex_state_key.value();
} else if ((flex_state_key = GenerateFlexStateKey())) {
LOG(INFO) << "Generated a new flex_state_key: " << flex_state_key.value();
} else {
LOG(ERROR) << "Couldn't find or generate a flex_state_key";
return std::nullopt;
}
// Write flex_state_key to file.
if (WriteFlexStateKey(flex_state_key.value())) {
LOG(INFO) << "Successfully wrote flex_state_key: "
<< flex_state_key.value();
return flex_state_key;
}
return std::nullopt;
}
} // namespace flex_id