blob: f149b33192bfb18cbf9227ba12af157e2e39b4b9 [file] [log] [blame]
// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include <string>
#include <base/bind.h>
#include <base/callback.h>
#include <base/files/file_path.h>
#include <base/logging.h>
#include <brillo/daemons/daemon.h>
#include <brillo/flag_helper.h>
#include <brillo/syslog_logging.h>
#include <dbus/bus.h>
#include <policy/device_policy.h>
#include <policy/libpolicy.h>
#include <sysexits.h>
#include "bindings/chrome_device_policy.pb.h"
#include "power_manager-client/power_manager/dbus-proxies.h"
#include "u2fd/tpm_vendor_cmd.h"
#include "u2fd/u2fhid.h"
#include "u2fd/uhid_device.h"
#ifndef VCSID
#define VCSID "<unknown>"
#endif
namespace {
constexpr char kDeviceName[] = "Integrated U2F";
constexpr uint32_t kDefaultVendorId = 0x18d1;
constexpr uint32_t kDefaultProductId = 0x502c;
namespace em = enterprise_management;
enum class U2fMode : uint8_t {
kUnset = em::DeviceSecondFactorAuthenticationProto_U2fMode_UNSET,
kDisabled = em::DeviceSecondFactorAuthenticationProto_U2fMode_DISABLED,
kU2f = em::DeviceSecondFactorAuthenticationProto_U2fMode_U2F,
kU2fExtended = em::DeviceSecondFactorAuthenticationProto_U2fMode_U2F_EXTENDED,
};
U2fMode ReadU2fPolicy() {
policy::PolicyProvider policy_provider;
// No available policy.
if (!policy_provider.Reload())
return U2fMode::kUnset;
int mode = 0;
const policy::DevicePolicy* policy = &policy_provider.GetDevicePolicy();
if (!policy->GetSecondFactorAuthenticationMode(&mode))
return U2fMode::kUnset;
return static_cast<U2fMode>(mode);
}
U2fMode GetU2fMode(bool force_u2f, bool force_g2f) {
U2fMode policy_mode = ReadU2fPolicy();
// Always honor the administrator request to disable even if given
// contradictory override flags.
if (policy_mode == U2fMode::kDisabled) {
return U2fMode::kDisabled;
}
if (force_g2f || policy_mode == U2fMode::kU2fExtended) {
return U2fMode::kU2fExtended;
}
if (force_u2f || policy_mode == U2fMode::kU2f) {
return U2fMode::kU2f;
}
return U2fMode::kDisabled;
}
const char* U2fModeToString(U2fMode mode) {
switch (mode) {
case U2fMode::kUnset:
return "disabled (no policy)";
case U2fMode::kDisabled:
return "disabled";
case U2fMode::kU2f:
return "U2F";
case U2fMode::kU2fExtended:
return "U2F+extensions";
}
return "unknown";
}
class U2fDaemon : public brillo::Daemon {
public:
U2fDaemon(U2fMode mode, uint32_t vendor_id, uint32_t product_id)
: u2f_mode_(mode), vendor_id_(vendor_id), product_id_(product_id) {}
private:
int OnInit() override {
std::string version;
if (!tpm_proxy_.Init()) {
LOG(ERROR) << "Failed to initialize D-Bus proxy with trunksd.";
return EX_IOERR;
}
int rc = tpm_proxy_.SetU2fVendorMode(static_cast<uint8_t>(u2f_mode_));
if (!rc)
rc = tpm_proxy_.GetU2fVersion(&version);
if (rc == u2f::kVendorRcNoSuchCommand) {
LOG(WARNING) << "U2F Feature not available in firmware.";
// Will exit gracefully as we don't want to re-spawn.
return EX_UNAVAILABLE;
}
if (rc != 0) {
LOG(ERROR) << "Cannot get U2F version from TPM.";
return EX_PROTOCOL;
}
LOG(INFO) << "version " << version;
dbus::Bus::Options options;
options.bus_type = dbus::Bus::SYSTEM;
bus_ = new dbus::Bus(options);
if (!bus_->Connect()) {
LOG(ERROR) << "Cannot connect to D-Bus.";
return EX_IOERR;
}
pm_proxy_ = std::make_unique<org::chromium::PowerManagerProxy>(bus_.get());
u2fhid_ = std::make_unique<u2f::U2fHid>(
std::make_unique<u2f::UHidDevice>(
vendor_id_, product_id_, kDeviceName, "u2fd-tpm-cr50"),
base::Bind(&u2f::TpmVendorCommandProxy::SendU2fApdu,
base::Unretained(&tpm_proxy_)),
base::Bind(
&org::chromium::PowerManagerProxy::IgnoreNextPowerButtonPress,
base::Unretained(pm_proxy_.get())));
return u2fhid_->Init() ? EX_OK : EX_PROTOCOL;
}
U2fMode u2f_mode_;
uint32_t vendor_id_;
uint32_t product_id_;
u2f::TpmVendorCommandProxy tpm_proxy_;
scoped_refptr<dbus::Bus> bus_;
std::unique_ptr<org::chromium::PowerManagerProxy> pm_proxy_;
std::unique_ptr<u2f::U2fHid> u2fhid_;
DISALLOW_COPY_AND_ASSIGN(U2fDaemon);
};
} // namespace
int main(int argc, char* argv[]) {
DEFINE_bool(force_u2f, false, "force U2F mode even if disabled by policy");
DEFINE_bool(
force_g2f, false, "force U2F mode plus extensions regardless of policy");
DEFINE_int32(product_id, kDefaultProductId, "Product ID for the HID device");
DEFINE_int32(vendor_id, kDefaultVendorId, "Vendor ID for the HID device");
DEFINE_bool(verbose, false, "verbose logging");
brillo::FlagHelper::Init(argc, argv, "u2fd, U2FHID emulation daemon.");
brillo::InitLog(brillo::kLogToSyslog | brillo::kLogHeader |
brillo::kLogToStderrIfTty);
if (FLAGS_verbose)
logging::SetMinLogLevel(-1);
LOG(INFO) << "Daemon version " << VCSID;
U2fMode mode = GetU2fMode(FLAGS_force_u2f, FLAGS_force_g2f);
LOG(INFO) << "Mode: " << U2fModeToString(mode)
<< " (force_u2f=" << FLAGS_force_u2f
<< " force_g2f=" << FLAGS_force_g2f << ")";
if (mode == U2fMode::kDisabled) {
LOG(INFO) << "U2F disabled, exiting...";
// Exit gracefully as we don't want to re-spawn.
return EX_OK;
}
U2fDaemon daemon(mode, FLAGS_vendor_id, FLAGS_product_id);
int rc = daemon.Run();
return rc == EX_UNAVAILABLE ? EX_OK : rc;
}