blob: e5d2c829fcacc9bbe3a2c62e8d01872867ba6e14 [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 <stdint.h>
#include <cstdlib>
#include <memory>
#include <string>
#include <base/containers/span.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <brillo/flag_helper.h>
#include <brillo/secure_blob.h>
#include <brillo/syslog_logging.h>
#include "cryptohome/crypto/fake_recovery_mediator_crypto.h"
#include "cryptohome/crypto/recovery_crypto.h"
using base::FilePath;
using brillo::SecureBlob;
using cryptohome::FakeRecoveryMediatorCrypto;
using cryptohome::RecoveryCrypto;
namespace {
// Hkdf salt and info used for encrypting/decrypting mediator share.
static const char kHkdfSaltHex[] = "0b0b0b0b";
static const char kHkdfInfoHex[] = "0b0b0b0b0b0b0b0b";
bool CheckMandatoryFlag(const std::string& flag_name,
const std::string& flag_value) {
if (!flag_value.empty())
return true;
LOG(ERROR) << "--" << flag_name << " is mandatory.";
return false;
}
bool ReadFileToSecureBlobLogged(const FilePath& file_path,
SecureBlob* contents) {
std::string contents_string;
if (!base::ReadFileToString(file_path, &contents_string)) {
LOG(ERROR) << "Failed to read from file " << file_path.value() << ".";
return false;
}
*contents = SecureBlob(contents_string);
return true;
}
bool WriteFileLogged(const FilePath& file_path,
base::span<const uint8_t> contents) {
if (base::WriteFile(file_path, contents))
return true;
LOG(ERROR) << "Failed to write to file " << file_path.value() << ".";
return false;
}
bool DoRecoveryCryptoCreateAction(
const FilePath& destination_share_out_file_path,
const FilePath& mediator_share_out_file_path,
const FilePath& publisher_pub_key_out_file_path,
const FilePath& recovery_secret_out_file_path) {
std::unique_ptr<RecoveryCrypto> recovery_crypto = RecoveryCrypto::Create();
if (!recovery_crypto) {
LOG(ERROR) << "Failed to create recovery crypto object.";
return false;
}
SecureBlob hkdf_info, hkdf_salt, mediator_pub_key;
CHECK(brillo::SecureBlob::HexStringToSecureBlob(kHkdfInfoHex, &hkdf_info));
CHECK(brillo::SecureBlob::HexStringToSecureBlob(kHkdfSaltHex, &hkdf_salt));
CHECK(
FakeRecoveryMediatorCrypto::GetFakeMediatorPublicKey(&mediator_pub_key));
SecureBlob destination_share, dealer_pub_key;
RecoveryCrypto::EncryptedMediatorShare encrypted_mediator_share;
if (!recovery_crypto->GenerateShares(mediator_pub_key,
&encrypted_mediator_share,
&destination_share, &dealer_pub_key)) {
LOG(ERROR) << "Failed to generate recovery shares.";
return false;
}
SecureBlob serialized_encrypted_mediator_share;
if (!RecoveryCrypto::SerializeEncryptedMediatorShareForTesting(
encrypted_mediator_share, &serialized_encrypted_mediator_share)) {
LOG(ERROR) << "Failed to serialize encrypted mediator share.";
return false;
}
SecureBlob publisher_pub_key, publisher_dh;
if (!recovery_crypto->GeneratePublisherKeys(
dealer_pub_key, &publisher_pub_key, &publisher_dh)) {
LOG(ERROR) << "Failed to generate recovery publisher keys.";
return false;
}
return WriteFileLogged(destination_share_out_file_path, destination_share) &&
WriteFileLogged(mediator_share_out_file_path,
serialized_encrypted_mediator_share) &&
WriteFileLogged(publisher_pub_key_out_file_path, publisher_pub_key) &&
WriteFileLogged(recovery_secret_out_file_path, publisher_dh);
}
bool DoRecoveryCryptoMediateAction(
const FilePath& mediator_share_in_file_path,
const FilePath& publisher_pub_key_in_file_path,
const FilePath& mediated_publisher_pub_key_out_file_path) {
SecureBlob serialized_encrypted_mediator_share;
SecureBlob publisher_pub_key;
if (!ReadFileToSecureBlobLogged(mediator_share_in_file_path,
&serialized_encrypted_mediator_share) ||
!ReadFileToSecureBlobLogged(publisher_pub_key_in_file_path,
&publisher_pub_key)) {
return false;
}
RecoveryCrypto::EncryptedMediatorShare encrypted_mediator_share;
if (!RecoveryCrypto::DeserializeEncryptedMediatorShareForTesting(
serialized_encrypted_mediator_share, &encrypted_mediator_share)) {
LOG(ERROR) << "Failed to deserialize encrypted mediator share.";
return false;
}
std::unique_ptr<FakeRecoveryMediatorCrypto> fake_mediator =
FakeRecoveryMediatorCrypto::Create();
if (!fake_mediator) {
LOG(ERROR) << "Failed to create fake mediator object.";
return false;
}
SecureBlob hkdf_info, hkdf_salt, mediator_priv_key;
CHECK(brillo::SecureBlob::HexStringToSecureBlob(kHkdfInfoHex, &hkdf_info));
CHECK(brillo::SecureBlob::HexStringToSecureBlob(kHkdfSaltHex, &hkdf_salt));
CHECK(FakeRecoveryMediatorCrypto::GetFakeMediatorPrivateKey(
&mediator_priv_key));
SecureBlob mediated_publisher_pub_key;
if (!fake_mediator->Mediate(mediator_priv_key, publisher_pub_key,
encrypted_mediator_share,
&mediated_publisher_pub_key)) {
LOG(ERROR) << "Failed to perform recovery mediation.";
return false;
}
return WriteFileLogged(mediated_publisher_pub_key_out_file_path,
mediated_publisher_pub_key);
}
bool DoRecoveryCryptoDecryptAction(
const FilePath& destination_share_in_file_path,
const FilePath& publisher_pub_key_in_file_path,
const FilePath& mediated_publisher_pub_key_in_file_path,
const FilePath& recovery_secret_out_file_path) {
SecureBlob hkdf_salt;
CHECK(brillo::SecureBlob::HexStringToSecureBlob(kHkdfSaltHex, &hkdf_salt));
SecureBlob destination_share, publisher_pub_key, mediated_publisher_pub_key;
if (!ReadFileToSecureBlobLogged(destination_share_in_file_path,
&destination_share) ||
!ReadFileToSecureBlobLogged(publisher_pub_key_in_file_path,
&publisher_pub_key) ||
!ReadFileToSecureBlobLogged(mediated_publisher_pub_key_in_file_path,
&mediated_publisher_pub_key)) {
return false;
}
std::unique_ptr<RecoveryCrypto> recovery_crypto = RecoveryCrypto::Create();
if (!recovery_crypto) {
LOG(ERROR) << "Failed to create recovery crypto object.";
return false;
}
SecureBlob destination_dh;
if (!recovery_crypto->RecoverDestination(publisher_pub_key, destination_share,
/*ephemeral_pub_key=*/base::nullopt,
mediated_publisher_pub_key,
&destination_dh)) {
LOG(ERROR) << "Failed to perform destination recovery.";
return false;
}
return WriteFileLogged(recovery_secret_out_file_path, destination_dh);
}
} // namespace
int main(int argc, char* argv[]) {
brillo::InitLog(brillo::kLogToStderr);
DEFINE_string(action, "",
"One of: recovery_crypto_create, recovery_crypto_mediate, "
"recovery_crypto_decrypt.");
DEFINE_string(destination_share_out_file, "",
"Path to the file where to store the Cryptohome Recovery "
"encrypted destination share.");
DEFINE_string(destination_share_in_file, "",
"Path to the file containing the Cryptohome Recovery encrypted "
"destination share.");
DEFINE_string(mediator_share_out_file, "",
"Path to the file where to store the Cryptohome Recovery "
"encrypted mediator share.");
DEFINE_string(mediator_share_in_file, "",
"Path to the file containing the Cryptohome Recovery encrypted "
"mediator share.");
DEFINE_string(publisher_pub_key_out_file, "",
"Path to the file where to store the Cryptohome Recovery "
"publisher public key.");
DEFINE_string(publisher_pub_key_in_file, "",
"Path to the file containing the Cryptohome Recovery publisher "
"public key.");
DEFINE_string(mediated_publisher_pub_key_out_file, "",
"Path to the file where to store the Cryptohome Recovery "
"mediated publisher public key.");
DEFINE_string(mediated_publisher_pub_key_in_file, "",
"Path to the file containing the Cryptohome Recovery "
"mediated publisher public key.");
DEFINE_string(
recovery_secret_out_file, "",
"Path to the file where to store the Cryptohome Recovery secret.");
brillo::FlagHelper::Init(argc, argv,
"cryptohome-test-tool - Test tool for cryptohome.");
bool success = false;
if (FLAGS_action.empty()) {
LOG(ERROR) << "--action is required.";
} else if (FLAGS_action == "recovery_crypto_create") {
if (CheckMandatoryFlag("destination_share_out_file",
FLAGS_destination_share_out_file) &&
CheckMandatoryFlag("mediator_share_out_file",
FLAGS_mediator_share_out_file) &&
CheckMandatoryFlag("publisher_pub_key_out_file",
FLAGS_publisher_pub_key_out_file) &&
CheckMandatoryFlag("recovery_secret_out_file",
FLAGS_recovery_secret_out_file)) {
success = DoRecoveryCryptoCreateAction(
FilePath(FLAGS_destination_share_out_file),
FilePath(FLAGS_mediator_share_out_file),
FilePath(FLAGS_publisher_pub_key_out_file),
FilePath(FLAGS_recovery_secret_out_file));
}
} else if (FLAGS_action == "recovery_crypto_mediate") {
if (CheckMandatoryFlag("mediator_share_in_file",
FLAGS_mediator_share_in_file) &&
CheckMandatoryFlag("publisher_pub_key_in_file",
FLAGS_publisher_pub_key_in_file) &&
CheckMandatoryFlag("mediated_publisher_pub_key_out_file",
FLAGS_mediated_publisher_pub_key_out_file)) {
success = DoRecoveryCryptoMediateAction(
FilePath(FLAGS_mediator_share_in_file),
FilePath(FLAGS_publisher_pub_key_in_file),
FilePath(FLAGS_mediated_publisher_pub_key_out_file));
}
} else if (FLAGS_action == "recovery_crypto_decrypt") {
if (CheckMandatoryFlag("destination_share_in_file",
FLAGS_destination_share_in_file) &&
CheckMandatoryFlag("publisher_pub_key_in_file",
FLAGS_publisher_pub_key_in_file) &&
CheckMandatoryFlag("mediated_publisher_pub_key_in_file",
FLAGS_mediated_publisher_pub_key_in_file) &&
CheckMandatoryFlag("recovery_secret_out_file",
FLAGS_recovery_secret_out_file)) {
success = DoRecoveryCryptoDecryptAction(
FilePath(FLAGS_destination_share_in_file),
FilePath(FLAGS_publisher_pub_key_in_file),
FilePath(FLAGS_mediated_publisher_pub_key_in_file),
FilePath(FLAGS_recovery_secret_out_file));
}
} else {
LOG(ERROR) << "Unknown --action.";
}
return success ? EXIT_SUCCESS : EXIT_FAILURE;
}