blob: c754397727f2a64047f88a704eba606fc1c23e5e [file] [log] [blame]
// Copyright (c) 2012 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.
//
// Cryptohome client that uses the dbus client interface
#include <inttypes.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <memory>
#include <string>
#include <vector>
#include <attestation/proto_bindings/interface.pb.h>
#include <base/command_line.h>
#include <base/files/file_path.h>
#include <base/logging.h>
#include <base/stl_util.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_split.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
#include <brillo/cryptohome.h>
#include <brillo/glib/dbus.h>
#include <brillo/secure_blob.h>
#include <brillo/syslog_logging.h>
#include <chromeos/constants/cryptohome.h>
#include <chromeos/dbus/service_constants.h>
#include <google/protobuf/message_lite.h>
#include "cryptohome/attestation.pb.h"
#include "cryptohome/crypto.h"
#include "cryptohome/cryptolib.h"
#include "cryptohome/filesystem_layout.h"
#include "cryptohome/key.pb.h"
#include "cryptohome/pkcs11_init.h"
#include "cryptohome/platform.h"
#include "cryptohome/rpc.pb.h"
#include "cryptohome/signed_secret.pb.h"
#include "cryptohome/storage/homedirs.h"
#include "cryptohome/vault_keyset.pb.h"
#include "bindings/cryptohome.dbusclient.h"
using base::FilePath;
using base::StringPrintf;
using brillo::SecureBlob;
using brillo::cryptohome::home::SanitizeUserNameWithSalt;
namespace {
// Number of days that the set_current_user_old action uses when updating the
// home directory timestamp. ~3 months should be old enough for test purposes.
const int kSetCurrentUserOldOffsetInDays = 92;
// Five minutes is enough to wait for any TPM operations, sync() calls, etc.
const int kDefaultTimeoutMs = 300000;
// We've 100 seconds to wait for TakeOwnership(), should be rather generous.
constexpr int kWaitOwnershipTimeoutInSeconds = 100;
// Poll once every 0.2s.
constexpr int kWaitOwnershipPollIntervalInMs = 200;
} // namespace
namespace switches {
static const char kSyslogSwitch[] = "syslog";
static const char kAttestationServerSwitch[] = "attestation-server";
static struct {
const char* name;
const int aca_type;
} kAttestationServers[] = {{"default", attestation::DEFAULT_ACA},
{"test", attestation::TEST_ACA},
{nullptr, attestation::ACAType_ARRAYSIZE}};
static const char kVaServerSwitch[] = "va-server";
static struct {
const char* name;
const int va_type;
} kVaServers[] = {{"default", attestation::DEFAULT_VA},
{"test", attestation::TEST_VA},
{nullptr, attestation::VAType_ARRAYSIZE}};
static const char kWaitOwnershipTimeoutSwitch[] = "wait-ownership-timeout";
static const char kActionSwitch[] = "action";
static const char* kActions[] = {"mount_ex",
"mount_guest_ex",
"unmount",
"is_mounted",
"check_key_ex",
"remove_key_ex",
"get_key_data_ex",
"list_keys_ex",
"migrate_key_ex",
"add_key_ex",
"add_data_restore_key",
"mass_remove_keys",
"update_key_ex",
"remove",
"obfuscate_user",
"get_system_salt",
"dump_keyset",
"dump_last_activity",
"tpm_status",
"tpm_more_status",
"status",
"set_current_user_old",
"tpm_take_ownership",
"tpm_clear_stored_password",
"tpm_wait_ownership",
"install_attributes_set",
"install_attributes_get",
"install_attributes_finalize",
"install_attributes_count",
"install_attributes_is_ready",
"install_attributes_is_secure",
"install_attributes_is_invalid",
"install_attributes_is_first_install",
"pkcs11_get_user_token_info",
"pkcs11_get_system_token_info",
"pkcs11_is_user_token_ok",
"pkcs11_terminate",
"tpm_verify_attestation",
"tpm_verify_ek",
"tpm_attestation_status",
"tpm_attestation_more_status",
"tpm_attestation_start_enroll",
"tpm_attestation_finish_enroll",
"tpm_attestation_enroll",
"tpm_attestation_start_cert_request",
"tpm_attestation_finish_cert_request",
"tpm_attestation_get_certificate",
"tpm_attestation_key_status",
"tpm_attestation_register_key",
"tpm_attestation_enterprise_challenge",
"tpm_attestation_simple_challenge",
"tpm_attestation_get_key_payload",
"tpm_attestation_set_key_payload",
"tpm_attestation_delete_keys",
"tpm_attestation_delete_key",
"tpm_attestation_get_ek",
"tpm_attestation_reset_identity",
"tpm_attestation_reset_identity_result",
"sign_lockbox",
"verify_lockbox",
"finalize_lockbox",
"get_boot_attribute",
"set_boot_attribute",
"flush_and_sign_boot_attributes",
"get_login_status",
"initialize_cast_key",
"get_firmware_management_parameters",
"set_firmware_management_parameters",
"remove_firmware_management_parameters",
"migrate_to_dircrypto",
"needs_dircrypto_migration",
"get_enrollment_id",
"get_supported_key_policies",
"get_account_disk_usage",
"lock_to_single_user_mount_until_reboot",
"get_rsu_device_id",
"check_health",
"start_fingerprint_auth_session",
"end_fingerprint_auth_session",
"start_auth_session",
NULL};
enum ActionEnum {
ACTION_MOUNT_EX,
ACTION_MOUNT_GUEST_EX,
ACTION_UNMOUNT,
ACTION_MOUNTED,
ACTION_CHECK_KEY_EX,
ACTION_REMOVE_KEY_EX,
ACTION_GET_KEY_DATA_EX,
ACTION_LIST_KEYS_EX,
ACTION_MIGRATE_KEY_EX,
ACTION_ADD_KEY_EX,
ACTION_ADD_DATA_RESTORE_KEY,
ACTION_MASS_REMOVE_KEYS,
ACTION_UPDATE_KEY_EX,
ACTION_REMOVE,
ACTION_OBFUSCATE_USER,
ACTION_GET_SYSTEM_SALT,
ACTION_DUMP_KEYSET,
ACTION_DUMP_LAST_ACTIVITY,
ACTION_TPM_STATUS,
ACTION_TPM_MORE_STATUS,
ACTION_STATUS,
ACTION_SET_CURRENT_USER_OLD,
ACTION_TPM_TAKE_OWNERSHIP,
ACTION_TPM_CLEAR_STORED_PASSWORD,
ACTION_TPM_WAIT_OWNERSHIP,
ACTION_INSTALL_ATTRIBUTES_SET,
ACTION_INSTALL_ATTRIBUTES_GET,
ACTION_INSTALL_ATTRIBUTES_FINALIZE,
ACTION_INSTALL_ATTRIBUTES_COUNT,
ACTION_INSTALL_ATTRIBUTES_IS_READY,
ACTION_INSTALL_ATTRIBUTES_IS_SECURE,
ACTION_INSTALL_ATTRIBUTES_IS_INVALID,
ACTION_INSTALL_ATTRIBUTES_IS_FIRST_INSTALL,
ACTION_PKCS11_GET_USER_TOKEN_INFO,
ACTION_PKCS11_GET_SYSTEM_TOKEN_INFO,
ACTION_PKCS11_IS_USER_TOKEN_OK,
ACTION_PKCS11_TERMINATE,
ACTION_TPM_VERIFY_ATTESTATION,
ACTION_TPM_VERIFY_EK,
ACTION_TPM_ATTESTATION_STATUS,
ACTION_TPM_ATTESTATION_MORE_STATUS,
ACTION_TPM_ATTESTATION_START_ENROLL,
ACTION_TPM_ATTESTATION_FINISH_ENROLL,
ACTION_TPM_ATTESTATION_ENROLL,
ACTION_TPM_ATTESTATION_START_CERTREQ,
ACTION_TPM_ATTESTATION_FINISH_CERTREQ,
ACTION_TPM_ATTESTATION_GET_CERTIFICATE,
ACTION_TPM_ATTESTATION_KEY_STATUS,
ACTION_TPM_ATTESTATION_REGISTER_KEY,
ACTION_TPM_ATTESTATION_ENTERPRISE_CHALLENGE,
ACTION_TPM_ATTESTATION_SIMPLE_CHALLENGE,
ACTION_TPM_ATTESTATION_GET_KEY_PAYLOAD,
ACTION_TPM_ATTESTATION_SET_KEY_PAYLOAD,
ACTION_TPM_ATTESTATION_DELETE_KEYS,
ACTION_TPM_ATTESTATION_DELETE_KEY,
ACTION_TPM_ATTESTATION_GET_EK,
ACTION_TPM_ATTESTATION_RESET_IDENTITY,
ACTION_TPM_ATTESTATION_RESET_IDENTITY_RESULT,
ACTION_SIGN_LOCKBOX,
ACTION_VERIFY_LOCKBOX,
ACTION_FINALIZE_LOCKBOX,
ACTION_GET_BOOT_ATTRIBUTE,
ACTION_SET_BOOT_ATTRIBUTE,
ACTION_FLUSH_AND_SIGN_BOOT_ATTRIBUTES,
ACTION_GET_LOGIN_STATUS,
ACTION_INITIALIZE_CAST_KEY,
ACTION_GET_FIRMWARE_MANAGEMENT_PARAMETERS,
ACTION_SET_FIRMWARE_MANAGEMENT_PARAMETERS,
ACTION_REMOVE_FIRMWARE_MANAGEMENT_PARAMETERS,
ACTION_MIGRATE_TO_DIRCRYPTO,
ACTION_NEEDS_DIRCRYPTO_MIGRATION,
ACTION_GET_ENROLLMENT_ID,
ACTION_GET_SUPPORTED_KEY_POLICIES,
ACTION_GET_ACCOUNT_DISK_USAGE,
ACTION_LOCK_TO_SINGLE_USER_MOUNT_UNTIL_REBOOT,
ACTION_GET_RSU_DEVICE_ID,
ACTION_CHECK_HEALTH,
ACTION_START_FINGERPRINT_AUTH_SESSION,
ACTION_END_FINGERPRINT_AUTH_SESSION,
ACTION_START_AUTH_SESSION,
};
static const char kUserSwitch[] = "user";
static const char kPasswordSwitch[] = "password";
static const char kFingerprintSwitch[] = "fingerprint";
static const char kKeyLabelSwitch[] = "key_label";
static const char kNewKeyLabelSwitch[] = "new_key_label";
static const char kRemoveKeyLabelSwitch[] = "remove_key_label";
static const char kOldPasswordSwitch[] = "old_password";
static const char kNewPasswordSwitch[] = "new_password";
static const char kForceSwitch[] = "force";
static const char kAsyncSwitch[] = "async";
static const char kCreateSwitch[] = "create";
static const char kAttrNameSwitch[] = "name";
static const char kAttrPrefixSwitch[] = "prefix";
static const char kAttrValueSwitch[] = "value";
static const char kFileSwitch[] = "file";
static const char kInputFileSwitch[] = "input";
static const char kOutputFileSwitch[] = "output";
static const char kEnsureEphemeralSwitch[] = "ensure_ephemeral";
static const char kCrosCoreSwitch[] = "cros_core";
static const char kProtobufSwitch[] = "protobuf";
static const char kFlagsSwitch[] = "flags";
static const char kDevKeyHashSwitch[] = "developer_key_hash";
static const char kEcryptfsSwitch[] = "ecryptfs";
static const char kToMigrateFromEcryptfsSwitch[] = "to_migrate_from_ecryptfs";
static const char kHiddenMount[] = "hidden_mount";
static const char kMinimalMigration[] = "minimal_migration";
static const char kPublicMount[] = "public_mount";
static const char kKeyPolicySwitch[] = "key_policy";
static const char kKeyPolicyLECredential[] = "le";
static const char kProfileSwitch[] = "profile";
static const char kIgnoreCache[] = "ignore_cache";
static const char kRestoreKeyInHexSwitch[] = "restore_key_in_hex";
static const char kMassRemoveExemptLabelsSwitch[] = "exempt_key_labels";
static const char kEnrollSwitch[] = "enroll";
static const char kUseDBus[] = "use_dbus";
} // namespace switches
#define DBUS_METHOD(method_name) org_chromium_CryptohomeInterface_##method_name
typedef void (*ProtoDBusReplyMethod)(DBusGProxy*, GArray*, GError*, gpointer);
typedef gboolean (*ProtoDBusMethod)(DBusGProxy*,
const GArray*,
GArray**,
GError**);
typedef DBusGProxyCall* (*ProtoDBusAsyncMethod)(DBusGProxy*,
const GArray*,
ProtoDBusReplyMethod,
gpointer);
brillo::SecureBlob GetSystemSalt(const brillo::dbus::Proxy& proxy) {
brillo::glib::ScopedError error;
brillo::glib::ScopedArray salt;
if (!org_chromium_CryptohomeInterface_get_system_salt(
proxy.gproxy(), &brillo::Resetter(&salt).lvalue(),
&brillo::Resetter(&error).lvalue())) {
LOG(ERROR) << "GetSystemSalt failed: " << error->message;
return brillo::SecureBlob();
}
brillo::SecureBlob system_salt;
system_salt.resize(salt->len);
if (system_salt.size() == salt->len) {
memcpy(system_salt.data(), static_cast<const void*>(salt->data), salt->len);
} else {
system_salt.clear();
}
return system_salt;
}
bool GetAttrName(const base::CommandLine* cl, std::string* name_out) {
*name_out = cl->GetSwitchValueASCII(switches::kAttrNameSwitch);
if (name_out->length() == 0) {
printf("No install attribute name specified (--name=<name>)\n");
return false;
}
return true;
}
bool GetAttrValue(const base::CommandLine* cl, std::string* value_out) {
*value_out = cl->GetSwitchValueASCII(switches::kAttrValueSwitch);
if (value_out->length() == 0) {
printf("No install attribute value specified (--value=<value>)\n");
return false;
}
return true;
}
bool GetAccountId(const base::CommandLine* cl, std::string* user_out) {
*user_out = cl->GetSwitchValueASCII(switches::kUserSwitch);
if (user_out->length() == 0) {
printf("No user specified (--user=<account_id>)\n");
return false;
}
return true;
}
bool GetPassword(const brillo::dbus::Proxy& proxy,
const base::CommandLine* cl,
const std::string& cl_switch,
const std::string& prompt,
std::string* password_out) {
std::string password = cl->GetSwitchValueASCII(cl_switch);
if (password.length() == 0) {
char buffer[256];
struct termios original_attr;
struct termios new_attr;
tcgetattr(0, &original_attr);
memcpy(&new_attr, &original_attr, sizeof(new_attr));
new_attr.c_lflag &= ~(ECHO);
tcsetattr(0, TCSANOW, &new_attr);
printf("%s: ", prompt.c_str());
fflush(stdout);
if (fgets(buffer, base::size(buffer), stdin))
password = buffer;
printf("\n");
tcsetattr(0, TCSANOW, &original_attr);
}
std::string trimmed_password;
base::TrimString(password, "\r\n", &trimmed_password);
SecureBlob passkey;
cryptohome::Crypto::PasswordToPasskey(trimmed_password.c_str(),
GetSystemSalt(proxy), &passkey);
*password_out = passkey.to_string();
return true;
}
bool IsMixingOldAndNewFileSwitches(const base::CommandLine* cl) {
return cl->HasSwitch(switches::kFileSwitch) &&
(cl->HasSwitch(switches::kInputFileSwitch) ||
cl->HasSwitch(switches::kOutputFileSwitch));
}
FilePath GetFile(const base::CommandLine* cl) {
const char kDefaultFilePath[] = "/tmp/__cryptohome";
FilePath file_path(cl->GetSwitchValueASCII(switches::kFileSwitch));
if (file_path.empty()) {
return FilePath(kDefaultFilePath);
}
return file_path;
}
FilePath GetInputFile(const base::CommandLine* cl) {
FilePath file_path(cl->GetSwitchValueASCII(switches::kInputFileSwitch));
if (file_path.empty()) {
return GetFile(cl);
}
return file_path;
}
FilePath GetOutputFile(const base::CommandLine* cl) {
FilePath file_path(cl->GetSwitchValueASCII(switches::kOutputFileSwitch));
if (file_path.empty()) {
return GetFile(cl);
}
return file_path;
}
bool GetProfile(const base::CommandLine* cl,
cryptohome::CertificateProfile* profile) {
const std::string profile_str =
cl->GetSwitchValueASCII(switches::kProfileSwitch);
if (profile_str.empty() || profile_str == "enterprise_user" ||
profile_str == "user" || profile_str == "u") {
*profile = cryptohome::ENTERPRISE_USER_CERTIFICATE;
} else if (profile_str == "enterprise_machine" || profile_str == "machine" ||
profile_str == "m") {
*profile = cryptohome::ENTERPRISE_MACHINE_CERTIFICATE;
} else if (profile_str == "enterprise_enrollment" ||
profile_str == "enrollment" || profile_str == "e") {
*profile = cryptohome::ENTERPRISE_ENROLLMENT_CERTIFICATE;
} else if (profile_str == "content_protection" || profile_str == "content" ||
profile_str == "c") {
*profile = cryptohome::CONTENT_PROTECTION_CERTIFICATE;
} else if (profile_str == "content_protection_with_stable_id" ||
profile_str == "cpsi") {
*profile = cryptohome::CONTENT_PROTECTION_CERTIFICATE_WITH_STABLE_ID;
} else if (profile_str == "cast") {
*profile = cryptohome::CAST_CERTIFICATE;
} else if (profile_str == "gfsc") {
*profile = cryptohome::GFSC_CERTIFICATE;
} else if (profile_str == "jetstream") {
*profile = cryptohome::JETSTREAM_CERTIFICATE;
} else {
printf("Unknown certificate profile: %s.\n", profile_str.c_str());
return false;
}
return true;
}
bool ConfirmRemove(const std::string& user) {
printf("!!! Are you sure you want to remove the user's cryptohome?\n");
printf("!!!\n");
printf("!!! Re-enter the username at the prompt to remove the\n");
printf("!!! cryptohome for the user.\n");
printf("Enter the username <%s>: ", user.c_str());
fflush(stdout);
char buffer[256];
if (!fgets(buffer, base::size(buffer), stdin)) {
printf("Error while reading username.\n");
return false;
}
std::string verification = buffer;
// fgets will append the newline character, remove it.
base::TrimWhitespaceASCII(verification, base::TRIM_ALL, &verification);
if (user != verification) {
printf("Usernames do not match.\n");
return false;
}
return true;
}
GArray* GArrayFromProtoBuf(const google::protobuf::MessageLite& pb) {
size_t len_raw = pb.ByteSizeLong();
if (len_raw > G_MAXUINT) {
printf("Protocol buffer too large.\n");
return NULL;
}
guint len = len_raw;
GArray* ary = g_array_sized_new(FALSE, FALSE, 1, len);
g_array_set_size(ary, len);
if (!pb.SerializeToArray(ary->data, len)) {
printf("Failed to serialize protocol buffer.\n");
return NULL;
}
return ary;
}
bool BuildAccountId(base::CommandLine* cl, cryptohome::AccountIdentifier* id) {
std::string account_id;
if (!GetAccountId(cl, &account_id)) {
printf("No account_id specified.\n");
return false;
}
id->set_account_id(account_id);
return true;
}
bool BuildAuthorization(base::CommandLine* cl,
const brillo::dbus::Proxy& proxy,
bool need_password,
cryptohome::AuthorizationRequest* auth) {
if (need_password) {
// Check if restore key is provided
if (cl->HasSwitch(switches::kRestoreKeyInHexSwitch)) {
brillo::SecureBlob raw_byte(
cl->GetSwitchValueASCII(switches::kRestoreKeyInHexSwitch));
if (raw_byte.to_string().length() == 0) {
printf("No hex string specified\n");
return false;
}
SecureBlob::HexStringToSecureBlob(raw_byte.to_string(), &raw_byte);
auth->mutable_key()->set_secret(raw_byte.to_string());
} else {
std::string password;
GetPassword(proxy, cl, switches::kPasswordSwitch, "Enter the password",
&password);
auth->mutable_key()->set_secret(password);
}
}
if (cl->HasSwitch(switches::kKeyLabelSwitch)) {
auth->mutable_key()->mutable_data()->set_label(
cl->GetSwitchValueASCII(switches::kKeyLabelSwitch));
}
return true;
}
void ParseBaseReply(GArray* reply_ary,
cryptohome::BaseReply* reply,
bool print_reply) {
if (!reply)
return;
if (!reply->ParseFromArray(reply_ary->data, reply_ary->len)) {
printf("Failed to parse reply.\n");
exit(1);
}
if (print_reply)
reply->PrintDebugString();
}
class ClientLoop {
public:
ClientLoop()
: loop_(NULL),
async_call_id_(0),
return_status_(false),
return_code_(0) {}
virtual ~ClientLoop() {
if (loop_) {
g_main_loop_unref(loop_);
}
}
void Initialize(brillo::dbus::Proxy* proxy) {
dbus_g_object_register_marshaller(g_cclosure_marshal_generic, G_TYPE_NONE,
G_TYPE_INT, G_TYPE_BOOLEAN, G_TYPE_INT,
G_TYPE_INVALID);
dbus_g_proxy_add_signal(proxy->gproxy(), "AsyncCallStatus", G_TYPE_INT,
G_TYPE_BOOLEAN, G_TYPE_INT, G_TYPE_INVALID);
dbus_g_proxy_connect_signal(proxy->gproxy(), "AsyncCallStatus",
G_CALLBACK(ClientLoop::CallbackThunk), this,
NULL);
dbus_g_object_register_marshaller(g_cclosure_marshal_generic, G_TYPE_NONE,
G_TYPE_INT, G_TYPE_BOOLEAN,
DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_INVALID);
dbus_g_proxy_add_signal(proxy->gproxy(), "AsyncCallStatusWithData",
G_TYPE_INT, G_TYPE_BOOLEAN, DBUS_TYPE_G_UCHAR_ARRAY,
G_TYPE_INVALID);
dbus_g_proxy_connect_signal(proxy->gproxy(), "AsyncCallStatusWithData",
G_CALLBACK(ClientLoop::CallbackDataThunk), this,
NULL);
loop_ = g_main_loop_new(NULL, TRUE);
}
void Run(int async_call_id) {
async_call_id_ = async_call_id;
g_main_loop_run(loop_);
}
void Run() { Run(0); }
// This callback can be used with a ClientLoop instance as the |userdata| to
// handle an asynchronous reply which emits a serialized BaseReply.
static void ParseReplyThunk(DBusGProxy* proxy,
GArray* data,
GError* error,
gpointer userdata) {
reinterpret_cast<ClientLoop*>(userdata)->ParseReply(data, error);
}
bool get_return_status() { return return_status_; }
int get_return_code() { return return_code_; }
std::string get_return_data() { return return_data_; }
cryptohome::BaseReply reply() { return reply_; }
private:
void Callback(int async_call_id, bool return_status, int return_code) {
if (async_call_id == async_call_id_) {
return_status_ = return_status;
return_code_ = return_code;
g_main_loop_quit(loop_);
}
}
void CallbackWithData(int async_call_id, bool return_status, GArray* data) {
if (async_call_id == async_call_id_) {
return_status_ = return_status;
return_data_ = std::string(static_cast<char*>(data->data), data->len);
g_main_loop_quit(loop_);
}
}
void ParseReply(GArray* reply_ary, GError* error) {
if (error && error->message) {
printf("Call error: %s\n", error->message);
exit(1);
}
ParseBaseReply(reply_ary, &reply_, true /* print_reply */);
g_main_loop_quit(loop_);
}
static void CallbackThunk(DBusGProxy* proxy,
int async_call_id,
bool return_status,
int return_code,
gpointer userdata) {
reinterpret_cast<ClientLoop*>(userdata)->Callback(
async_call_id, return_status, return_code);
}
static void CallbackDataThunk(DBusGProxy* proxy,
int async_call_id,
bool return_status,
GArray* data,
gpointer userdata) {
reinterpret_cast<ClientLoop*>(userdata)->CallbackWithData(
async_call_id, return_status, data);
}
GMainLoop* loop_;
int async_call_id_;
bool return_status_;
int return_code_;
std::string return_data_;
cryptohome::BaseReply reply_;
};
bool MakeProtoDBusCall(const std::string& name,
ProtoDBusMethod method,
ProtoDBusAsyncMethod async_method,
base::CommandLine* cl,
brillo::dbus::Proxy* proxy,
const google::protobuf::MessageLite& request,
cryptohome::BaseReply* reply,
bool print_reply) {
brillo::glib::ScopedArray request_ary(GArrayFromProtoBuf(request));
if (cl->HasSwitch(switches::kAsyncSwitch)) {
ClientLoop loop;
loop.Initialize(proxy);
DBusGProxyCall* call = (*async_method)(proxy->gproxy(), request_ary.get(),
&ClientLoop::ParseReplyThunk,
static_cast<gpointer>(&loop));
if (!call) {
printf("Failed to call %s!\n", name.c_str());
return false;
}
loop.Run();
*reply = loop.reply();
} else {
brillo::glib::ScopedError error;
brillo::glib::ScopedArray reply_ary;
if (!(*method)(proxy->gproxy(), request_ary.get(),
&brillo::Resetter(&reply_ary).lvalue(),
&brillo::Resetter(&error).lvalue())) {
printf("Failed to call %s: %s\n", name.c_str(), error->message);
return false;
}
ParseBaseReply(reply_ary.get(), reply, print_reply);
}
if (reply->has_error()) {
printf("%s error: %d\n", name.c_str(), reply->error());
return false;
}
return true;
}
std::string GetPCAName(int pca_type) {
switch (pca_type) {
case attestation::DEFAULT_ACA:
return "the default ACA";
case attestation::TEST_ACA:
return "the test ACA";
default: {
std::ostringstream stream;
stream << "ACA " << pca_type;
return stream.str();
}
}
}
int main(int argc, char** argv) {
base::CommandLine::Init(argc, argv);
base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
if (cl->HasSwitch(switches::kSyslogSwitch))
brillo::InitLog(brillo::kLogToSyslog | brillo::kLogToStderr);
else
brillo::InitLog(brillo::kLogToStderr);
int pca_type = attestation::ACAType_ARRAYSIZE;
if (cl->HasSwitch(switches::kAttestationServerSwitch)) {
std::string server =
cl->GetSwitchValueASCII(switches::kAttestationServerSwitch);
for (int i = 0; switches::kAttestationServers[i].name; ++i) {
if (server == switches::kAttestationServers[i].name) {
pca_type = switches::kAttestationServers[i].aca_type;
break;
}
}
if (pca_type == attestation::ACAType_ARRAYSIZE) {
printf("Invalid attestation server: %s\n", server.c_str());
return 1;
}
} else {
pca_type = attestation::DEFAULT_ACA;
}
int va_type = attestation::VAType_ARRAYSIZE;
std::string va_server(
cl->HasSwitch(switches::kVaServerSwitch)
? cl->GetSwitchValueASCII(switches::kVaServerSwitch)
: cl->GetSwitchValueASCII(switches::kAttestationServerSwitch));
if (va_server.size()) {
for (int i = 0; switches::kVaServers[i].name; ++i) {
if (va_server == switches::kVaServers[i].name) {
va_type = switches::kVaServers[i].va_type;
break;
}
}
if (va_type == attestation::VAType_ARRAYSIZE) {
printf("Invalid Verified Access server: %s\n", va_server.c_str());
return 1;
}
} else {
va_type = attestation::DEFAULT_VA;
}
if (IsMixingOldAndNewFileSwitches(cl)) {
printf("Use either --%s and --%s together, or --%s only.\n",
switches::kInputFileSwitch, switches::kOutputFileSwitch,
switches::kFileSwitch);
return 1;
}
std::string action = cl->GetSwitchValueASCII(switches::kActionSwitch);
brillo::dbus::BusConnection bus = brillo::dbus::GetSystemBusConnection();
brillo::dbus::Proxy proxy(bus, cryptohome::kCryptohomeServiceName,
cryptohome::kCryptohomeServicePath,
cryptohome::kCryptohomeInterface);
DCHECK(proxy.gproxy()) << "Failed to acquire proxy";
dbus_g_proxy_set_default_timeout(proxy.gproxy(), kDefaultTimeoutMs);
cryptohome::Platform platform;
if (!strcmp(switches::kActions[switches::ACTION_MOUNT_EX], action.c_str())) {
bool is_public_mount = cl->HasSwitch(switches::kPublicMount);
cryptohome::AccountIdentifier id;
if (!BuildAccountId(cl, &id))
return 1;
cryptohome::AuthorizationRequest auth;
if (!BuildAuthorization(cl, proxy, !is_public_mount, &auth))
return 1;
cryptohome::MountRequest mount_req;
mount_req.set_require_ephemeral(
cl->HasSwitch(switches::kEnsureEphemeralSwitch));
mount_req.set_to_migrate_from_ecryptfs(
cl->HasSwitch(switches::kToMigrateFromEcryptfsSwitch));
mount_req.set_hidden_mount(cl->HasSwitch(switches::kHiddenMount));
mount_req.set_public_mount(is_public_mount);
if (cl->HasSwitch(switches::kCreateSwitch)) {
cryptohome::CreateRequest* create = mount_req.mutable_create();
if (cl->HasSwitch(switches::kPublicMount)) {
cryptohome::Key* key = create->add_keys();
key->mutable_data()->set_label(auth.key().data().label());
} else {
create->set_copy_authorization_key(true);
}
if (cl->HasSwitch(switches::kEcryptfsSwitch)) {
create->set_force_ecryptfs(true);
}
}
brillo::glib::ScopedArray account_ary(GArrayFromProtoBuf(id));
brillo::glib::ScopedArray auth_ary(GArrayFromProtoBuf(auth));
brillo::glib::ScopedArray req_ary(GArrayFromProtoBuf(mount_req));
if (!account_ary.get() || !auth_ary.get() || !req_ary.get())
return 1;
cryptohome::BaseReply reply;
brillo::glib::ScopedError error;
if (cl->HasSwitch(switches::kAsyncSwitch)) {
ClientLoop loop;
loop.Initialize(&proxy);
DBusGProxyCall* call = org_chromium_CryptohomeInterface_mount_ex_async(
proxy.gproxy(), account_ary.get(), auth_ary.get(), req_ary.get(),
&ClientLoop::ParseReplyThunk, static_cast<gpointer>(&loop));
if (!call)
return 1;
loop.Run();
reply = loop.reply();
} else {
GArray* out_reply = NULL;
if (!org_chromium_CryptohomeInterface_mount_ex(
proxy.gproxy(), account_ary.get(), auth_ary.get(), req_ary.get(),
&out_reply, &brillo::Resetter(&error).lvalue())) {
printf("MountEx call failed: %s", error->message);
return 1;
}
ParseBaseReply(out_reply, &reply, true /* print_reply */);
}
if (reply.has_error()) {
printf("Mount failed.\n");
return reply.error();
}
printf("Mount succeeded.\n");
} else if (!strcmp(switches::kActions[switches::ACTION_MOUNT_GUEST_EX],
action.c_str())) {
cryptohome::BaseReply reply;
cryptohome::MountGuestRequest request;
brillo::glib::ScopedError error;
GArray* out_reply = NULL;
brillo::glib::ScopedArray guest_request_ary(GArrayFromProtoBuf(request));
if (!org_chromium_CryptohomeInterface_mount_guest_ex(
proxy.gproxy(), guest_request_ary.get(), &out_reply,
&brillo::Resetter(&error).lvalue())) {
printf("Mount call failed: %s.\n", error->message);
return 1;
}
ParseBaseReply(out_reply, &reply, true /* print_reply */);
if (reply.has_error()) {
printf("Mount failed.\n");
return reply.error();
}
printf("Mount succeeded.\n");
} else if (!strcmp(switches::kActions
[switches::ACTION_START_FINGERPRINT_AUTH_SESSION],
action.c_str())) {
cryptohome::AccountIdentifier id;
if (!BuildAccountId(cl, &id))
return 1;
cryptohome::StartFingerprintAuthSessionRequest req;
brillo::glib::ScopedArray account_ary(GArrayFromProtoBuf(id));
brillo::glib::ScopedArray req_ary(GArrayFromProtoBuf(req));
if (!account_ary.get() || !req_ary.get())
return 1;
cryptohome::BaseReply reply;
brillo::glib::ScopedError error;
GArray* out_reply = NULL;
if (!org_chromium_CryptohomeInterface_start_fingerprint_auth_session(
proxy.gproxy(), account_ary.get(), req_ary.get(), &out_reply,
&brillo::Resetter(&error).lvalue())) {
printf("StartFingerprintAuthSession call failed: %s", error->message);
return 1;
}
ParseBaseReply(out_reply, &reply, true /* print_reply */);
if (reply.has_error()) {
printf("Fingerprint auth session failed to start.\n");
return reply.error();
}
} else if (!strcmp(switches::kActions
[switches::ACTION_END_FINGERPRINT_AUTH_SESSION],
action.c_str())) {
cryptohome::EndFingerprintAuthSessionRequest req;
brillo::glib::ScopedArray req_ary(GArrayFromProtoBuf(req));
if (!req_ary.get())
return 1;
brillo::glib::ScopedError error;
GArray* out_reply = NULL;
if (!org_chromium_CryptohomeInterface_end_fingerprint_auth_session(
proxy.gproxy(), req_ary.get(), &out_reply,
&brillo::Resetter(&error).lvalue())) {
printf("EndFingerprintAuthSession call failed: %s", error->message);
return 1;
}
// EndFingerprintAuthSession always succeeds.
} else if (!strcmp(switches::kActions[switches::ACTION_REMOVE_KEY_EX],
action.c_str())) {
cryptohome::AccountIdentifier id;
if (!BuildAccountId(cl, &id))
return 1;
cryptohome::AuthorizationRequest auth;
if (!BuildAuthorization(cl, proxy, true /* need_password */, &auth))
return 1;
cryptohome::RemoveKeyRequest remove_req;
cryptohome::KeyData* data = remove_req.mutable_key()->mutable_data();
data->set_label(cl->GetSwitchValueASCII(switches::kRemoveKeyLabelSwitch));
brillo::glib::ScopedArray account_ary(GArrayFromProtoBuf(id));
brillo::glib::ScopedArray auth_ary(GArrayFromProtoBuf(auth));
brillo::glib::ScopedArray req_ary(GArrayFromProtoBuf(remove_req));
if (!account_ary.get() || !auth_ary.get() || !req_ary.get())
return 1;
cryptohome::BaseReply reply;
brillo::glib::ScopedError error;
if (cl->HasSwitch(switches::kAsyncSwitch)) {
ClientLoop loop;
loop.Initialize(&proxy);
DBusGProxyCall* call =
org_chromium_CryptohomeInterface_remove_key_ex_async(
proxy.gproxy(), account_ary.get(), auth_ary.get(), req_ary.get(),
&ClientLoop::ParseReplyThunk, static_cast<gpointer>(&loop));
if (!call)
return 1;
loop.Run();
reply = loop.reply();
} else {
GArray* out_reply = NULL;
if (!org_chromium_CryptohomeInterface_remove_key_ex(
proxy.gproxy(), account_ary.get(), auth_ary.get(), req_ary.get(),
&out_reply, &brillo::Resetter(&error).lvalue())) {
printf("RemoveKeyEx call failed: %s", error->message);
return 1;
}
ParseBaseReply(out_reply, &reply, true /* print_reply */);
}
if (reply.has_error()) {
printf("Key removal failed.\n");
return reply.error();
}
printf("Key removed.\n");
} else if (!strcmp(switches::kActions[switches::ACTION_GET_KEY_DATA_EX],
action.c_str())) {
cryptohome::AccountIdentifier id;
if (!BuildAccountId(cl, &id)) {
return 1;
}
cryptohome::AuthorizationRequest auth;
cryptohome::GetKeyDataRequest key_data_req;
const std::string label =
cl->GetSwitchValueASCII(switches::kKeyLabelSwitch);
if (label.empty()) {
printf("No key_label specified.\n");
return 1;
}
key_data_req.mutable_key()->mutable_data()->set_label(label);
brillo::glib::ScopedArray account_ary(GArrayFromProtoBuf(id));
brillo::glib::ScopedArray auth_ary(GArrayFromProtoBuf(auth));
brillo::glib::ScopedArray req_ary(GArrayFromProtoBuf(key_data_req));
if (!account_ary.get() || !auth_ary.get() || !req_ary.get()) {
return 1;
}
cryptohome::BaseReply reply;
brillo::glib::ScopedError error;
if (cl->HasSwitch(switches::kAsyncSwitch)) {
ClientLoop loop;
loop.Initialize(&proxy);
DBusGProxyCall* call =
org_chromium_CryptohomeInterface_get_key_data_ex_async(
proxy.gproxy(), account_ary.get(), auth_ary.get(), req_ary.get(),
&ClientLoop::ParseReplyThunk, static_cast<gpointer>(&loop));
if (!call) {
return 1;
}
loop.Run();
reply = loop.reply();
} else {
GArray* out_reply = NULL;
if (!org_chromium_CryptohomeInterface_get_key_data_ex(
proxy.gproxy(), account_ary.get(), auth_ary.get(), req_ary.get(),
&out_reply, &brillo::Resetter(&error).lvalue())) {
printf("GetKeyDataEx call failed: %s", error->message);
return 1;
}
ParseBaseReply(out_reply, &reply, true /* print_reply */);
}
if (reply.has_error()) {
printf("Key retrieval failed.\n");
return reply.error();
}
} else if (!strcmp(switches::kActions[switches::ACTION_LIST_KEYS_EX],
action.c_str())) {
cryptohome::AccountIdentifier id;
if (!BuildAccountId(cl, &id))
return 1;
cryptohome::AuthorizationRequest auth;
cryptohome::ListKeysRequest list_keys_req;
brillo::glib::ScopedArray account_ary(GArrayFromProtoBuf(id));
brillo::glib::ScopedArray auth_ary(GArrayFromProtoBuf(auth));
brillo::glib::ScopedArray req_ary(GArrayFromProtoBuf(list_keys_req));
if (!account_ary.get() || !auth_ary.get() || !req_ary.get())
return 1;
cryptohome::BaseReply reply;
brillo::glib::ScopedError error;
if (cl->HasSwitch(switches::kAsyncSwitch)) {
ClientLoop loop;
loop.Initialize(&proxy);
DBusGProxyCall* call =
org_chromium_CryptohomeInterface_list_keys_ex_async(
proxy.gproxy(), account_ary.get(), auth_ary.get(), req_ary.get(),
&ClientLoop::ParseReplyThunk, static_cast<gpointer>(&loop));
if (!call) {
return 1;
}
loop.Run();
reply = loop.reply();
} else {
GArray* out_reply = NULL;
if (!org_chromium_CryptohomeInterface_list_keys_ex(
proxy.gproxy(), account_ary.get(), auth_ary.get(), req_ary.get(),
&out_reply, &brillo::Resetter(&error).lvalue())) {
printf("ListKeysEx call failed: %s", error->message);
return 1;
}
ParseBaseReply(out_reply, &reply, true /* print_reply */);
}
if (reply.has_error()) {
printf("Failed to list keys.\n");
return reply.error();
}
if (!reply.HasExtension(cryptohome::ListKeysReply::reply)) {
printf("ListKeysReply missing.\n");
return 1;
}
cryptohome::ListKeysReply list_keys_reply =
reply.GetExtension(cryptohome::ListKeysReply::reply);
for (int i = 0; i < list_keys_reply.labels_size(); ++i) {
printf("Label: %s\n", list_keys_reply.labels(i).c_str());
}
} else if (!strcmp(switches::kActions[switches::ACTION_CHECK_KEY_EX],
action.c_str())) {
cryptohome::AccountIdentifier id;
if (!BuildAccountId(cl, &id))
return 1;
cryptohome::AuthorizationRequest auth;
if (cl->HasSwitch(switches::kFingerprintSwitch)) {
auth.mutable_key()->mutable_data()->set_type(
cryptohome::KeyData::KEY_TYPE_FINGERPRINT);
} else if (!BuildAuthorization(cl, proxy, true /* need_password */,
&auth)) {
return 1;
}
cryptohome::CheckKeyRequest check_req;
// TODO(wad) Add a privileges cl interface
brillo::glib::ScopedArray account_ary(GArrayFromProtoBuf(id));
brillo::glib::ScopedArray auth_ary(GArrayFromProtoBuf(auth));
brillo::glib::ScopedArray req_ary(GArrayFromProtoBuf(check_req));
if (!account_ary.get() || !auth_ary.get() || !req_ary.get())
return 1;
cryptohome::BaseReply reply;
brillo::glib::ScopedError error;
if (cl->HasSwitch(switches::kAsyncSwitch)) {
ClientLoop loop;
loop.Initialize(&proxy);
DBusGProxyCall* call =
org_chromium_CryptohomeInterface_check_key_ex_async(
proxy.gproxy(), account_ary.get(), auth_ary.get(), req_ary.get(),
&ClientLoop::ParseReplyThunk, static_cast<gpointer>(&loop));
if (!call)
return 1;
loop.Run();
reply = loop.reply();
} else {
GArray* out_reply = NULL;
if (!org_chromium_CryptohomeInterface_check_key_ex(
proxy.gproxy(), account_ary.get(), auth_ary.get(), req_ary.get(),
&out_reply, &brillo::Resetter(&error).lvalue())) {
printf("CheckKeyEx call failed: %s", error->message);
return 1;
}
ParseBaseReply(out_reply, &reply, true /* print_reply */);
}
if (reply.has_error()) {
printf("Key authentication failed.\n");
return reply.error();
}
printf("Key authenticated.\n");
} else if (!strcmp(switches::kActions[switches::ACTION_ADD_DATA_RESTORE_KEY],
action.c_str())) {
cryptohome::AccountIdentifier id;
if (!BuildAccountId(cl, &id))
return 1;
cryptohome::AuthorizationRequest auth;
if (!BuildAuthorization(cl, proxy, true /* need_password */, &auth))
return 1;
brillo::glib::ScopedArray account_ary(GArrayFromProtoBuf(id));
brillo::glib::ScopedArray auth_ary(GArrayFromProtoBuf(auth));
if (!account_ary.get() || !auth_ary.get())
return 1;
cryptohome::BaseReply reply;
brillo::glib::ScopedError error;
if (cl->HasSwitch(switches::kAsyncSwitch)) {
ClientLoop loop;
loop.Initialize(&proxy);
DBusGProxyCall* call =
org_chromium_CryptohomeInterface_add_data_restore_key_async(
proxy.gproxy(), account_ary.get(), auth_ary.get(),
&ClientLoop::ParseReplyThunk, static_cast<gpointer>(&loop));
if (!call)
return 1;
loop.Run();
reply = loop.reply();
} else {
GArray* out_reply = NULL;
if (!org_chromium_CryptohomeInterface_add_data_restore_key(
proxy.gproxy(), account_ary.get(), auth_ary.get(), &out_reply,
&brillo::Resetter(&error).lvalue())) {
printf("Restore key addition failed: %s", error->message);
return 1;
}
ParseBaseReply(out_reply, &reply, true /* print_reply */);
}
if (reply.has_error()) {
printf("Restore key addition failed.\n");
return reply.error();
}
SecureBlob data_restore_key_raw(
reply.GetExtension(cryptohome::AddDataRestoreKeyReply::reply)
.data_restore_key());
printf("Restore key addition succeeded.\n");
printf("Here's the data restore key in hex: %s\n",
brillo::SecureBlobToSecureHex(data_restore_key_raw)
.to_string()
.c_str());
} else if (!strcmp(switches::kActions[switches::ACTION_MASS_REMOVE_KEYS],
action.c_str())) {
cryptohome::AccountIdentifier id;
if (!BuildAccountId(cl, &id))
return 1;
cryptohome::AuthorizationRequest auth;
if (!BuildAuthorization(cl, proxy, true /* need_password */, &auth))
return 1;
cryptohome::MassRemoveKeysRequest mass_remove_keys_request;
// Since it's unlikely to have comma in a label string,
// exempt_key_labels are seperated by comma from command line input
// ( e.g. --exempt_key_labels=label1,label2,label3 )
std::vector<std::string> exempt_labels = SplitString(
cl->GetSwitchValueASCII(switches::kMassRemoveExemptLabelsSwitch), ",",
base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
for (std::string label : exempt_labels) {
cryptohome::KeyData* data =
mass_remove_keys_request.add_exempt_key_data();
data->set_label(label);
}
brillo::glib::ScopedArray account_ary(GArrayFromProtoBuf(id));
brillo::glib::ScopedArray auth_ary(GArrayFromProtoBuf(auth));
brillo::glib::ScopedArray req_ary(
GArrayFromProtoBuf(mass_remove_keys_request));
if (!account_ary.get() || !auth_ary.get() || !req_ary.get())
return 1;
cryptohome::BaseReply reply;
brillo::glib::ScopedError error;
if (cl->HasSwitch(switches::kAsyncSwitch)) {
ClientLoop loop;
loop.Initialize(&proxy);
DBusGProxyCall* call =
org_chromium_CryptohomeInterface_mass_remove_keys_async(
proxy.gproxy(), account_ary.get(), auth_ary.get(), req_ary.get(),
&ClientLoop::ParseReplyThunk, static_cast<gpointer>(&loop));
if (!call)
return 1;
loop.Run();
reply = loop.reply();
} else {
GArray* out_reply = NULL;
if (!org_chromium_CryptohomeInterface_mass_remove_keys(
proxy.gproxy(), account_ary.get(), auth_ary.get(), req_ary.get(),
&out_reply, &brillo::Resetter(&error).lvalue())) {
printf("MassRemoveKeys call failed: %s", error->message);
return 1;
}
ParseBaseReply(out_reply, &reply, true /* print_reply */);
}
if (reply.has_error()) {
printf("MassRemoveKeys failed.\n");
return reply.error();
}
printf("MassRemoveKeys succeeded.\n");
} else if (!strcmp(switches::kActions[switches::ACTION_MIGRATE_KEY_EX],
action.c_str())) {
std::string account_id, password, old_password;
if (!GetAccountId(cl, &account_id)) {
return 1;
}
GetPassword(proxy, cl, switches::kPasswordSwitch,
StringPrintf("Enter the password for <%s>", account_id.c_str()),
&password);
GetPassword(
proxy, cl, switches::kOldPasswordSwitch,
StringPrintf("Enter the old password for <%s>", account_id.c_str()),
&old_password);
cryptohome::AccountIdentifier account;
cryptohome::AuthorizationRequest auth_request;
cryptohome::MigrateKeyRequest migrate_request;
account.set_account_id(account_id);
auth_request.mutable_key()->set_secret(old_password);
migrate_request.set_secret(password);
brillo::glib::ScopedArray account_ary(GArrayFromProtoBuf(account));
brillo::glib::ScopedArray auth_request_ary(
GArrayFromProtoBuf(auth_request));
brillo::glib::ScopedArray migrate_request_ary(
GArrayFromProtoBuf(migrate_request));
if (!account_ary.get() || !auth_request_ary.get() ||
!migrate_request_ary.get()) {
return 1;
}
cryptohome::BaseReply reply;
brillo::glib::ScopedError error;
GArray* out_reply = NULL;
if (!org_chromium_CryptohomeInterface_migrate_key_ex(
proxy.gproxy(), account_ary.get(), auth_request_ary.get(),
migrate_request_ary.get(), &out_reply,
&brillo::Resetter(&error).lvalue())) {
printf("MigrateKeyEx call failed: %s", error->message);
return 1;
}
ParseBaseReply(out_reply, &reply, true /* print_reply */);
if (reply.has_error()) {
printf("Key migration failed.\n");
return reply.error();
}
printf("Key migration succeeded.\n");
} else if (!strcmp(switches::kActions[switches::ACTION_ADD_KEY_EX],
action.c_str())) {
std::string new_password;
GetPassword(proxy, cl, switches::kNewPasswordSwitch,
"Enter the new password", &new_password);
cryptohome::AccountIdentifier id;
if (!BuildAccountId(cl, &id))
return 1;
cryptohome::AuthorizationRequest auth;
if (!BuildAuthorization(cl, proxy, true /* need_password */, &auth))
return 1;
cryptohome::AddKeyRequest key_req;
key_req.set_clobber_if_exists(cl->HasSwitch(switches::kForceSwitch));
cryptohome::Key* key = key_req.mutable_key();
key->set_secret(new_password);
cryptohome::KeyData* data = key->mutable_data();
data->set_label(cl->GetSwitchValueASCII(switches::kNewKeyLabelSwitch));
if (cl->HasSwitch(switches::kKeyPolicySwitch)) {
if (cl->GetSwitchValueASCII(switches::kKeyPolicySwitch) ==
switches::kKeyPolicyLECredential) {
data->mutable_policy()->set_low_entropy_credential(true);
} else {
printf("Unknown key policy.\n");
return 1;
}
}
// TODO(wad) Add a privileges cl interface
brillo::glib::ScopedArray account_ary(GArrayFromProtoBuf(id));
brillo::glib::ScopedArray auth_ary(GArrayFromProtoBuf(auth));
brillo::glib::ScopedArray req_ary(GArrayFromProtoBuf(key_req));
if (!account_ary.get() || !auth_ary.get() || !req_ary.get())
return 1;
cryptohome::BaseReply reply;
brillo::glib::ScopedError error;
if (cl->HasSwitch(switches::kAsyncSwitch)) {
ClientLoop loop;
loop.Initialize(&proxy);
DBusGProxyCall* call = org_chromium_CryptohomeInterface_add_key_ex_async(
proxy.gproxy(), account_ary.get(), auth_ary.get(), req_ary.get(),
&ClientLoop::ParseReplyThunk, static_cast<gpointer>(&loop));
if (!call)
return 1;
loop.Run();
reply = loop.reply();
} else {
GArray* out_reply = NULL;
if (!org_chromium_CryptohomeInterface_add_key_ex(
proxy.gproxy(), account_ary.get(), auth_ary.get(), req_ary.get(),
&out_reply, &brillo::Resetter(&error).lvalue())) {
printf("AddKeyEx call failed: %s", error->message);
return 1;
}
ParseBaseReply(out_reply, &reply, true /* print_reply */);
}
if (reply.has_error()) {
printf("Key addition failed.\n");
return reply.error();
}
printf("Key added.\n");
} else if (!strcmp(switches::kActions[switches::ACTION_REMOVE],
action.c_str())) {
std::string account_id;
if (!GetAccountId(cl, &account_id)) {
return 1;
}
if (!cl->HasSwitch(switches::kForceSwitch) && !ConfirmRemove(account_id)) {
return 1;
}
cryptohome::AccountIdentifier identifier;
identifier.set_account_id(account_id);
brillo::glib::ScopedArray account_ary(GArrayFromProtoBuf(identifier));
if (!account_ary.get())
return 1;
GArray* out_reply = nullptr;
brillo::glib::ScopedError error;
if (!org_chromium_CryptohomeInterface_remove_ex(
proxy.gproxy(), account_ary.get(), &out_reply,
&brillo::Resetter(&error).lvalue())) {
printf("Remove call failed: %s.\n", error->message);
return 1;
}
cryptohome::BaseReply reply;
ParseBaseReply(out_reply, &reply, true /* print_reply */);
if (reply.has_error()) {
printf("Remove failed.\n");
return 1;
}
printf("Remove succeeded.\n");
} else if (!strcmp(switches::kActions[switches::ACTION_UNMOUNT],
action.c_str())) {
cryptohome::UnmountRequest request;
brillo::glib::ScopedArray request_ary(GArrayFromProtoBuf(request));
if (!request_ary.get())
return 1;
GArray* out_reply = nullptr;
brillo::glib::ScopedError error;
if (!org_chromium_CryptohomeInterface_unmount_ex(
proxy.gproxy(), request_ary.get(), &out_reply,
&brillo::Resetter(&error).lvalue())) {
printf("Unmount call failed: %s.\n", error->message);
return 1;
}
cryptohome::BaseReply reply;
ParseBaseReply(out_reply, &reply, true /* print_reply */);
if (reply.has_error()) {
printf("Unmount failed.\n");
return 1;
}
printf("Unmount succeeded.\n");
} else if (!strcmp(switches::kActions[switches::ACTION_MOUNTED],
action.c_str())) {
brillo::glib::ScopedError error;
gboolean done = false;
if (!org_chromium_CryptohomeInterface_is_mounted(
proxy.gproxy(), &done, &brillo::Resetter(&error).lvalue())) {
printf("IsMounted call failed: %s.\n", error->message);
}
if (done) {
printf("true\n");
} else {
printf("false\n");
}
} else if (!strcmp(switches::kActions[switches::ACTION_OBFUSCATE_USER],
action.c_str())) {
std::string account_id;
if (!GetAccountId(cl, &account_id)) {
return 1;
}
if (cl->HasSwitch(switches::kUseDBus)) {
gchar* result;
brillo::glib::ScopedError error;
if (!org_chromium_CryptohomeInterface_get_sanitized_username(
proxy.gproxy(), account_id.c_str(), &result,
&brillo::Resetter(&error).lvalue())) {
printf("GetSanitizedUserName call failed: %s.\n", error->message);
return 1;
}
printf("%s\n", result);
} else {
// Use libbrillo directly instead of going through dbus/cryptohome.
if (!brillo::cryptohome::home::EnsureSystemSaltIsLoaded()) {
printf("Failed to load system salt\n");
return 1;
}
std::string* salt_ptr = brillo::cryptohome::home::GetSystemSalt();
brillo::SecureBlob system_salt = SecureBlob(*salt_ptr);
printf("%s\n", SanitizeUserNameWithSalt(account_id, system_salt).c_str());
}
} else if (!strcmp(switches::kActions[switches::ACTION_GET_SYSTEM_SALT],
action.c_str())) {
brillo::SecureBlob system_salt;
if (cl->HasSwitch(switches::kUseDBus)) {
system_salt = GetSystemSalt(proxy);
if (system_salt.empty()) {
printf("Failed to retrieve system salt\n");
}
} else {
// Use libbrillo directly instead of going through dbus/cryptohome.
if (!brillo::cryptohome::home::EnsureSystemSaltIsLoaded()) {
printf("Failed to load system salt\n");
return 1;
}
std::string* salt_ptr = brillo::cryptohome::home::GetSystemSalt();
system_salt = SecureBlob(*salt_ptr);
}
std::string hex_salt =
base::HexEncode(system_salt.data(), system_salt.size());
// We want to follow the convention of having low case hex for output as in
// GetSanitizedUsername().
std::transform(hex_salt.begin(), hex_salt.end(), hex_salt.begin(),
::tolower);
printf("%s\n", hex_salt.c_str());
} else if (!strcmp(switches::kActions[switches::ACTION_DUMP_KEYSET],
action.c_str())) {
std::string account_id;
if (!GetAccountId(cl, &account_id)) {
return 1;
}
FilePath vault_path =
FilePath("/home/.shadow")
.Append(SanitizeUserNameWithSalt(account_id, GetSystemSalt(proxy)))
.Append("master.0");
brillo::Blob contents;
if (!platform.ReadFile(vault_path, &contents)) {
printf("Couldn't load keyset contents: %s.\n",
vault_path.value().c_str());
return 1;
}
cryptohome::SerializedVaultKeyset serialized;
if (!serialized.ParseFromArray(contents.data(), contents.size())) {
printf("Couldn't parse keyset contents: %s.\n",
vault_path.value().c_str());
return 1;
}
printf("For keyset: %s\n", vault_path.value().c_str());
printf(" Flags:\n");
if ((serialized.flags() & cryptohome::SerializedVaultKeyset::TPM_WRAPPED) &&
serialized.has_tpm_key()) {
printf(" TPM_WRAPPED\n");
}
if ((serialized.flags() & cryptohome::SerializedVaultKeyset::PCR_BOUND) &&
serialized.has_tpm_key() && serialized.has_extended_tpm_key()) {
printf(" PCR_BOUND\n");
}
if (serialized.flags() &
cryptohome::SerializedVaultKeyset::SCRYPT_WRAPPED) {
printf(" SCRYPT_WRAPPED\n");
}
SecureBlob blob(serialized.salt().length());
serialized.salt().copy(blob.char_data(), serialized.salt().length(), 0);
printf(" Salt:\n");
printf(" %s\n", cryptohome::CryptoLib::SecureBlobToHex(blob).c_str());
blob.resize(serialized.wrapped_keyset().length());
serialized.wrapped_keyset().copy(blob.char_data(),
serialized.wrapped_keyset().length(), 0);
printf(" Wrapped (Encrypted) Keyset:\n");
printf(" %s\n", cryptohome::CryptoLib::SecureBlobToHex(blob).c_str());
if (serialized.has_tpm_key()) {
blob.resize(serialized.tpm_key().length());
serialized.tpm_key().copy(blob.char_data(), serialized.tpm_key().length(),
0);
printf(" TPM-Bound (Encrypted) Vault Encryption Key:\n");
printf(" %s\n", cryptohome::CryptoLib::SecureBlobToHex(blob).c_str());
}
if (serialized.has_extended_tpm_key()) {
blob.resize(serialized.extended_tpm_key().length());
serialized.extended_tpm_key().copy(
blob.char_data(), serialized.extended_tpm_key().length(), 0);
printf(" TPM-Bound (Encrypted) Vault Encryption Key, PCR extended:\n");
printf(" %s\n", cryptohome::CryptoLib::SecureBlobToHex(blob).c_str());
}
if (serialized.has_tpm_public_key_hash()) {
blob.resize(serialized.tpm_public_key_hash().length());
serialized.tpm_public_key_hash().copy(blob.char_data(),
serialized.tpm_key().length(), 0);
printf(" TPM Public Key Hash:\n");
printf(" %s\n", cryptohome::CryptoLib::SecureBlobToHex(blob).c_str());
}
if (serialized.has_password_rounds()) {
printf(" Password rounds:\n");
printf(" %d\n", serialized.password_rounds());
}
base::Time last_activity =
base::Time::FromInternalValue(serialized.last_activity_timestamp());
FilePath timestamp_path = vault_path.AddExtension("timestamp");
brillo::Blob tcontents;
if (platform.ReadFile(timestamp_path, &tcontents)) {
cryptohome::Timestamp timestamp;
if (!timestamp.ParseFromArray(tcontents.data(), tcontents.size())) {
printf("Couldn't parse timestamp contents: %s.\n",
timestamp_path.value().c_str());
}
last_activity = base::Time::FromInternalValue(timestamp.timestamp());
} else {
printf("Couldn't load timestamp contents: %s.\n",
timestamp_path.value().c_str());
}
printf(" Last activity (days ago):\n");
printf(" %d\n", (base::Time::Now() - last_activity).InDays());
} else if (!strcmp(switches::kActions[switches::ACTION_DUMP_LAST_ACTIVITY],
action.c_str())) {
std::vector<FilePath> user_dirs;
if (!platform.EnumerateDirectoryEntries(FilePath("/home/.shadow/"), false,
&user_dirs)) {
LOG(ERROR) << "Can not list shadow root.";
return 1;
}
for (std::vector<FilePath>::iterator it = user_dirs.begin();
it != user_dirs.end(); ++it) {
const std::string dir_name = it->BaseName().value();
if (!brillo::cryptohome::home::IsSanitizedUserName(dir_name))
continue;
// TODO(wad): change it so that it uses GetVaultKeysets().
std::unique_ptr<cryptohome::FileEnumerator> file_enumerator(
platform.GetFileEnumerator(*it, false, base::FileEnumerator::FILES));
base::Time max_activity = base::Time::UnixEpoch();
FilePath next_path;
while (!(next_path = file_enumerator->Next()).empty()) {
FilePath file_name = next_path.BaseName().RemoveFinalExtension();
// Scan for "master." files.
if (file_name.value() != cryptohome::kKeyFile)
continue;
brillo::Blob contents;
if (!platform.ReadFile(next_path, &contents)) {
LOG(ERROR) << "Couldn't load keyset: " << next_path.value();
continue;
}
cryptohome::SerializedVaultKeyset keyset;
if (!keyset.ParseFromArray(contents.data(), contents.size())) {
LOG(ERROR) << "Couldn't parse keyset: " << next_path.value();
continue;
}
base::Time last_activity =
base::Time::FromInternalValue(keyset.last_activity_timestamp());
FilePath timestamp_path = next_path.AddExtension("timestamp");
brillo::Blob tcontents;
if (platform.ReadFile(timestamp_path, &tcontents)) {
cryptohome::Timestamp timestamp;
if (!timestamp.ParseFromArray(tcontents.data(), tcontents.size())) {
printf("Couldn't parse timestamp contents: %s.\n",
timestamp_path.value().c_str());
}
last_activity = base::Time::FromInternalValue(timestamp.timestamp());
} else {
printf("Couldn't load timestamp contents: %s.\n",
timestamp_path.value().c_str());
}
if (last_activity > max_activity) {
max_activity = last_activity;
}
}
if (max_activity > base::Time::UnixEpoch()) {
printf("%s %3d\n", dir_name.c_str(),
(base::Time::Now() - max_activity).InDays());
}
}
} else if (!strcmp(switches::kActions[switches::ACTION_TPM_STATUS],
action.c_str())) {
brillo::glib::ScopedError error;
gboolean result = false;
if (!org_chromium_CryptohomeInterface_tpm_is_enabled(
proxy.gproxy(), &result, &brillo::Resetter(&error).lvalue())) {
printf("TpmIsEnabled call failed: %s.\n", error->message);
} else {
printf("TPM Enabled: %s\n", (result ? "true" : "false"));
}
result = false;
if (!org_chromium_CryptohomeInterface_tpm_is_owned(
proxy.gproxy(), &result, &brillo::Resetter(&error).lvalue())) {
printf("TpmIsOwned call failed: %s.\n", error->message);
} else {
printf("TPM Owned: %s\n", (result ? "true" : "false"));
}
if (!org_chromium_CryptohomeInterface_tpm_is_being_owned(
proxy.gproxy(), &result, &brillo::Resetter(&error).lvalue())) {
printf("TpmIsBeingOwned call failed: %s.\n", error->message);
} else {
printf("TPM Being Owned: %s\n", (result ? "true" : "false"));
}
if (!org_chromium_CryptohomeInterface_tpm_is_ready(
proxy.gproxy(), &result, &brillo::Resetter(&error).lvalue())) {
printf("TpmIsReady call failed: %s.\n", error->message);
} else {
printf("TPM Ready: %s\n", (result ? "true" : "false"));
}
gchar* password;
if (!org_chromium_CryptohomeInterface_tpm_get_password(
proxy.gproxy(), &password, &brillo::Resetter(&error).lvalue())) {
printf("TpmGetPassword call failed: %s.\n", error->message);
} else {
printf("TPM Password: %s\n", password);
g_free(password);
}
} else if (!strcmp(switches::kActions[switches::ACTION_TPM_MORE_STATUS],
action.c_str())) {
cryptohome::GetTpmStatusRequest request;
cryptohome::BaseReply reply;
if (!MakeProtoDBusCall(cryptohome::kCryptohomeGetTpmStatus,
DBUS_METHOD(get_tpm_status),
DBUS_METHOD(get_tpm_status_async), cl, &proxy,
request, &reply, true /* print_reply */)) {
return 1;
}
if (!reply.HasExtension(cryptohome::GetTpmStatusReply::reply)) {
printf("GetTpmStatusReply missing.\n");
return 1;
}
printf("GetTpmStatus success.\n");
} else if (!strcmp(switches::kActions[switches::ACTION_STATUS],
action.c_str())) {
brillo::glib::ScopedError error;
gchar* status;
if (!org_chromium_CryptohomeInterface_get_status_string(
proxy.gproxy(), &status, &brillo::Resetter(&error).lvalue())) {
printf("GetStatusString call failed: %s.\n", error->message);
} else {
printf("%s\n", status);
g_free(status);
}
} else if (!strcmp(switches::kActions[switches::ACTION_SET_CURRENT_USER_OLD],
action.c_str())) {
brillo::glib::ScopedError error;
ClientLoop client_loop;
client_loop.Initialize(&proxy);
if (!org_chromium_CryptohomeInterface_update_current_user_activity_timestamp( // NOLINT
proxy.gproxy(),
base::TimeDelta::FromDays(kSetCurrentUserOldOffsetInDays)
.InSeconds(),
&brillo::Resetter(&error).lvalue())) {
printf("UpdateCurrentUserActivityTimestamp call failed: %s.\n",
error->message);
} else {
printf(
"Timestamp successfully updated. You may verify it with "
"--action=dump_keyset --user=...\n");
}
} else if (!strcmp(switches::kActions[switches::ACTION_TPM_TAKE_OWNERSHIP],
action.c_str())) {
brillo::glib::ScopedError error;
if (!org_chromium_CryptohomeInterface_tpm_can_attempt_ownership(
proxy.gproxy(), &brillo::Resetter(&error).lvalue())) {
printf("TpmCanAttemptOwnership call failed: %s.\n", error->message);
}
} else if (!strcmp(
switches::kActions[switches::ACTION_TPM_CLEAR_STORED_PASSWORD],
action.c_str())) {
brillo::glib::ScopedError error;
if (!org_chromium_CryptohomeInterface_tpm_clear_stored_password(
proxy.gproxy(), &brillo::Resetter(&error).lvalue())) {
printf("TpmClearStoredPassword call failed: %s.\n", error->message);
}
} else if (!strcmp(
switches::kActions[switches::ACTION_INSTALL_ATTRIBUTES_GET],
action.c_str())) {
std::string name;
if (!GetAttrName(cl, &name)) {
printf("No attribute name specified.\n");
return 1;
}
brillo::glib::ScopedError error;
gboolean result;
if (!org_chromium_CryptohomeInterface_install_attributes_is_ready(
proxy.gproxy(), &result, &brillo::Resetter(&error).lvalue())) {
printf("IsReady call failed: %s.\n", error->message);
return 1;
}
if (result == FALSE) {
printf("InstallAttributes() is not ready.\n");
return 1;
}
brillo::glib::ScopedArray value;
if (!org_chromium_CryptohomeInterface_install_attributes_get(
proxy.gproxy(), name.c_str(), &brillo::Resetter(&value).lvalue(),
&result, &brillo::Resetter(&error).lvalue())) {
printf("Get() failed: %s.\n", error->message);
return 1;
}
std::string value_str(value->data, value->len);
if (result == TRUE) {
printf("%s\n", value_str.c_str());
} else {
return 1;
}
} else if (!strcmp(
switches::kActions[switches::ACTION_INSTALL_ATTRIBUTES_SET],
action.c_str())) {
std::string name;
if (!GetAttrName(cl, &name)) {
printf("No attribute name specified.\n");
return 1;
}
std::string value;
if (!GetAttrValue(cl, &value)) {
printf("No attribute value specified.\n");
return 1;
}
brillo::glib::ScopedError error;
gboolean result;
if (!org_chromium_CryptohomeInterface_install_attributes_is_ready(
proxy.gproxy(), &result, &brillo::Resetter(&error).lvalue())) {
printf("IsReady call failed: %s.\n", error->message);
return 1;
}
if (result == FALSE) {
printf("InstallAttributes() is not ready.\n");
return 1;
}
brillo::glib::ScopedArray value_ary(g_array_new(FALSE, FALSE, 1));
g_array_append_vals(value_ary.get(), value.c_str(), value.size() + 1);
if (!org_chromium_CryptohomeInterface_install_attributes_set(
proxy.gproxy(), name.c_str(), value_ary.get(), &result,
&brillo::Resetter(&error).lvalue())) {
printf("Set() failed: %s.\n", error->message);
return 1;
}
if (result == FALSE)
return 1;
} else if (!strcmp(switches::kActions
[switches::ACTION_INSTALL_ATTRIBUTES_FINALIZE],
action.c_str())) {
brillo::glib::ScopedError error;
gboolean result;
if (!org_chromium_CryptohomeInterface_install_attributes_is_ready(
proxy.gproxy(), &result, &brillo::Resetter(&error).lvalue())) {
printf("IsReady call failed: %s.\n", error->message);
return 1;
}
if (result == FALSE) {
printf("InstallAttributes is not ready.\n");
return 1;
}
if (!org_chromium_CryptohomeInterface_install_attributes_finalize(
proxy.gproxy(), &result, &brillo::Resetter(&error).lvalue())) {
printf("Finalize() failed: %s.\n", error->message);
return 1;
}
printf("InstallAttributesFinalize(): %d\n", result);
} else if (!strcmp(
switches::kActions[switches::ACTION_INSTALL_ATTRIBUTES_COUNT],
action.c_str())) {
brillo::glib::ScopedError error;
gint result;
if (!org_chromium_CryptohomeInterface_install_attributes_count(
proxy.gproxy(), &result, &brillo::Resetter(&error).lvalue())) {
printf("InstallAttributesCount() call failed: %s.\n", error->message);
return 1;
}
printf("InstallAttributesCount(): %d\n", result);
} else if (!strcmp(switches::kActions
[switches::ACTION_INSTALL_ATTRIBUTES_IS_READY],
action.c_str())) {
brillo::glib::ScopedError error;
gboolean result;
if (!org_chromium_CryptohomeInterface_install_attributes_is_ready(
proxy.gproxy(), &result, &brillo::Resetter(&error).lvalue())) {
printf("InstallAttributesIsReady() call failed: %s.\n", error->message);
return 1;
}
printf("InstallAttributesIsReady(): %d\n", static_cast<int>(result));
} else if (!strcmp(switches::kActions
[switches::ACTION_INSTALL_ATTRIBUTES_IS_SECURE],
action.c_str())) {
brillo::glib::ScopedError error;
gboolean result;
if (!org_chromium_CryptohomeInterface_install_attributes_is_secure(
proxy.gproxy(), &result, &brillo::Resetter(&error).lvalue())) {
printf("InstallAttributesIsSecure() call failed: %s.\n", error->message);
return 1;
}
printf("InstallAttributesIsSecure(): %d\n", static_cast<int>(result));
} else if (!strcmp(switches::kActions
[switches::ACTION_INSTALL_ATTRIBUTES_IS_INVALID],
action.c_str())) {
brillo::glib::ScopedError error;
gboolean result;
if (!org_chromium_CryptohomeInterface_install_attributes_is_invalid(
proxy.gproxy(), &result, &brillo::Resetter(&error).lvalue())) {
printf("InstallAttributesIsInvalid() call failed: %s.\n", error->message);
return 1;
}
printf("InstallAttributesIsInvalid(): %d\n", static_cast<int>(result));
} else if (!strcmp(switches::kActions
[switches::ACTION_INSTALL_ATTRIBUTES_IS_FIRST_INSTALL],
action.c_str())) {
brillo::glib::ScopedError error;
gboolean result;
if (!org_chromium_CryptohomeInterface_install_attributes_is_first_install(
proxy.gproxy(), &result, &brillo::Resetter(&error).lvalue())) {
printf("InstallAttributesIsFirstInstall() call failed: %s.\n",
error->message);
return 1;
}
printf("InstallAttributesIsFirstInstall(): %d\n", static_cast<int>(result));
} else if (!strcmp(switches::kActions[switches::ACTION_TPM_WAIT_OWNERSHIP],
action.c_str())) {
// Note that this is a rather hackish implementation that will be replaced
// once the refactor to distributed mode is over. It'll be replaced with an
// implementation that does one synchronous call to tpm_manager's
// TakeOwnership(), then check if it's owned.
int timeout = kWaitOwnershipTimeoutInSeconds;
int timeout_in_switch;
if (cl->HasSwitch(switches::kWaitOwnershipTimeoutSwitch) &&
base::StringToInt(
cl->GetSwitchValueASCII(switches::kWaitOwnershipTimeoutSwitch),
&timeout_in_switch)) {
timeout = timeout_in_switch;
}
brillo::glib::ScopedError error;
auto deadline = base::Time::Now() + base::TimeDelta::FromSeconds(timeout);
while (base::Time::Now() < deadline) {
base::PlatformThread::Sleep(
base::TimeDelta::FromMilliseconds(kWaitOwnershipPollIntervalInMs));
gboolean is_owned = false;
if (!org_chromium_CryptohomeInterface_tpm_is_owned(
proxy.gproxy(), &is_owned, &brillo::Resetter(&error).lvalue())) {
printf("TpmIsOwned call failed: %s.\n", error->message);
return 1;
}
if (is_owned) {
// This is the condition we are waiting for.
printf("TPM is now owned.\n");
return 0;
}
}
printf("Fail to own TPM.\n");
return 1;
} else if (!strcmp(switches::kActions
[switches::ACTION_PKCS11_GET_USER_TOKEN_INFO],
action.c_str())) {
// If no account_id is specified, proceed with the empty string.
std::string account_id = cl->GetSwitchValueASCII(switches::kUserSwitch);
if (!account_id.empty()) {
brillo::glib::ScopedError error;
gchar* label = NULL;
gchar* pin = NULL;
int slot = 0;
if (!org_chromium_CryptohomeInterface_pkcs11_get_tpm_token_info_for_user(
proxy.gproxy(), account_id.c_str(), &label, &pin, &slot,
&brillo::Resetter(&error).lvalue())) {
printf("PKCS #11 info call failed: %s.\n", error->message);
} else {
printf("Token properties for %s:\n", account_id.c_str());
printf("Label = %s\n", label);
printf("Pin = %s\n", pin);
printf("Slot = %d\n", slot);
g_free(label);
g_free(pin);
}
} else {
printf("Account ID/Username not specified.\n");
return 1;
}
} else if (!strcmp(switches::kActions
[switches::ACTION_PKCS11_GET_SYSTEM_TOKEN_INFO],
action.c_str())) {
brillo::glib::ScopedError error;
gchar* label = NULL;
gchar* pin = NULL;
int slot = 0;
if (!org_chromium_CryptohomeInterface_pkcs11_get_tpm_token_info(
proxy.gproxy(), &label, &pin, &slot,
&brillo::Resetter(&error).lvalue())) {
printf("PKCS #11 info call failed: %s.\n", error->message);
} else {
printf("System token properties:\n");
printf("Label = %s\n", label);
printf("Pin = %s\n", pin);
printf("Slot = %d\n", slot);
g_free(label);
g_free(pin);
}
} else if (!strcmp(
switches::kActions[switches::ACTION_PKCS11_IS_USER_TOKEN_OK],
action.c_str())) {
cryptohome::Pkcs11Init init;
if (!init.IsUserTokenOK()) {
printf("User token looks broken!\n");
return 1;
}
printf("User token looks OK!\n");
} else if (!strcmp(switches::kActions[switches::ACTION_PKCS11_TERMINATE],
action.c_str())) {
// If no account_id is specified, proceed with the empty string.
std::string account_id;
GetAccountId(cl, &account_id);
brillo::glib::ScopedError error;
if (!org_chromium_CryptohomeInterface_pkcs11_terminate(
proxy.gproxy(), account_id.c_str(),
&brillo::Resetter(&error).lvalue())) {
printf("PKCS #11 terminate call failed: %s.\n", error->message);
}
} else if (!strcmp(
switches::kActions[switches::ACTION_TPM_VERIFY_ATTESTATION],
action.c_str())) {
bool is_cros_core = cl->HasSwitch(switches::kCrosCoreSwitch);
brillo::glib::ScopedError error;
gboolean result = FALSE;
if (!org_chromium_CryptohomeInterface_tpm_verify_attestation_data(
proxy.gproxy(), is_cros_core, &result,
&brillo::Resetter(&error).lvalue())) {
printf("TpmVerifyAttestationData call failed: %s.\n", error->message);
return 1;
}
if (result == FALSE) {
printf("TPM attestation data is not valid or is not available.\n");
return 1;
}
} else if (!strcmp(switches::kActions[switches::ACTION_TPM_VERIFY_EK],
action.c_str())) {
bool is_cros_core = cl->HasSwitch(switches::kCrosCoreSwitch);
brillo::glib::ScopedError error;
gboolean result = FALSE;
if (!org_chromium_CryptohomeInterface_tpm_verify_ek(
proxy.gproxy(), is_cros_core, &result,
&brillo::Resetter(&error).lvalue())) {
printf("TpmVerifyEK call failed: %s.\n", error->message);
return 1;
}
if (result == FALSE) {
printf("TPM endorsement key is not valid or is not available.\n");
return 1;
}
} else if (!strcmp(
switches::kActions[switches::ACTION_TPM_ATTESTATION_STATUS],
action.c_str())) {
brillo::glib::ScopedError error;
gboolean result = FALSE;
if (!org_chromium_CryptohomeInterface_tpm_is_attestation_prepared(
proxy.gproxy(), &result, &brillo::Resetter(&error).lvalue())) {
printf("TpmIsAttestationPrepared call failed: %s.\n", error->message);
} else {
printf("Attestation Prepared: %s\n", (result ? "true" : "false"));
}
if (!org_chromium_CryptohomeInterface_tpm_is_attestation_enrolled(
proxy.gproxy(), &result, &brillo::Resetter(&error).lvalue())) {
printf("TpmIsAttestationEnrolled call failed: %s.\n", error->message);
} else {
printf("Attestation Enrolled: %s\n", (result ? "true" : "false"));
}
} else if (!strcmp(switches::kActions
[switches::ACTION_TPM_ATTESTATION_MORE_STATUS],
action.c_str())) {
cryptohome::AttestationGetEnrollmentPreparationsRequest request;
cryptohome::BaseReply reply;
if (!MakeProtoDBusCall(
cryptohome::kCryptohomeTpmAttestationGetEnrollmentPreparationsEx,
DBUS_METHOD(tpm_attestation_get_enrollment_preparations_ex),
DBUS_METHOD(tpm_attestation_get_enrollment_preparations_ex_async),
cl, &proxy, request, &reply, false /* print_reply */)) {
printf("TpmAttestationGetEnrollmentPreparationsEx call failed.\n");
} else if (!reply.HasExtension(
cryptohome::AttestationGetEnrollmentPreparationsReply::
reply)) {
printf("AttestationGetEnrollmentPreparationsReply missing.\n");
} else {
cryptohome::AttestationGetEnrollmentPreparationsReply* extension =
reply.MutableExtension(
cryptohome::AttestationGetEnrollmentPreparationsReply::reply);
auto map = extension->enrollment_preparations();
bool prepared = false;
for (auto it = map.cbegin(), end = map.cend(); it != end; ++it) {
prepared |= it->second;
}
printf("Attestation Prepared: %s\n", prepared ? "true" : "false");
for (auto it = map.cbegin(), end = map.cend(); it != end; ++it) {
printf(" Prepared for %s: %s\n", GetPCAName(it->first).c_str(),
(it->second ? "true" : "false"));
}
}
// TODO(crbug.com/922062): Replace with a call listing all identity certs.
brillo::glib::ScopedError error;
gboolean result = FALSE;
if (!org_chromium_CryptohomeInterface_tpm_is_attestation_enrolled(
proxy.gproxy(), &result, &brillo::Resetter(&error).lvalue())) {
printf("TpmIsAttestationEnrolled call failed: %s.\n", error->message);
} else {
printf("Attestation Enrolled: %s\n", (result ? "true" : "false"));
}
} else if (!strcmp(switches::kActions
[switches::ACTION_TPM_ATTESTATION_START_ENROLL],
action.c_str())) {
brillo::glib::ScopedError error;
std::string response_data;
if (!cl->HasSwitch(switches::kAsyncSwitch)) {
brillo::glib::ScopedArray data;
if (!org_chromium_CryptohomeInterface_tpm_attestation_create_enroll_request( // NOLINT
proxy.gproxy(), pca_type, &brillo::Resetter(&data).lvalue(),
&brillo::Resetter(&error).lvalue())) {
printf("TpmAttestationCreateEnrollRequest call failed: %s.\n",
error->message);
return 1;
}
response_data = std::string(static_cast<char*>(data->data), data->len);
} else {
ClientLoop client_loop;
client_loop.Initialize(&proxy);
gint async_id = -1;
if (!org_chromium_CryptohomeInterface_async_tpm_attestation_create_enroll_request( // NOLINT
proxy.gproxy(), pca_type, &async_id,
&brillo::Resetter(&error).lvalue())) {
printf("AsyncTpmAttestationCreateEnrollRequest call failed: %s.\n",
error->message);
return 1;
} else {
client_loop.Run(async_id);
if (!client_loop.get_return_status()) {
printf("Attestation enrollment request failed.\n");
return 1;
}
response_data = client_loop.get_return_data();
}
}
base::WriteFile(GetOutputFile(cl), response_data.data(),
response_data.length());
} else if (!strcmp(switches::kActions
[switches::ACTION_TPM_ATTESTATION_FINISH_ENROLL],
action.c_str())) {
std::string contents;
if (!base::ReadFileToString(GetInputFile(cl), &contents)) {
printf("Failed to read input file.\n");
return 1;
}
brillo::glib::ScopedArray data(g_array_new(FALSE, FALSE, 1));
g_array_append_vals(data.get(), contents.data(), contents.length());
gboolean success = FALSE;
brillo::glib::ScopedError error;
if (!cl->HasSwitch(switches::kAsyncSwitch)) {
if (!org_chromium_CryptohomeInterface_tpm_attestation_enroll(
proxy.gproxy(), pca_type, data.get(), &success,
&brillo::Resetter(&error).lvalue())) {
printf("TpmAttestationEnroll call failed: %s.\n", error->message);
return 1;
}
} else {
ClientLoop client_loop;
client_loop.Initialize(&proxy);
gint async_id = -1;
if (!org_chromium_CryptohomeInterface_async_tpm_attestation_enroll(
proxy.gproxy(), pca_type, data.get(), &async_id,
&brillo::Resetter(&error).lvalue())) {
printf("AsyncTpmAttestationEnroll call failed: %s.\n", error->message);
return 1;
} else {
client_loop.Run(async_id);
success = client_loop.get_return_status();
}
}
if (!success) {
printf("Attestation enrollment failed.\n");
return 1;
}
} else if (!strcmp(
switches::kActions[switches::ACTION_TPM_ATTESTATION_ENROLL],
action.c_str())) {
brillo::glib::ScopedError error;
gboolean success = FALSE;
const bool forced = cl->HasSwitch(switches::kForceSwitch);
if (!cl->HasSwitch(switches::kAsyncSwitch)) {
brillo::glib::ScopedArray data;
if (!org_chromium_CryptohomeInterface_tpm_attestation_enroll_ex(
proxy.gproxy(), pca_type, forced, &success,
&brillo::Resetter(&error).lvalue())) {
printf("TpmAttestationEnrollEx call failed: %s.\n", error->message);
return 1;
}
} else {
ClientLoop client_loop;
client_loop.Initialize(&proxy);
gint async_id = -1;
if (!org_chromium_CryptohomeInterface_async_tpm_attestation_enroll_ex(
proxy.gproxy(), pca_type, forced, &async_id,
&brillo::Resetter(&error).lvalue())) {
printf("AsyncTpmAttestationEnrollEx call failed: %s.\n",
error->message);
return 1;
} else {
client_loop.Run(async_id);
success = client_loop.get_return_status();
}
}
if (!success) {
printf("Attestation enrollment failed.\n");
return 1;
}
} else if (!strcmp(switches::kActions
[switches::ACTION_TPM_ATTESTATION_START_CERTREQ],
action.c_str())) {
brillo::glib::ScopedError error;
std::string response_data;
cryptohome::CertificateProfile profile;
if (!GetProfile(cl, &profile)) {
return 1;
}
if (!cl->HasSwitch(switches::kAsyncSwitch)) {
brillo::glib::ScopedArray data;
if (!org_chromium_CryptohomeInterface_tpm_attestation_create_cert_request(
proxy.gproxy(), pca_type, profile, "", "",
&brillo::Resetter(&data).lvalue(),
&brillo::Resetter(&error).lvalue())) {
printf("TpmAttestationCreateCertRequest call failed: %s.\n",
error->message);
return 1;
}
response_data = std::string(static_cast<char*>(data->data), data->len);
} else {
ClientLoop client_loop;
client_loop.Initialize(&proxy);
gint async_id = -1;
if (!org_chromium_CryptohomeInterface_async_tpm_attestation_create_cert_request( // NOLINT
proxy.gproxy(), pca_type, profile, "", "", &async_id,
&brillo::Resetter(&error).lvalue())) {
printf("AsyncTpmAttestationCreateCertRequest call failed: %s.\n",
error->message);
return 1;
} else {
client_loop.Run(async_id);
if (!client_loop.get_return_status()) {
printf("Attestation certificate request failed.\n");
return 1;
}
response_data = client_loop.get_return_data();
}
}
base::WriteFile(GetOutputFile(cl), response_data.data(),
response_data.length());
} else if (!strcmp(switches::kActions
[switches::ACTION_TPM_ATTESTATION_FINISH_CERTREQ],
action.c_str())) {
std::string account_id = cl->GetSwitchValueASCII(switches::kUserSwitch);
std::string key_name = cl->GetSwitchValueASCII(switches::kAttrNameSwitch);
if (key_name.length() == 0) {
printf("No key name specified (--%s=<name>)\n",
switches::kAttrNameSwitch);
return 1;
}
std::string contents;
if (!base::ReadFileToString(GetInputFile(cl), &contents)) {
printf("Failed to read input file.\n");
return 1;
}
gboolean is_user_specific = !account_id.empty();
brillo::glib::ScopedArray data(g_array_new(FALSE, FALSE, 1));
g_array_append_vals(data.get(), contents.data(), contents.length());
gboolean success = FALSE;
brillo::glib::ScopedError error;
std::string cert_data;
if (!cl->HasSwitch(switches::kAsyncSwitch)) {
brillo::glib::ScopedArray cert;
if (!org_chromium_CryptohomeInterface_tpm_attestation_finish_cert_request(
proxy.gproxy(), data.get(), is_user_specific, account_id.c_str(),
key_name.c_str(), &brillo::Resetter(&cert).lvalue(), &success,
&brillo::Resetter(&error).lvalue())) {
printf("TpmAttestationFinishCertRequest call failed: %s.\n",
error->message);
return 1;
}
cert_data = std::string(static_cast<char*>(cert->data), cert->len);
} else {
ClientLoop client_loop;
client_loop.Initialize(&proxy);
gint async_id = -1;
if (!org_chromium_CryptohomeInterface_async_tpm_attestation_finish_cert_request( // NOLINT
proxy.gproxy(), data.get(), is_user_specific, account_id.c_str(),
key_name.c_str(), &async_id,
&brillo::Resetter(&error).lvalue())) {
printf("AsyncTpmAttestationFinishCertRequest call failed: %s.\n",
error->message);
return 1;
} else {
client_loop.Run(async_id);
success = client_loop.get_return_status();
cert_data = client_loop.get_return_data();
}
}
if (!success) {
printf("Attestation certificate request failed.\n");
return 1;
}
base::WriteFile(GetOutputFile(cl), cert_data.data(), cert_data.length());
} else if (!strcmp(switches::kActions
[switches::ACTION_TPM_ATTESTATION_GET_CERTIFICATE],
action.c_str())) {
brillo::glib::ScopedError error;
cryptohome::CertificateProfile profile;
const std::string account_id =
cl->GetSwitchValueASCII(switches::kUserSwitch);
const std::string key_name =
cl->GetSwitchValueASCII(switches::kAttrNameSwitch);
const bool forced = cl->HasSwitch(switches::kForceSwitch);
const bool shall_trigger_enrollment =
cl->HasSwitch(switches::kEnrollSwitch);
gboolean success = FALSE;
std::string cert;
if (!GetProfile(cl, &profile)) {
return 1;
}
if (!cl->HasSwitch(switches::kAsyncSwitch)) {
brillo::glib::ScopedArray data;
if (!org_chromium_CryptohomeInterface_tpm_attestation_get_certificate_ex(
proxy.gproxy(), profile, account_id.c_str(),
/*request_origin=*/"", pca_type,
/*key_type=*/1, key_name.c_str(), forced,
shall_trigger_enrollment, &brillo::Resetter(&data).lvalue(),
&success, &brillo::Resetter(&error).lvalue())) {
printf("TpmAttestationCreateCertRequest call failed: %s.\n",
error->message);
return 1;
}
cert = std::string(static_cast<char*>(data->data), data->len);
} else {
ClientLoop client_loop;
client_loop.Initialize(&proxy);
gint async_id = -1;
if (!org_chromium_CryptohomeInterface_async_tpm_attestation_get_certificate_ex( // NOLINT
proxy.gproxy(), profile, account_id.c_str(),
/*request_origin=*/"", pca_type,
/*key_type=*/1, key_name.c_str(), forced,
shall_trigger_enrollment, &async_id,
&brillo::Resetter(&error).lvalue())) {
printf("AsyncTpmAttestationCreateCertRequest call failed: %s.\n",
error->message);
return 1;
} else {
client_loop.Run(async_id);
success = client_loop.get_return_status();
cert = client_loop.get_return_data();
}
}
if (!success) {
printf("Attestation certificate request failed.\n");
return 1;
}
base::WriteFile(GetOutputFile(cl), cert.data(), cert.length());
} else if (!strcmp(switches::kActions
[switches::ACTION_TPM_ATTESTATION_KEY_STATUS],
action.c_str())) {
std::string account_id = cl->GetSwitchValueASCII(switches::kUserSwitch);
std::string key_name = cl->GetSwitchValueASCII(switches::kAttrNameSwitch);
if (key_name.length() == 0) {
printf("No key name specified (--%s=<name>)\n",
switches::kAttrNameSwitch);
return 1;
}
gboolean is_user_specific = !account_id.empty();
brillo::glib::ScopedError error;
gboolean exists = FALSE;
if (!org_chromium_CryptohomeInterface_tpm_attestation_does_key_exist(
proxy.gproxy(), is_user_specific, account_id.c_str(),
key_name.c_str(), &exists, &brillo::Resetter(&error).lvalue())) {
printf("TpmAttestationDoesKeyExist call failed: %s.\n", error->message);
return 1;
}
if (!exists) {
printf("Key does not exist.\n");
return 0;
}
gboolean success = FALSE;
brillo::glib::ScopedArray cert;
if (!org_chromium_CryptohomeInterface_tpm_attestation_get_certificate(
proxy.gproxy(), is_user_specific, account_id.c_str(),
key_name.c_str(), &brillo::Resetter(&cert).lvalue(), &success,
&brillo::Resetter(&error).lvalue())) {
printf("TpmAttestationGetCertificate call failed: %s.\n", error->message);
return 1;
}
brillo::glib::ScopedArray public_key;
if (!org_chromium_CryptohomeInterface_tpm_attestation_get_public_key(
proxy.gproxy(), is_user_specific, account_id.c_str(),
key_name.c_str(), &brillo::Resetter(&public_key).lvalue(), &success,
&brillo::Resetter(&error).lvalue())) {
printf("TpmAttestationGetPublicKey call failed: %s.\n", error->message);
return 1;
}
std::string cert_pem =
std::string(static_cast<char*>(cert->data), cert->len);
std::string public_key_hex =
base::HexEncode(public_key->data, public_key->len);
printf("Public Key:\n%s\n\nCertificate:\n%s\n", public_key_hex.c_str(),
cert_pem.c_str());
} else if (!strcmp(switches::kActions
[switches::ACTION_TPM_ATTESTATION_REGISTER_KEY],
action.c_str())) {
std::string account_id = cl->GetSwitchValueASCII(switches::kUserSwitch);
std::string key_name = cl->GetSwitchValueASCII(switches::kAttrNameSwitch);
if (key_name.length() == 0) {
printf("No key name specified (--%s=<name>)\n",
switches::kAttrNameSwitch);
return 1;
}
const gboolean is_user_specific = !account_id.empty();
ClientLoop client_loop;
client_loop.Initialize(&proxy);
gint async_id = -1;
brillo::glib::ScopedError error;
if (!org_chromium_CryptohomeInterface_tpm_attestation_register_key(
proxy.gproxy(), is_user_specific, account_id.c_str(),
key_name.c_str(), &async_id, &brillo::Resetter(&error).lvalue())) {
printf("TpmAttestationRegisterKey call failed: %s.\n", error->message);
return 1;
} else {
client_loop.Run(async_id);
gboolean result = client_loop.get_return_status();
printf("Result: %s\n", result ? "Success" : "Failure");
}
} else if (!strcmp(
switches::kActions
[switches::ACTION_TPM_ATTESTATION_ENTERPRISE_CHALLENGE],
action.c_str())) {
std::string account_id = cl->GetSwitchValueASCII(switches::kUserSwitch);
std::string key_name = cl->GetSwitchValueASCII(switches::kAttrNameSwitch);
if (key_name.length() == 0) {
printf("No key name specified (--%s=<name>)\n",
switches::kAttrNameSwitch);
return 1;
}
gboolean is_user_specific = !account_id.empty();
std::string contents;
if (!base::ReadFileToString(GetInputFile(cl), &contents)) {
printf("Failed to read input file: %s\n",
GetInputFile(cl).value().c_str());
return 1;
}
brillo::glib::ScopedArray challenge(g_array_new(FALSE, FALSE, 1));
g_array_append_vals(challenge.get(), contents.data(), contents.length());
brillo::glib::ScopedArray device_id(g_array_new(FALSE, FALSE, 1));
std::string device_id_str = "fake_device_id";
g_array_append_vals(device_id.get(), device_id_str.data(),
device_id_str.length());
brillo::glib::ScopedError error;
ClientLoop client_loop;
client_loop.Initialize(&proxy);
gint async_id = -1;
if (!org_chromium_CryptohomeInterface_tpm_attestation_sign_enterprise_va_challenge( // NOLINT
proxy.gproxy(), va_type, is_user_specific, account_id.c_str(),
key_name.c_str(), account_id.c_str(), device_id.get(), TRUE,
challenge.get(), &async_id, &brillo::Resetter(&error).lvalue())) {
printf("AsyncTpmAttestationSignEnterpriseVaChallenge call failed: %s.\n",
error->message);
return 1;
}
client_loop.Run(async_id);
if (!client_loop.get_return_status()) {
printf("Attestation challenge response failed.\n");
return 1;
}
std::string response_data = client_loop.get_return_data();
base::WriteFileDescriptor(STDOUT_FILENO, response_data.data(),
response_data.length());
} else if (!strcmp(switches::kActions
[switches::ACTION_TPM_ATTESTATION_SIMPLE_CHALLENGE],
action.c_str())) {
std::string account_id = cl->GetSwitchValueASCII(switches::kUserSwitch);
std::string key_name = cl->GetSwitchValueASCII(switches::kAttrNameSwitch);
if (key_name.length() == 0) {
printf("No key name specified (--%s=<name>)\n",
switches::kAttrNameSwitch);
return 1;
}
gboolean is_user_specific = !account_id.empty();
std::string contents = "challenge";
brillo::glib::ScopedArray challenge(g_array_new(FALSE, FALSE, 1));
g_array_append_vals(challenge.get(), contents.data(), contents.length());
brillo::glib::ScopedError error;
ClientLoop client_loop;
client_loop.Initialize(&proxy);
gint async_id = -1;
if (!org_chromium_CryptohomeInterface_tpm_attestation_sign_simple_challenge(
proxy.gproxy(), is_user_specific, account_id.c_str(),
key_name.c_str(), challenge.get(), &async_id,
&brillo::Resetter(&error).lvalue())) {
printf("AsyncTpmAttestationSignSimpleChallenge call failed: %s.\n",
error->message);
return 1;
}
client_loop.Run(async_id);
if (!client_loop.get_return_status()) {
printf("Attestation challenge response failed.\n");
return 1;
}
std::string response_data = client_loop.get_return_data();
base::WriteFileDescriptor(STDOUT_FILENO, response_data.data(),
response_data.length());
} else if (!strcmp(switches::kActions
[switches::ACTION_TPM_ATTESTATION_GET_KEY_PAYLOAD],
action.c_str())) {
std::string account_id = cl->GetSwitchValueASCII(switches::kUserSwitch);
std::string key_name = cl->GetSwitchValueASCII(switches::kAttrNameSwitch);
if (key_name.length() == 0) {
printf("No key name specified (--%s=<name>)\n",
switches::kAttrNameSwitch);
return 1;
}
brillo::glib::ScopedArray payload;
gboolean is_user_specific = !account_id.empty();
brillo::glib::ScopedError error;
gboolean success = FALSE;
if (!org_chromium_CryptohomeInterface_tpm_attestation_get_key_payload(
proxy.gproxy(), is_user_specific, account_id.c_str(),
key_name.c_str(), &brillo::Resetter(&payload).lvalue(), &success,
&brillo::Resetter(&error).lvalue())) {
printf("AsyncTpmAttestationGetKetPayload call failed: %s.\n",
error->message);
return 1;
}
if (!success) {
printf("AsyncTpmAttestationGetKetPayload operation failed.\n");
return 1;
}
base::WriteFile(GetOutputFile(cl), payload->data, payload->len);
base::WriteFileDescriptor(STDOUT_FILENO, payload->data, payload->len);
} else if (!strcmp(switches::kActions
[switches::ACTION_TPM_ATTESTATION_SET_KEY_PAYLOAD],
action.c_str())) {
std::string account_id = cl->GetSwitchValueASCII(switches::kUserSwitch);
std::string key_name = cl->GetSwitchValueASCII(switches::kAttrNameSwitch);
std::string value = cl->GetSwitchValueASCII(switches::kAttrValueSwitch);
if (key_name.length() == 0) {
printf("No key name specified (--%s=<name>)\n",
switches::kAttrNameSwitch);
return 1;
}
if (value.length() == 0) {
printf("No payload specified (--%s=<payload>)\n",
switches::kAttrValueSwitch);
return 1;
}
brillo::glib::ScopedArray payload(g_array_new(FALSE, FALSE, 1));
g_array_append_vals(payload.get(), value.data(), value.length());
gboolean is_user_specific = !account_id.empty();
brillo::glib::ScopedError error;
gboolean success = FALSE;
if (!org_chromium_CryptohomeInterface_tpm_attestation_set_key_payload(
proxy.gproxy(), is_user_specific, account_id.c_str(),
key_name.c_str(), payload.get(), &success,
&brillo::Resetter(&error).lvalue())) {
printf("AsyncTpmAttestationSetKetPayload call failed: %s.\n",
error->message);
return 1;
}
if (!success) {
printf("AsyncTpmAttestationSetKetPayload operation failed.\n");
return 1;
}
} else if (!strcmp(switches::kActions
[switches::ACTION_TPM_ATTESTATION_DELETE_KEYS],
action.c_str())) {
std::string account_id = cl->GetSwitchValueASCII(switches::kUserSwitch);
std::string key_prefix =
cl->GetSwitchValueASCII(switches::kAttrPrefixSwitch);
if (key_prefix.empty()) {
printf("No key prefix specified (--%s=<prefix>)\n",
switches::kAttrPrefixSwitch);
return 1;
}
gboolean is_user_specific = !account_id.empty();
brillo::glib::ScopedError error;
gboolean success = FALSE;
if (!org_chromium_CryptohomeInterface_tpm_attestation_delete_keys(
proxy.gproxy(), is_user_specific, account_id.c_str(),
key_prefix.c_str(), &success, &brillo::Resetter(&error).lvalue())) {
printf("AsyncTpmAttestationDeleteKeys call failed: %s.\n",
error->message);
return 1;
}
if (!success) {
printf("Delete operation failed.\n");
return 1;
}
} else if (!strcmp(switches::kActions
[switches::ACTION_TPM_ATTESTATION_DELETE_KEY],
action.c_str())) {
std::string account_id = cl->GetSwitchValueASCII(switches::kUserSwitch);
std::string key_name = cl->GetSwitchValueASCII(switches::kAttrNameSwitch);
if (key_name.empty()) {
printf("No key name specified (--%s=<name>)\n",
switches::kAttrNameSwitch);
return 1;
}
gboolean is_user_specific = !account_id.empty();
brillo::glib::ScopedError error;
gboolean success = FALSE;
if (!org_chromium_CryptohomeInterface_tpm_attestation_delete_key(
proxy.gproxy(), is_user_specific, account_id.c_str(),
key_name.c_str(), &success, &brillo::Resetter(&error).lvalue())) {
printf("AsyncTpmAttestationDeleteKeys call failed: %s.\n",
error->message);
return 1;
}
if (!success) {
printf("Delete operation failed.\n");
return 1;
}
} else if (!strcmp(
switches::kActions[switches::ACTION_TPM_ATTESTATION_GET_EK],
action.c_str())) {
if (cl->HasSwitch(switches::kProtobufSwitch)) {
// Get the EK info as a protobuf.
cryptohome::GetEndorsementInfoRequest request;
cryptohome::BaseReply reply;
if (!MakeProtoDBusCall("GetEndorsementInfo",
DBUS_METHOD(get_endorsement_info),
DBUS_METHOD(get_endorsement_info_async), cl,
&proxy, request, &reply, true /* print_reply */)) {
return 1;
}
if (!reply.HasExtension(cryptohome::GetEndorsementInfoReply::reply)) {
printf("GetEndorsementInfoReply missing.\n");
return 1;
}
printf("GetEndorsementInfo (protobuf) success.\n");
} else {
brillo::glib::ScopedError error;
gboolean success = FALSE;
gchar* ek_info = NULL;
if (!org_chromium_CryptohomeInterface_tpm_attestation_get_ek(
proxy.gproxy(), &ek_info, &success,
&brillo::Resetter(&error).lvalue())) {
printf("AsyncTpmAttestationGetEK call failed: %s.\n", error->message);
return 1;
}
if (!success) {
printf("Failed to get EK.\n");
g_free(ek_info);
return 1;
}
printf("%s\n", ek_info);
g_free(ek_info);
}
} else if (!strcmp(switches::kActions
[switches::ACTION_TPM_ATTESTATION_RESET_IDENTITY],
action.c_str())) {
brillo::glib::ScopedError error;
gboolean success = FALSE;
std::string token = cl->GetSwitchValueASCII(switches::kPasswordSwitch);
brillo::glib::ScopedArray reset_request;
if (!org_chromium_CryptohomeInterface_tpm_attestation_reset_identity(
proxy.gproxy(), token.c_str(),
&brillo::Resetter(&reset_request).lvalue(), &success,
&brillo::Resetter(&error).lvalue())) {
printf("TpmAttestationResetIdentity call failed: %s.\n", error->message);
return 1;
}
if (!success) {
printf("Failed to get identity reset request.\n");
return 1;
}
base::WriteFile(GetOutputFile(cl), reset_request->data, reset_request->len);
} else if (!strcmp(
switches::kActions
[switches::ACTION_TPM_ATTESTATION_RESET_IDENTITY_RESULT],
action.c_str())) {
std::string contents;
if (!base::ReadFileToString(GetInputFile(cl), &contents)) {
printf("Failed to read input file: %s\n",
GetInputFile(cl).value().c_str());
return 1;
}
cryptohome::AttestationResetResponse response;
if (!response.ParseFromString(contents)) {
printf("Failed to parse response.\n");
return 1;
}
switch (response.status()) {
case cryptohome::OK:
printf("Identity reset successful.\n");
break;
case cryptohome::SERVER_ERROR:
printf("Identity reset server error: %s\n", response.detail().c_str());
break;
case cryptohome::BAD_REQUEST:
printf("Identity reset data error: %s\n", response.detail().c_str());
break;
case cryptohome::REJECT:
printf("Identity reset request denied: %s\n",
response.detail().c_str());
break;
case cryptohome::QUOTA_LIMIT_EXCEEDED:
printf("Identity reset quota exceeded: %s\n",
response.detail().c_str());
break;
default:
printf("Identity reset unknown error: %s\n", response.detail().c_str());
}
} else if (!strcmp(switches::kActions[switches::ACTION_SIGN_LOCKBOX],
action.c_str())) {
std::string data;
if (!base::ReadFileToString(GetInputFile(cl), &data)) {
printf("Failed to read input file: %s\n",
GetInputFile(cl).value().c_str());
return 1;
}
cryptohome::SignBootLockboxRequest request;
request.set_data(data);
cryptohome::BaseReply reply;
if (!MakeProtoDBusCall("SignBootLockbox", DBUS_METHOD(sign_boot_lockbox),
DBUS_METHOD(sign_boot_lockbox_async), cl, &proxy,
request, &reply, true /* print_reply */)) {
return 1;
}
if (!reply.HasExtension(cryptohome::SignBootLockboxReply::reply)) {
printf("SignBootLockboxReply missing.\n");
return 1;
}
std::string signature =
reply.GetExtension(cryptohome::SignBootLockboxReply::reply).signature();
base::WriteFile(GetOutputFile(cl).AddExtension("signature"),
signature.data(), signature.size());
printf("SignBootLockbox success.\n");
} else if (!strcmp(switches::kActions[switches::ACTION_VERIFY_LOCKBOX],
action.c_str())) {
std::string data;
if (!base::ReadFileToString(GetInputFile(cl), &data)) {
printf("Failed to read input file: %s\n",
GetInputFile(cl).value().c_str());
return 1;
}
std::string signature;
FilePath signature_file = GetInputFile(cl).AddExtension("signature");
if (!base::ReadFileToString(signature_file, &signature)) {
printf("Failed to read input file: %s\n", signature_file.value().c_str());
return 1;
}
cryptohome::VerifyBootLockboxRequest request;
request.set_data(data);
request.set_signature(signature);
cryptohome::BaseReply reply;
if (!MakeProtoDBusCall("VerifyBootLockbox",
DBUS_METHOD(verify_boot_lockbox),
DBUS_METHOD(verify_boot_lockbox_async), cl, &proxy,
request, &reply, true /* print_reply */)) {
return 1;
}
printf("VerifyBootLockbox success.\n");
} else if (!strcmp(switches::kActions[switches::ACTION_FINALIZE_LOCKBOX],
action.c_str())) {
cryptohome::FinalizeBootLockboxRequest request;
cryptohome::BaseReply reply;
if (!MakeProtoDBusCall("FinalizeBootLockbox",
DBUS_METHOD(finalize_boot_lockbox),
DBUS_METHOD(finalize_boot_lockbox_async), cl, &proxy,
request, &reply, true /* print_reply */)) {
return 1;
}
printf("FinalizeBootLockbox success.\n");
} else if (!strcmp(switches::kActions[switches::ACTION_GET_BOOT_ATTRIBUTE],
action.c_str())) {
std::string name;
if (!GetAttrName(cl, &name)) {
printf("No attribute name specified.\n");
return 1;
}
cryptohome::GetBootAttributeRequest request;
request.set_name(name);
cryptohome::BaseReply reply;
if (!MakeProtoDBusCall("GetBootAttribute", DBUS_METHOD(get_boot_attribute),
DBUS_METHOD(get_boot_attribute_async), cl, &proxy,
request, &reply, true /* print_reply */)) {
return 1;
}
if (!reply.HasExtension(cryptohome::GetBootAttributeReply::reply)) {
printf("GetBootAttributeReply missing.\n");
return 1;
}
std::string value =
reply.GetExtension(cryptohome::GetBootAttributeReply::reply).value();
printf("%s\n", value.c_str());
} else if (!strcmp(switches::kActions[switches::ACTION_SET_BOOT_ATTRIBUTE],
action.c_str())) {
std::string name;
if (!GetAttrName(cl, &name)) {
printf("No attribute name specified.\n");
return 1;
}
std::string value;
if (!GetAttrValue(cl, &value)) {
printf("No attribute value specified.\n");
return 1;
}
cryptohome::SetBootAttributeRequest request;
request.set_name(name);
request.set_value(value);
cryptohome::BaseReply reply;
if (!MakeProtoDBusCall("SetBootAttribute", DBUS_METHOD(set_boot_attribute),
DBUS_METHOD(set_boot_attribute_async), cl, &proxy,
request, &reply, true /* print_reply */)) {
return 1;
}
printf("SetBootAttribute success.\n");
} else if (!strcmp(switches::kActions
[switches::ACTION_FLUSH_AND_SIGN_BOOT_ATTRIBUTES],
action.c_str())) {
cryptohome::FlushAndSignBootAttributesRequest request;
cryptohome::BaseReply reply;
if (!MakeProtoDBusCall("FlushAndSignBootAttributes",
DBUS_METHOD(flush_and_sign_boot_attributes),
DBUS_METHOD(flush_and_sign_boot_attributes_async),
cl, &proxy, request, &reply,
true /* print_reply */)) {
return 1;
}
printf("FlushAndSignBootAttributes success.\n");
} else if (!strcmp(switches::kActions[switches::ACTION_GET_LOGIN_STATUS],
action.c_str())) {
cryptohome::GetLoginStatusRequest request;
cryptohome::BaseReply reply;
if (!MakeProtoDBusCall("GetLoginStatus", DBUS_METHOD(get_login_status),
DBUS_METHOD(get_login_status_async), cl, &proxy,
request, &reply, true /* print_reply */)) {
return 1;
}
if (!reply.HasExtension(cryptohome::GetLoginStatusReply::reply)) {
printf("GetLoginStatusReply missing.\n");
return 1;
}
printf("GetLoginStatus success.\n");
} else if (!strcmp(switches::kActions[switches::ACTION_INITIALIZE_CAST_KEY],
action.c_str())) {
cryptohome::InitializeCastKeyRequest request;
cryptohome::BaseReply reply;
if (!MakeProtoDBusCall("InitializeCastKey",
DBUS_METHOD(initialize_cast_key),
DBUS_METHOD(initialize_cast_key_async), cl, &proxy,
request, &reply, true /* print_reply */)) {
return 1;
}
printf("InitializeCastKey success.\n");
} else if (!strcmp(switches::kActions
[switches::ACTION_GET_FIRMWARE_MANAGEMENT_PARAMETERS],
action.c_str())) {
cryptohome::GetFirmwareManagementParametersRequest request;
cryptohome::BaseReply reply;
if (!MakeProtoDBusCall(
cryptohome::kCryptohomeGetFirmwareManagementParameters,
DBUS_METHOD(get_firmware_management_parameters),
DBUS_METHOD(get_firmware_management_parameters_async), cl, &proxy,
request, &reply, true /* print_reply */)) {
return 1;
}
if (!reply.HasExtension(
cryptohome::GetFirmwareManagementParametersReply::reply)) {
printf("GetFirmwareManagementParametersReply missing.\n");
return 1;
}
cryptohome::GetFirmwareManagementParametersReply get_fwmp_reply =
reply.GetExtension(
cryptohome::GetFirmwareManagementParametersReply::reply);
printf("flags=0x%08x\n", get_fwmp_reply.flags());
brillo::Blob hash =
brillo::BlobFromString(get_fwmp_reply.developer_key_hash());
printf("hash=%s\n", cryptohome::CryptoLib::BlobToHex(hash).c_str());
printf("GetFirmwareManagementParameters success.\n");
} else if (!strcmp(switches::kActions
[switches::ACTION_SET_FIRMWARE_MANAGEMENT_PARAMETERS],
action.c_str())) {
cryptohome::SetFirmwareManagementParametersRequest request;
cryptohome::BaseReply reply;
if (cl->HasSwitch(switches::kFlagsSwitch)) {
std::string flags_str = cl->GetSwitchValueASCII(switches::kFlagsSwitch);
char* end = NULL;
int32_t flags = strtol(flags_str.c_str(), &end, 0);
if (end && *end != '\0') {
printf("Bad flags value.\n");
return 1;
}
request.set_flags(flags);
} else {
printf("Use --flags (and optionally --developer_key_hash).\n");
return 1;
}
if (cl->HasSwitch(switches::kDevKeyHashSwitch)) {
std::string hash_str =
cl->GetSwitchValueASCII(switches::kDevKeyHashSwitch);
brillo::Blob hash;
if (!base::HexStringToBytes(hash_str, &hash)) {
printf("Bad hash value.\n");
return 1;
}
if (hash.size() != SHA256_DIGEST_LENGTH) {
printf("Bad hash size.\n");
return 1;
}
request.set_developer_key_hash(brillo::BlobToString(hash));
}
if (!MakeProtoDBusCall(
cryptohome::kCryptohomeSetFirmwareManagementParameters,
DBUS_METHOD(set_firmware_management_parameters),
DBUS_METHOD(set_firmware_management_parameters_async), cl, &proxy,
request, &reply, true /* print_reply */)) {
return 1;
}
printf("SetFirmwareManagementParameters success.\n");
} else if (!strcmp(
switches::kActions
[switches::ACTION_REMOVE_FIRMWARE_MANAGEMENT_PARAMETERS],
action.c_str())) {
cryptohome::RemoveFirmwareManagementParametersRequest request;
cryptohome::BaseReply reply;
if (!MakeProtoDBusCall(
cryptohome::kCryptohomeRemoveFirmwareManagementParameters,
DBUS_METHOD(remove_firmware_management_parameters),
DBUS_METHOD(remove_firmware_management_parameters_async), cl,
&proxy, request, &reply, true /* print_reply */)) {
return 1;
}
printf("RemoveFirmwareManagementParameters success.\n");
} else if (!strcmp(switches::kActions[switches::ACTION_MIGRATE_TO_DIRCRYPTO],
action.c_str())) {
cryptohome::AccountIdentifier id;
if (!BuildAccountId(cl, &id))
return 1;
brillo::glib::ScopedArray account_ary(GArrayFromProtoBuf(id));
if (!account_ary.get())
return 1;
cryptohome::MigrateToDircryptoRequest request;
request.set_minimal_migration(cl->HasSwitch(switches::kMinimalMigration));
brillo::glib::ScopedArray request_ary(GArrayFromProtoBuf(request));
if (!request_ary.get())
return 1;
brillo::glib::ScopedError error;
if (!org_chromium_CryptohomeInterface_migrate_to_dircrypto(
proxy.gproxy(), account_ary.get(), request_ary.get(),
&brillo::Resetter(&error).lvalue())) {
printf("MigrateToDircrypto call failed: %s\n", error->message);
return 1;
}
printf("MigrateToDircrypto call succeeded.\n");
} else if (!strcmp(
switches::kActions[switches::ACTION_NEEDS_DIRCRYPTO_MIGRATION],
action.c_str())) {
cryptohome::AccountIdentifier id;
if (!BuildAccountId(cl, &id)) {
printf("No account_id specified.\n");
return 1;
}
brillo::glib::ScopedArray account_ary(GArrayFromProtoBuf(id));
if (!account_ary.get())
return 1;
brillo::glib::ScopedError error;
gboolean needs_migration = false;
if (!org_chromium_CryptohomeInterface_needs_dircrypto_migration(
proxy.gproxy(), account_ary.get(), &needs_migration,
&brillo::Resetter(&error).lvalue())) {
printf("NeedsDirCryptoMigration call failed: %s.\n", error->message);
return 1;
}
if (needs_migration)
printf("Yes\n");
else
printf("No\n");
} else if (!strcmp(switches::kActions[switches::ACTION_GET_ENROLLMENT_ID],
action.c_str())) {
gboolean success = FALSE;
brillo::glib::ScopedArray enrollment_id;
brillo::glib::ScopedError error;
if (!org_chromium_CryptohomeInterface_tpm_attestation_get_enrollment_id(
proxy.gproxy(), cl->HasSwitch(switches::kIgnoreCache),
&brillo::Resetter(&enrollment_id).lvalue(), &success,
&brillo::Resetter(&error).lvalue())) {
printf("GetEnrollmentId call failed: %s.\n", error->message);
return 1;
}
std::string eid_str = base::ToLowerASCII(
base::HexEncode(enrollment_id->data, enrollment_id->len));
printf("%s\n", eid_str.c_str());
} else if (!strcmp(switches::kActions
[switches::ACTION_GET_SUPPORTED_KEY_POLICIES],
action.c_str())) {
cryptohome::GetSupportedKeyPoliciesRequest request;
cryptohome::BaseReply reply;
if (!MakeProtoDBusCall(cryptohome::kCryptohomeGetSupportedKeyPolicies,
DBUS_METHOD(get_supported_key_policies),
DBUS_METHOD(get_supported_key_policies_async), cl,
&proxy, request, &reply, true /* print_reply */)) {
return 1;
}
if (!reply.HasExtension(cryptohome::GetSupportedKeyPoliciesReply::reply)) {
printf("GetSupportedKeyPoliciesReply missing.\n");
return 1;
}
printf("GetSupportedKeyPolicies success.\n");
} else if (!strcmp(
switches::kActions[switches::ACTION_GET_ACCOUNT_DISK_USAGE],
action.c_str())) {
cryptohome::AccountIdentifier id;
if (!BuildAccountId(cl, &id))
return 1;
brillo::glib::ScopedArray id_ary(GArrayFromProtoBuf(id));
brillo::glib::ScopedError error;
GArray* out_reply = NULL;
if (!org_chromium_CryptohomeInterface_get_account_disk_usage(
proxy.gproxy(), id_ary.get(), &out_reply,
&brillo::Resetter(&error).lvalue())) {
printf("GetAccountDiskUsage call failed: %s", error->message);
return 1;
}
cryptohome::BaseReply reply;
ParseBaseReply(out_reply, &reply, true /* print_reply */);
if (reply.has_error()) {
printf("GetAccountDiskUsage failed with %d.\n", reply.error());
return reply.error();
}
if (!reply.HasExtension(cryptohome::GetAccountDiskUsageReply::reply)) {
printf("GetAccountDiskUsageReply missing.\n");
return 1;
}
auto ext = reply.GetExtension(cryptohome::GetAccountDiskUsageReply::reply);
printf("Account Disk Usage in bytes: %" PRId64 "\n", ext.size());
return 0;
} else if (!strcmp(
switches::kActions
[switches::ACTION_LOCK_TO_SINGLE_USER_MOUNT_UNTIL_REBOOT],
action.c_str())) {
cryptohome::AccountIdentifier id;
if (!BuildAccountId(cl, &id))
return 1;
cryptohome::LockToSingleUserMountUntilRebootRequest request;
request.mutable_account_id()->CopyFrom(id);
brillo::glib::ScopedArray req_ary(GArrayFromProtoBuf(request));
cryptohome::BaseReply reply;
brillo::glib::ScopedError error;
GArray* out_reply = NULL;
if (!org_chromium_CryptohomeInterface_lock_to_single_user_mount_until_reboot( // NOLINT
proxy.gproxy(), req_ary.get(), &out_reply,
&brillo::Resetter(&error).lvalue())) {
printf("LockToSingleUserMountUntilReboot call failed: %s",
error->message);
return 1;
}
ParseBaseReply(out_reply, &reply, true /* print_reply */);
printf("Login disabled.\n");
} else if (!strcmp(switches::kActions[switches::ACTION_GET_RSU_DEVICE_ID],
action.c_str())) {
cryptohome::GetRsuDeviceIdRequest request;
cryptohome::BaseReply reply;
if (!MakeProtoDBusCall("GetRsuDeviceId", DBUS_METHOD(get_rsu_device_id),
DBUS_METHOD(get_rsu_device_id_async), cl, &proxy,
request, &reply, true /* print_reply */)) {
return 1;
}
if (!reply.HasExtension(cryptohome::GetRsuDeviceIdReply::reply)) {
printf("GetRsuDeviceIdReply missing.\n");
return 1;
}
} else if (!strcmp(switches::kActions[switches::ACTION_CHECK_HEALTH],
action.c_str())) {
cryptohome::CheckHealthRequest request;
cryptohome::BaseReply reply;
if (!MakeProtoDBusCall("CheckHealth", DBUS_METHOD(check_health),
DBUS_METHOD(check_health_async), cl, &proxy, request,
&reply, true /* print_reply */)) {
return 1;
}
if (!reply.HasExtension(cryptohome::CheckHealthReply::reply)) {
printf("CheckHealthReply missing.\n");
return 1;
}
} else if (!strcmp(switches::kActions[switches::ACTION_START_AUTH_SESSION],
action.c_str())) {
cryptohome::AccountIdentifier id;
if (!BuildAccountId(cl, &id))
return 1;
cryptohome::StartAuthSessionRequest req;
brillo::glib::ScopedArray account_ary(GArrayFromProtoBuf(id));
brillo::glib::ScopedArray req_ary(GArrayFromProtoBuf(req));
if (!account_ary.get() || !req_ary.get())
return 1;
cryptohome::BaseReply reply;
brillo::glib::ScopedError error;
GArray* out_reply = NULL;
VLOG(1) << "Attempt to start auth session.";
if (!org_chromium_CryptohomeInterface_start_auth_session(
proxy.gproxy(), account_ary.get(), req_ary.get(), &out_reply,
&brillo::Resetter(&error).lvalue())) {
return 1;
}
// TODO(crbug.com/1152474): Print Auth Session token here for the developer
// to easily access token.
ParseBaseReply(out_reply, &reply, true /* print_reply */);
if (reply.has_error()) {
printf("Auth session failed to start.\n");
return reply.error();
}
printf("Auth session start succeeded.\n");
} else {
printf("Unknown action or no action given. Available actions:\n");
for (int i = 0; switches::kActions[i]; i++)
printf(" --action=%s\n", switches::kActions[i]);
}
return 0;
} // NOLINT(readability/fn_size)