blob: 1a503e0a1b8c0654feee2518f486b0c45929a2dc [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/homedirs.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/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",
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,
};
static const char kUserSwitch[] = "user";
static const char kPasswordSwitch[] = "password";
static const char kFingerprintSwitch[] = "fingerprint";
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 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());
// 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_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::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_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;
}
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());
}
if (serialized.has_timestamp_file_exists()) {
FilePath timestamp_path = vault_path.AddExtension("timestamp");
brillo::Blob tcontents;
if (!platform.ReadFile(timestamp_path, &tcontents)) {
printf("Couldn't load timestamp contents: %s.\n",
timestamp_path.value().c_str());
}
cryptohome::Timestamp timestamp;
if (!timestamp.ParseFromArray(tcontents.data(), tcontents.size())) {
printf("Couldn't parse timestamp contents: %s.\n",
timestamp_path.value().c_str());
}
const base::Time last_activity =
base::Time::FromInternalValue(timestamp.timestamp());
printf(" Last activity (days ago):\n");
printf(" %d\n", (base::Time::Now() - last_activity).InDays());
} else 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_timestamp_file_exists()) {
FilePath timestamp_path = next_path.AddExtension("timestamp");
brillo::Blob tcontents;
if (!platform.ReadFile(timestamp_path, &tcontents)) {
printf("Couldn't load timestamp contents: %s.\n",
timestamp_path.value().c_str());
}
cryptohome::Timestamp timestamp;
if (!timestamp.ParseFromArray(tcontents.data(), tcontents.size())) {
printf("Couldn't parse timestamp contents: %s.\n",
timestamp_path.value().c_str());
}
const base::Time last_activity =
base::Time::FromInternalValue(timestamp.timestamp());
if (last_activity > max_activity) {
max_activity = last_activity;
}
} else 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_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(
kWaitOwnershipTimeoutInSeconds);
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