blob: e4da67f1a4af0e098cdba4005ab706fc72b5aab0 [file] [log] [blame]
// Copyright 2020 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 "arc/keymaster/context/context_adaptor.h"
#include <memory>
#include <base/check.h>
#include <base/logging.h>
#include <base/optional.h>
#include <brillo/dbus/dbus_object.h>
#include <chromeos/dbus/service_constants.h>
#include <dbus/object_proxy.h>
#include <session_manager/dbus-proxies.h>
namespace arc {
namespace keymaster {
namespace context {
namespace {
scoped_refptr<::dbus::Bus> InitDBusInCurrentTaskRunner() {
dbus::Bus::Options options;
options.bus_type = dbus::Bus::SYSTEM;
scoped_refptr<::dbus::Bus> bus = new dbus::Bus(options);
CHECK(bus->Connect()) << "Failed to initialize adaptor DBus connection";
return bus;
}
} // namespace
ContextAdaptor::ContextAdaptor() : weak_ptr_factory_(this) {}
ContextAdaptor::~ContextAdaptor() = default;
scoped_refptr<::dbus::Bus> ContextAdaptor::GetBus() {
// Ensure |bus_| is initialized before usages.
if (!bus_)
bus_ = InitDBusInCurrentTaskRunner();
return bus_;
}
base::Optional<std::string> ContextAdaptor::FetchPrimaryUserEmail() {
// Short circuit if the results is already cached.
if (cached_email_.has_value())
return cached_email_.value();
// Prepare output variables.
std::string user_email;
std::string sanitized_username;
brillo::ErrorPtr error;
// Make dbus call.
org::chromium::SessionManagerInterfaceProxy session_manager_proxy(GetBus());
if (!session_manager_proxy.RetrievePrimarySession(
&user_email, &sanitized_username, &error)) {
std::string error_message = error ? error->GetMessage() : "Unknown error.";
LOG(INFO) << "Failed to get primary session: " << error_message;
return base::nullopt;
}
// Cache and return result.
cached_email_ = user_email;
return user_email;
}
base::Optional<CK_SLOT_ID> ContextAdaptor::FetchSlotId(Slot slot) {
switch (slot) {
case Slot::kUser:
return FetchPrimaryUserSlotId();
case Slot::kSystem:
return FetchSystemSlotId();
default:
LOG(ERROR) << "Unknown chaps slot=" << static_cast<int>(slot);
return base::nullopt;
}
}
base::Optional<CK_SLOT_ID> ContextAdaptor::FetchPrimaryUserSlotId() {
// Short circuit if the result is already cached.
if (cached_user_slot_.has_value())
return cached_user_slot_;
// Fetch email of the primary signed in user.
base::Optional<std::string> user_email = FetchPrimaryUserEmail();
if (!user_email.has_value())
return base::nullopt;
// Cache and return result.
cached_user_slot_ = FetchSlotIdFromTpmTokenInfo(user_email);
return cached_user_slot_;
}
base::Optional<CK_SLOT_ID> ContextAdaptor::FetchSystemSlotId() {
// Initialize |cached_system_slot_| if result is not already cached.
if (!cached_system_slot_.has_value()) {
cached_system_slot_ =
FetchSlotIdFromTpmTokenInfo(/*user_email=*/base::nullopt);
}
return cached_system_slot_;
}
base::Optional<CK_SLOT_ID> ContextAdaptor::FetchSlotIdFromTpmTokenInfo(
base::Optional<std::string> user_email) {
// Create the dbus proxy if it's not created.
if (!pkcs11_proxy_) {
pkcs11_proxy_.reset(
new org::chromium::CryptohomePkcs11InterfaceProxy(GetBus()));
}
user_data_auth::Pkcs11GetTpmTokenInfoRequest request;
// Setting a username retrieves the token info for that user. Leaving it empty
// retrieves token info for the system.
if (user_email.has_value())
request.set_username(user_email.value());
user_data_auth::Pkcs11GetTpmTokenInfoReply reply;
brillo::ErrorPtr error;
bool success = pkcs11_proxy_->Pkcs11GetTpmTokenInfo(
request, &reply, &error, user_data_auth::kUserDataAuthServiceTimeoutInMs);
if (!success || error) {
// Error is logged when it is created, so we don't need to log it again.
LOG(ERROR) << "Could not fetch slot information from cryptohome.";
return base::nullopt;
}
// Return resulting slot.
return reply.token_info().slot();
}
} // namespace context
} // namespace keymaster
} // namespace arc