blob: 812b559ff5e6fa302a1a5c0b35bc3ddd131ef65d [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 <base/command_line.h>
#include <base/files/file_path.h>
#include <base/logging.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.h"
#include "cryptohome/crypto.h"
#include "cryptohome/cryptolib.h"
#include "cryptohome/mount.h"
#include "cryptohome/obfuscated_username.h"
#include "cryptohome/pkcs11_init.h"
#include "cryptohome/platform.h"
#include "attestation.pb.h" // NOLINT(build/include)
#include "bindings/cryptohome.dbusclient.h"
#include "key.pb.h" // NOLINT(build/include)
#include "rpc.pb.h" // NOLINT(build/include)
#include "signed_secret.pb.h" // NOLINT(build/include)
#include "vault_keyset.pb.h" // NOLINT(build/include)
using base::FilePath;
using base::StringPrintf;
using brillo::SecureBlob;
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;
} // namespace
namespace switches {
static const char kSyslogSwitch[] = "syslog";
static const char kAttestationServerSwitch[] = "attestation-server";
static struct {
const char *name;
const cryptohome::Attestation::PCAType pca_type;
} kAttestationServers[] = {
{ "default", cryptohome::Attestation::kDefaultPCA },
{ "test", cryptohome::Attestation::kTestPCA },
{ nullptr, cryptohome::Attestation::kMaxPCAType }
};
static const char kVaServerSwitch[] = "va-server";
static struct {
const char *name;
const cryptohome::Attestation::VAType va_type;
} kVaServers[] = {
{ "default", cryptohome::Attestation::kDefaultVA },
{ "test", cryptohome::Attestation::kTestVA },
{ nullptr, cryptohome::Attestation::kMaxVAType }
};
static const char kActionSwitch[] = "action";
static const char* kActions[] = {"mount_ex",
"mount_guest",
"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",
"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",
"pkcs11_token_status",
"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_start_cert_request",
"tpm_attestation_finish_cert_request",
"tpm_attestation_key_status",
"tpm_attestation_register_key",
"tpm_attestation_enterprise_challenge",
"tpm_attestation_delete",
"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",
"lock_to_single_user_mount_until_reboot",
"get_rsu_device_id",
NULL};
enum ActionEnum {
ACTION_MOUNT_EX,
ACTION_MOUNT_GUEST,
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_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_PKCS11_TOKEN_STATUS,
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_START_CERTREQ,
ACTION_TPM_ATTESTATION_FINISH_CERTREQ,
ACTION_TPM_ATTESTATION_KEY_STATUS,
ACTION_TPM_ATTESTATION_REGISTER_KEY,
ACTION_TPM_ATTESTATION_ENTERPRISE_CHALLENGE,
ACTION_TPM_ATTESTATION_DELETE,
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_LOCK_TO_SINGLE_USER_MOUNT_UNTIL_REBOOT,
ACTION_GET_RSU_DEVICE_ID,
};
static const char kUserSwitch[] = "user";
static const char kPasswordSwitch[] = "password";
static const char kKeyLabelSwitch[] = "key_label";
static const char kKeyRevisionSwitch[] = "key_revision";
static const char kHmacSigningKeySwitch[] = "hmac_signing_key";
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 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";
} // 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, arraysize(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 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, arraysize(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) {
guint len = pb.ByteSize();
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_;
};
class TpmWaitLoop {
public:
TpmWaitLoop()
: loop_(NULL) { }
virtual ~TpmWaitLoop() {
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_BOOLEAN,
G_TYPE_BOOLEAN,
G_TYPE_BOOLEAN,
G_TYPE_INVALID);
dbus_g_proxy_add_signal(proxy->gproxy(), "TpmInitStatus",
G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
G_TYPE_INVALID);
dbus_g_proxy_connect_signal(proxy->gproxy(), "TpmInitStatus",
G_CALLBACK(TpmWaitLoop::CallbackThunk),
this, NULL);
loop_ = g_main_loop_new(NULL, TRUE);
}
void Run() {
g_main_loop_run(loop_);
}
private:
static void CallbackThunk(DBusGProxy* proxy, bool ready, bool is_owned,
bool took_ownership, gpointer userdata) {
printf("TPM ready: %s\n", (ready ? "true" : "false"));
printf("TPM owned: %s\n", (is_owned ? "true" : "false"));
printf("TPM took_ownership: %s\n", (took_ownership ? "true" : "false"));
g_main_loop_quit(reinterpret_cast<TpmWaitLoop*>(userdata)->loop_);
}
GMainLoop *loop_;
};
bool WaitForTPMOwnership(brillo::dbus::Proxy* proxy) {
TpmWaitLoop client_loop;
client_loop.Initialize(proxy);
gboolean result;
brillo::glib::ScopedError error;
if (!org_chromium_CryptohomeInterface_tpm_is_being_owned(
proxy->gproxy(), &result, &brillo::Resetter(&error).lvalue())) {
printf("TpmIsBeingOwned call failed: %s.\n", error->message);
}
if (result) {
printf("Waiting for TPM to be owned...\n");
client_loop.Run();
} else {
printf("TPM is not currently being owned.\n");
}
return result;
}
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 cryptohome::Attestation::kDefaultPCA:
return "the default PCA";
case cryptohome::Attestation::kTestPCA:
return "the test PCA";
default: {
std::ostringstream stream;
stream << "PCA " << 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);
cryptohome::Attestation::PCAType pca_type =
cryptohome::Attestation::kMaxPCAType;
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].pca_type;
break;
}
}
if (pca_type == cryptohome::Attestation::kMaxPCAType) {
printf("Invalid attestation server: %s\n", server.c_str());
return 1;
}
} else {
pca_type = cryptohome::Attestation::kDefaultPCA;
}
cryptohome::Attestation::VAType va_type = cryptohome::Attestation::kMaxVAType;
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 == cryptohome::Attestation::kMaxVAType) {
printf("Invalid Verified Access server: %s\n", va_server.c_str());
return 1;
}
} else {
va_type = cryptohome::Attestation::kDefaultVA;
}
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());
// The proto definition defaults all privileges to true but we only want
// mount, add, remove, and update.
key->mutable_data()->mutable_privileges()->set_authorized_update(false);
} 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_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 (!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::kHmacSigningKeySwitch)) {
cryptohome::KeyAuthorizationData* auth_data =
data->add_authorization_data();
auth_data->set_type(
cryptohome::KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_HMACSHA256);
cryptohome::KeyAuthorizationSecret* auth_secret =
auth_data->add_secrets();
auth_secret->mutable_usage()->set_sign(true);
auth_secret->set_symmetric_key(cl->GetSwitchValueASCII(
switches::kHmacSigningKeySwitch));
LOG(INFO) << "Adding restricted key";
cryptohome::KeyPrivileges* privs = data->mutable_privileges();
privs->set_mount(true);
privs->set_authorized_update(true);
privs->set_update(false);
privs->set_add(false);
privs->set_remove(false);
}
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_UPDATE_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::UpdateKeyRequest key_req;
cryptohome::Key* key = key_req.mutable_changes();
key->set_secret(new_password);
cryptohome::KeyData* data = key->mutable_data();
if (cl->HasSwitch(switches::kNewKeyLabelSwitch))
data->set_label(cl->GetSwitchValueASCII(switches::kNewKeyLabelSwitch));
if (cl->HasSwitch(switches::kKeyRevisionSwitch)) {
int int_value = 0;
if (!base::StringToInt(
cl->GetSwitchValueASCII(switches::kKeyRevisionSwitch), &int_value))
LOG(FATAL) << "Cannot parse --key_revision";
data->set_revision(int_value);
}
if (cl->HasSwitch(switches::kHmacSigningKeySwitch)) {
ac::chrome::managedaccounts::account::Secret new_secret;
new_secret.set_revision(data->revision());
new_secret.set_secret(key->secret());
std::string changes_str;
if (!new_secret.SerializeToString(&changes_str)) {
LOG(FATAL) << "Failed to serialize Secret";
}
brillo::SecureBlob hmac_key(
cl->GetSwitchValueASCII(switches::kHmacSigningKeySwitch));
brillo::SecureBlob hmac_data(changes_str.begin(), changes_str.end());
SecureBlob hmac = cryptohome::CryptoLib::HmacSha256(hmac_key, hmac_data);
key_req.set_authorization_signature(hmac.to_string());
}
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_update_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_update_key_ex(proxy.gproxy(),
account_ary.get(),
auth_ary.get(),
req_ary.get(),
&out_reply,
&brillo::Resetter(&error).lvalue())) {
printf("Failed to call UpdateKeyEx!\n");
return 1;
}
ParseBaseReply(out_reply, &reply, true /* print_reply */);
}
if (reply.has_error()) {
printf("Key update failed.\n");
return reply.error();
}
printf("Key updated.\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;
}
printf("%s\n",
cryptohome::BuildObfuscatedUsername(account_id, GetSystemSalt(proxy))
.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(cryptohome::BuildObfuscatedUsername(
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());
}
if (serialized.has_last_activity_timestamp()) {
const base::Time last_activity =
base::Time::FromInternalValue(serialized.last_activity_timestamp());
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;
}
if (keyset.has_last_activity_timestamp()) {
const base::Time last_activity =
base::Time::FromInternalValue(keyset.last_activity_timestamp());
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_TPM_WAIT_OWNERSHIP],
action.c_str())) {
return !WaitForTPMOwnership(&proxy);
} else if (!strcmp(
switches::kActions[switches::ACTION_PKCS11_TOKEN_STATUS],
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 {
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_START_CERTREQ],
action.c_str())) {
brillo::glib::ScopedError error;
std::string response_data;
std::string profile_str = cl->GetSwitchValueASCII(switches::kProfileSwitch);
cryptohome::CertificateProfile profile;
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 {
printf("Unknown certificate profile: %s.\n", profile_str.c_str());
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_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;
}
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(),
true,
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(),
"cros@crosdmsregtest.com",
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_DELETE],
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 success = FALSE;
if (!org_chromium_CryptohomeInterface_tpm_attestation_delete_keys(
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;
}