blob: a71b4c7ae701bc5b6c43c1bf3ae9d90aefa3657b [file] [log] [blame]
Louis Collardd0524c12019-09-27 09:09:18 +08001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "u2fd/u2f_daemon.h"
6
Louis Collardfca3bc32019-09-27 15:46:04 +08007#include <functional>
Louis Collardd0524c12019-09-27 09:09:18 +08008#include <string>
9#include <sysexits.h>
Louis Collardfca3bc32019-09-27 15:46:04 +080010#include <utility>
Louis Collardd4ee40d2019-10-01 14:19:01 +080011#include <vector>
Louis Collardd0524c12019-09-27 09:09:18 +080012
Louis Collardd4ee40d2019-10-01 14:19:01 +080013#include <attestation/proto_bindings/interface.pb.h>
14#include <attestation-client/attestation/dbus-constants.h>
15#include <base/bind.h>
16#include <base/optional.h>
17#include <base/synchronization/waitable_event.h>
Louis Collardd0524c12019-09-27 09:09:18 +080018#include <dbus/u2f/dbus-constants.h>
19#include <policy/device_policy.h>
20#include <policy/libpolicy.h>
Louis Collardd4ee40d2019-10-01 14:19:01 +080021#include <trunks/cr50_headers/virtual_nvmem.h>
Louis Collardd0524c12019-09-27 09:09:18 +080022
23#include "u2fd/u2fhid.h"
24#include "u2fd/uhid_device.h"
25
26namespace u2f {
27
Louis Collardd0524c12019-09-27 09:09:18 +080028namespace {
29
30constexpr char kDeviceName[] = "Integrated U2F";
31constexpr int kWinkSignalMinIntervalMs = 1000;
32
33// The U2F counter stored in cr50 is stored in a format resistant to rollbacks,
34// and that guarantees monotonicity even in the presence of partial writes.
35// See //platform/ec/include/nvcounter.h
36//
37// The counter is stored across 2 pages of flash - a high page and a low page,
38// with each page containing 512 4-byte words. The counter increments using
39// 'strikes', with each strike occupying 4 bits. The high page can represent
40// numbers 0-2048, and the low page can represent numbers 0-4096.
41// The pages are interpreted as two digits of a base-4097 number, giving us
42// the maximum value below.
43// See //platform/ec/common/nvcounter.c for more details.
44constexpr uint32_t kMaxCr50U2fCounterValue = (2048 * 4097) + 4096;
45// If we are supporting legacy key handles, we initialize the counter such that
46// it is always larger than the maximum possible value cr50 could have returned,
47// and therefore guarantee that we provide a monotonically increasing counter
48// value for migrated key handles.
49constexpr uint32_t kLegacyKhCounterMin = kMaxCr50U2fCounterValue + 1;
50
51bool U2fPolicyReady() {
52 policy::PolicyProvider policy_provider;
53
54 return policy_provider.Reload();
55}
56
57U2fMode ReadU2fPolicy() {
58 policy::PolicyProvider policy_provider;
59
60 if (!policy_provider.Reload()) {
61 LOG(DFATAL) << "Failed to load device policy";
62 }
63
64 int mode = 0;
65 const policy::DevicePolicy* policy = &policy_provider.GetDevicePolicy();
66 if (!policy->GetSecondFactorAuthenticationMode(&mode))
67 return U2fMode::kUnset;
68
69 return static_cast<U2fMode>(mode);
70}
71
Louis Collard49d78f92019-09-27 14:59:44 +080072const char* U2fModeToString(U2fMode mode) {
73 switch (mode) {
74 case U2fMode::kUnset:
75 return "unset";
76 case U2fMode::kDisabled:
77 return "disabled";
78 case U2fMode::kU2f:
79 return "U2F";
80 case U2fMode::kU2fExtended:
81 return "U2F+extensions";
82 }
83 return "unknown";
84}
85
Louis Collardd0524c12019-09-27 09:09:18 +080086U2fMode GetU2fMode(bool force_u2f, bool force_g2f) {
87 U2fMode policy_mode = ReadU2fPolicy();
88
Louis Collard49d78f92019-09-27 14:59:44 +080089 LOG(INFO) << "Requested Mode: Policy[" << U2fModeToString(policy_mode)
90 << "], force_u2f[" << force_u2f << "], force_g2f[" << force_g2f
91 << "]";
92
Louis Collardd0524c12019-09-27 09:09:18 +080093 // Always honor the administrator request to disable even if given
94 // contradictory override flags.
95 if (policy_mode == U2fMode::kDisabled) {
Louis Collard49d78f92019-09-27 14:59:44 +080096 LOG(INFO) << "Mode: Disabled (explicitly by policy)";
Louis Collardd0524c12019-09-27 09:09:18 +080097 return U2fMode::kDisabled;
98 }
99
100 if (force_g2f || policy_mode == U2fMode::kU2fExtended) {
Louis Collard49d78f92019-09-27 14:59:44 +0800101 LOG(INFO) << "Mode: U2F+extensions";
Louis Collardd0524c12019-09-27 09:09:18 +0800102 return U2fMode::kU2fExtended;
103 }
104
105 if (force_u2f || policy_mode == U2fMode::kU2f) {
Louis Collard49d78f92019-09-27 14:59:44 +0800106 LOG(INFO) << "Mode:U2F";
Louis Collardd0524c12019-09-27 09:09:18 +0800107 return U2fMode::kU2f;
108 }
109
Louis Collard49d78f92019-09-27 14:59:44 +0800110 LOG(INFO) << "Mode: Disabled";
Louis Collardd0524c12019-09-27 09:09:18 +0800111 return U2fMode::kDisabled;
112}
113
114void OnPolicySignalConnected(const std::string& interface,
115 const std::string& signal,
116 bool success) {
117 if (!success) {
118 LOG(FATAL) << "Could not connect to signal " << signal << " on interface "
119 << interface;
120 }
121}
122
Louis Collardd0524c12019-09-27 09:09:18 +0800123} // namespace
124
125U2fDaemon::U2fDaemon(bool force_u2f,
126 bool force_g2f,
Louis Collardd4ee40d2019-10-01 14:19:01 +0800127 bool g2f_allowlist_data,
Louis Collardd0524c12019-09-27 09:09:18 +0800128 bool legacy_kh_fallback,
129 uint32_t vendor_id,
130 uint32_t product_id)
Louis Collardf35b15c2019-10-04 12:22:28 +0800131 : brillo::DBusServiceDaemon(u2f::kU2FServiceName),
132 force_u2f_(force_u2f),
Louis Collardd0524c12019-09-27 09:09:18 +0800133 force_g2f_(force_g2f),
Louis Collardd4ee40d2019-10-01 14:19:01 +0800134 g2f_allowlist_data_(g2f_allowlist_data),
Louis Collard9977d552019-09-27 11:25:03 +0800135 legacy_kh_fallback_(legacy_kh_fallback),
Louis Collardd0524c12019-09-27 09:09:18 +0800136 vendor_id_(vendor_id),
137 product_id_(product_id) {}
138
139int U2fDaemon::OnInit() {
Louis Collardf35b15c2019-10-04 12:22:28 +0800140 int rc = brillo::DBusServiceDaemon::OnInit();
141 if (rc != EX_OK)
142 return rc;
Louis Collardc345b3a2019-09-27 14:59:24 +0800143
144 if (!InitializeDBusProxies()) {
145 return EX_IOERR;
146 }
147
Yicheng Lia09baa02020-09-02 13:04:26 -0700148 user_state_ = std::make_unique<u2f::UserState>(
149 sm_proxy_.get(), legacy_kh_fallback_ ? kLegacyKhCounterMin : 0);
150
Louis Collardd0524c12019-09-27 09:09:18 +0800151 sm_proxy_->RegisterPropertyChangeCompleteSignalHandler(
Yicheng Li53b0c732020-12-09 13:57:15 -0800152 base::Bind(&U2fDaemon::TryStartService, base::Unretained(this)),
Louis Collardd0524c12019-09-27 09:09:18 +0800153 base::Bind(&OnPolicySignalConnected));
154
155 bool policy_ready = U2fPolicyReady();
156
157 if (policy_ready) {
Yicheng Li53b0c732020-12-09 13:57:15 -0800158 int status = StartService();
Yicheng Lida824952020-12-01 14:23:43 -0800159
Louis Collardd0524c12019-09-27 09:09:18 +0800160 // If U2F is not currently enabled, we'll wait for policy updates
161 // that may enable it. We don't ever disable U2F on policy updates.
162 // TODO(louiscollard): Fix the above.
163 if (status != EX_CONFIG)
164 return status;
165 }
166
167 if (policy_ready) {
168 LOG(INFO) << "U2F currently disabled, waiting for policy updates...";
169 } else {
170 LOG(INFO) << "Policy not available, waiting...";
171 }
172
173 return EX_OK;
174}
175
Yicheng Li53b0c732020-12-09 13:57:15 -0800176void U2fDaemon::TryStartService(
Louis Collardd0524c12019-09-27 09:09:18 +0800177 const std::string& /* unused dbus signal status */) {
Yicheng Li53b0c732020-12-09 13:57:15 -0800178 // If there's u2fhid_ then we have already started service.
179 if (u2fhid_)
180 return;
181
182 if (!U2fPolicyReady())
183 return;
184
185 int status = StartService();
186
187 if (status != EX_OK && status != EX_CONFIG) {
188 // Something went wrong.
189 exit(status);
Louis Collardd0524c12019-09-27 09:09:18 +0800190 }
191}
192
Yicheng Li53b0c732020-12-09 13:57:15 -0800193int U2fDaemon::StartService() {
194 // Start U2fHid service before WebAuthn because WebAuthn initialization can
195 // be slow.
196 int status = StartU2fHidService();
197
198 U2fMode u2f_mode = GetU2fMode(force_u2f_, force_g2f_);
Yicheng Lid0d21e22020-12-17 18:06:23 -0800199 LOG(INFO) << "Initializing WebAuthn handler.";
Yicheng Lia42e6d42021-01-22 14:58:46 -0800200 InitializeWebAuthnHandler(u2f_mode);
Yicheng Li53b0c732020-12-09 13:57:15 -0800201
202 return status;
203}
204
Yicheng Lia09baa02020-09-02 13:04:26 -0700205int U2fDaemon::StartU2fHidService() {
Louis Collardd0524c12019-09-27 09:09:18 +0800206 if (u2fhid_) {
207 // Any failures in previous calls to this function would have caused the
208 // program to terminate, so we can assume we have successfully started.
209 return EX_OK;
210 }
211
Louis Collard49d78f92019-09-27 14:59:44 +0800212 U2fMode u2f_mode = GetU2fMode(force_u2f_, force_g2f_);
213 if (u2f_mode == U2fMode::kDisabled) {
Louis Collardd0524c12019-09-27 09:09:18 +0800214 return EX_CONFIG;
215 }
216
Yicheng Lia09baa02020-09-02 13:04:26 -0700217 LOG(INFO) << "Starting U2fHid service.";
218
Louis Collardbd3fc472019-10-18 16:19:03 +0800219 // If g2f is enabled by policy, we always include allowlisting data.
220 bool include_g2f_allowlist_data =
221 g2f_allowlist_data_ || (ReadU2fPolicy() == U2fMode::kU2fExtended);
222
223 CreateU2fMsgHandler(
224 u2f_mode == U2fMode::kU2fExtended /* Allow G2F Attestation */,
225 include_g2f_allowlist_data);
Louis Collarda5fa3c32019-10-07 15:02:25 +0800226
Louis Collardfca3bc32019-09-27 15:46:04 +0800227 CreateU2fHid();
Louis Collardd0524c12019-09-27 09:09:18 +0800228
229 return u2fhid_->Init() ? EX_OK : EX_PROTOCOL;
230}
231
Louis Collardc345b3a2019-09-27 14:59:24 +0800232bool U2fDaemon::InitializeDBusProxies() {
233 if (!tpm_proxy_.Init()) {
Louis Collardd4ee40d2019-10-01 14:19:01 +0800234 LOG(ERROR) << "Failed to initialize trunksd DBus proxy";
235 return false;
236 }
237
238 attestation_proxy_ = bus_->GetObjectProxy(
239 attestation::kAttestationServiceName,
240 dbus::ObjectPath(attestation::kAttestationServicePath));
241
242 if (!attestation_proxy_) {
243 LOG(ERROR) << "Failed to initialize attestationd DBus proxy";
Louis Collardc345b3a2019-09-27 14:59:24 +0800244 return false;
245 }
246
Louis Collardd0524c12019-09-27 09:09:18 +0800247 pm_proxy_ = std::make_unique<org::chromium::PowerManagerProxy>(bus_.get());
248 sm_proxy_ =
249 std::make_unique<org::chromium::SessionManagerInterfaceProxy>(bus_.get());
250
251 return true;
252}
253
Louis Collardf35b15c2019-10-04 12:22:28 +0800254void U2fDaemon::RegisterDBusObjectsAsync(
255 brillo::dbus_utils::AsyncEventSequencer* sequencer) {
Louis Collardd0524c12019-09-27 09:09:18 +0800256 dbus_object_.reset(new brillo::dbus_utils::DBusObject(
257 nullptr, bus_, dbus::ObjectPath(u2f::kU2FServicePath)));
258
259 auto u2f_interface = dbus_object_->AddOrGetInterface(u2f::kU2FInterface);
260
261 wink_signal_ = u2f_interface->RegisterSignal<u2f::UserNotification>(
262 u2f::kU2FUserNotificationSignal);
263
Yicheng Lic03ac7e2019-12-09 16:13:26 -0800264 // Handlers for the WebAuthn DBus API.
265 u2f_interface->AddMethodHandler(kU2FMakeCredential,
266 base::Unretained(&webauthn_handler_),
267 &WebAuthnHandler::MakeCredential);
Louis Collardb7664ae2019-10-05 13:57:01 +0800268
Yicheng Lic03ac7e2019-12-09 16:13:26 -0800269 u2f_interface->AddMethodHandler(kU2FGetAssertion,
270 base::Unretained(&webauthn_handler_),
271 &WebAuthnHandler::GetAssertion);
Louis Collardb7664ae2019-10-05 13:57:01 +0800272
273 u2f_interface->AddSimpleMethodHandler(kU2FHasCredentials,
274 base::Unretained(&webauthn_handler_),
275 &WebAuthnHandler::HasCredentials);
276
Yicheng Lif2a083a2020-12-21 17:29:47 -0800277 u2f_interface->AddSimpleMethodHandler(kU2FHasLegacyCredentials,
278 base::Unretained(&webauthn_handler_),
279 &WebAuthnHandler::HasLegacyCredentials);
280
Yicheng Li98006782020-09-09 18:19:54 -0700281 u2f_interface->AddSimpleMethodHandler(kU2FCancelWebAuthnFlow,
282 base::Unretained(&webauthn_handler_),
283 &WebAuthnHandler::Cancel);
284
Yicheng Lif17da5c2020-11-06 20:31:26 -0800285 u2f_interface->AddMethodHandler(kU2FIsUvpaa,
286 base::Unretained(&webauthn_handler_),
287 &WebAuthnHandler::IsUvpaa);
288
Yicheng Libc150862021-01-13 10:59:53 -0800289 u2f_interface->AddSimpleMethodHandler(kU2FIsU2fEnabled,
290 base::Unretained(&webauthn_handler_),
291 &WebAuthnHandler::IsU2fEnabled);
292
Louis Collardf35b15c2019-10-04 12:22:28 +0800293 dbus_object_->RegisterAsync(
294 sequencer->GetHandler("Failed to register DBus Interface.", true));
Louis Collardd0524c12019-09-27 09:09:18 +0800295}
296
Louis Collardbd3fc472019-10-18 16:19:03 +0800297void U2fDaemon::CreateU2fMsgHandler(bool allow_g2f_attestation,
298 bool include_g2f_allowlisting_data) {
Louis Collardfca3bc32019-09-27 15:46:04 +0800299 std::function<void()> request_presence = [this]() {
300 IgnorePowerButtonPress();
301 SendWinkSignal();
302 };
303
Louis Collardd4ee40d2019-10-01 14:19:01 +0800304 auto allowlisting_util =
Louis Collardbd3fc472019-10-18 16:19:03 +0800305 include_g2f_allowlisting_data
Louis Collardd4ee40d2019-10-01 14:19:01 +0800306 ? std::make_unique<u2f::AllowlistingUtil>([this](int cert_size) {
307 return GetCertifiedG2fCert(cert_size);
308 })
309 : std::unique_ptr<u2f::AllowlistingUtil>(nullptr);
310
Louis Collardfca3bc32019-09-27 15:46:04 +0800311 u2f_msg_handler_ = std::make_unique<u2f::U2fMessageHandler>(
Louis Collarda5fa3c32019-10-07 15:02:25 +0800312 std::move(allowlisting_util), request_presence, user_state_.get(),
Andrey Pronind289a1d2020-01-22 18:51:13 -0800313 &tpm_proxy_, &metrics_library_, legacy_kh_fallback_,
314 allow_g2f_attestation);
Louis Collardfca3bc32019-09-27 15:46:04 +0800315}
316
317void U2fDaemon::CreateU2fHid() {
Louis Collardfca3bc32019-09-27 15:46:04 +0800318 u2fhid_ = std::make_unique<u2f::U2fHid>(
319 std::make_unique<u2f::UHidDevice>(vendor_id_, product_id_, kDeviceName,
320 "u2fd-tpm-cr50"),
Louis Collardaf957012020-02-12 14:21:43 +0800321 u2f_msg_handler_.get());
Louis Collardfca3bc32019-09-27 15:46:04 +0800322}
323
Yicheng Lia42e6d42021-01-22 14:58:46 -0800324void U2fDaemon::InitializeWebAuthnHandler(U2fMode u2f_mode) {
Yicheng Li546ea542019-11-15 14:28:06 -0800325 std::function<void()> request_presence = [this]() {
326 IgnorePowerButtonPress();
327 SendWinkSignal();
328 };
329
Yicheng Li1bbf5292021-01-25 17:19:56 -0800330 std::unique_ptr<u2f::AllowlistingUtil> allowlisting_util;
331 // If g2f is enabled by policy, we always include allowlisting data.
332 if (g2f_allowlist_data_ || (ReadU2fPolicy() == U2fMode::kU2fExtended)) {
333 allowlisting_util = std::make_unique<u2f::AllowlistingUtil>(
334 [this](int cert_size) { return GetCertifiedG2fCert(cert_size); });
335 }
336
Yicheng Lib46d4362020-06-05 15:15:45 -0700337 webauthn_handler_.Initialize(bus_.get(), &tpm_proxy_, user_state_.get(),
Yicheng Li1bbf5292021-01-25 17:19:56 -0800338 u2f_mode, request_presence,
Yicheng Lie7a26252021-02-03 12:18:37 -0800339 std::move(allowlisting_util), &metrics_library_);
Yicheng Li546ea542019-11-15 14:28:06 -0800340}
341
Louis Collardd0524c12019-09-27 09:09:18 +0800342void U2fDaemon::SendWinkSignal() {
343 static base::TimeTicks last_sent;
344 base::TimeDelta elapsed = base::TimeTicks::Now() - last_sent;
345
346 if (elapsed.InMilliseconds() > kWinkSignalMinIntervalMs) {
347 u2f::UserNotification notification;
348 notification.set_event_type(u2f::UserNotification::TOUCH_NEEDED);
349
350 wink_signal_.lock()->Send(notification);
351
352 last_sent = base::TimeTicks::Now();
353 }
354}
355
356void U2fDaemon::IgnorePowerButtonPress() {
357 // Duration of the user presence persistence on the firmware side.
358 const base::TimeDelta kPresenceTimeout = base::TimeDelta::FromSeconds(10);
359
360 brillo::ErrorPtr err;
361 // Mask the next power button press for the UI
362 pm_proxy_->IgnoreNextPowerButtonPress(kPresenceTimeout.ToInternalValue(),
363 &err, -1);
364}
365
Louis Collardd4ee40d2019-10-01 14:19:01 +0800366namespace {
367
368constexpr char kKeyLabelEmk[] = "attest-ent-machine";
369
370} // namespace
371
372base::Optional<attestation::GetCertifiedNvIndexReply>
373U2fDaemon::GetCertifiedG2fCert(int g2f_cert_size) {
374 if (g2f_cert_size < 1 || g2f_cert_size > VIRTUAL_NV_INDEX_G2F_CERT_SIZE) {
375 LOG(ERROR)
376 << "Invalid G2F cert size specified for whitelisting data request";
377 return base::nullopt;
378 }
379
380 attestation::GetCertifiedNvIndexRequest request;
381
382 request.set_nv_index(VIRTUAL_NV_INDEX_G2F_CERT);
383 request.set_nv_size(g2f_cert_size);
384 request.set_key_label(kKeyLabelEmk);
385
386 brillo::ErrorPtr error;
387
388 std::unique_ptr<dbus::Response> dbus_response =
389 brillo::dbus_utils::CallMethodAndBlock(
390 attestation_proxy_, attestation::kAttestationInterface,
391 attestation::kGetCertifiedNvIndex, &error, request);
392
393 if (!dbus_response) {
394 LOG(ERROR) << "Failed to retrieve certified G2F cert from attestationd";
395 return base::nullopt;
396 }
397
398 attestation::GetCertifiedNvIndexReply reply;
399
400 dbus::MessageReader reader(dbus_response.get());
401 if (!reader.PopArrayOfBytesAsProto(&reply)) {
402 LOG(ERROR) << "Failed to parse GetCertifiedNvIndexReply";
403 return base::nullopt;
404 }
405
406 if (reply.status() != attestation::AttestationStatus::STATUS_SUCCESS) {
407 LOG(ERROR) << "Call get GetCertifiedNvIndex failed, status: "
408 << reply.status();
409 return base::nullopt;
410 }
411
412 return reply;
413}
414
Louis Collardd0524c12019-09-27 09:09:18 +0800415} // namespace u2f