Skip to content

Commit

Permalink
Add ArcKeyMintBridge, CertStoreBridgeKeyMint and cert_store.mojom
Browse files Browse the repository at this point in the history
Add ArcKeyMintBridge and CertStoreBridgeKeyMint. Mostly copied over from
chrome/browser/ash/arc/keymaster, and will co-exist with the later.

In follow-up CL(s), CertStoreService will determine whether system should
use KeyMint or Keymaster, and choose either ArcKeyMintBridge or
ArcKeymasterBridge.

This CL also added a cert_store.mojom, copied over from
chrome/services/keymaster/public/mojom/cert_store.mojom. Adding a
separate mojom file allows for potential changes related to KeyMint,
while keeping the one for Keymaster stable. It also allows easier
deprecation of Keymaster in the future.

As of this CL, ArcKeyMintBridge and CertStoreBridgeKeyMint are not yet
being meaningfully used, thus should not break anything either.

Bug: b:247941366
Test: autoninja -C out/Default/ ash_components_unittests &&
testing/xvfb.py ./out/Default/ash_components_unittests
Test: autoninja -C out_hatch/Release/ chrome chrome_sandbox nacl_helper

Change-Id: Ibf24793b671aa8ea091ac127a81578bc2d680018
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4189369
Reviewed-by: Alex Gough <ajgo@chromium.org>
Reviewed-by: Yury Khmel <khmel@chromium.org>
Commit-Queue: Yao Li <yaohuali@google.com>
Reviewed-by: Ken Rockot <rockot@google.com>
Cr-Commit-Position: refs/heads/main@{#1100784}
  • Loading branch information
yaoli-us authored and Chromium LUCI CQ committed Feb 3, 2023
1 parent 7980f5f commit 215bdb1
Show file tree
Hide file tree
Showing 12 changed files with 441 additions and 7 deletions.
5 changes: 5 additions & 0 deletions chrome/browser/ash/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,10 @@ source_set("ash") {
"arc/keymaster/arc_keymaster_bridge.h",
"arc/keymaster/cert_store_bridge.cc",
"arc/keymaster/cert_store_bridge.h",
"arc/keymint/arc_keymint_bridge.cc",
"arc/keymint/arc_keymint_bridge.h",
"arc/keymint/cert_store_bridge_keymint.cc",
"arc/keymint/cert_store_bridge_keymint.h",
"arc/kiosk/arc_kiosk_bridge.cc",
"arc/kiosk/arc_kiosk_bridge.h",
"arc/metrics/arc_metrics_service_proxy.cc",
Expand Down Expand Up @@ -3393,6 +3397,7 @@ source_set("ash") {
"//chrome/services/file_util/public/cpp",
"//chrome/services/keymanagement/public/mojom",
"//chrome/services/keymaster/public/mojom",
"//chrome/services/keymint/public/mojom",
"//chrome/services/media_gallery_util/public/cpp",
"//chrome/services/media_gallery_util/public/mojom:mojom_headers",
"//chrome/services/printing/public/mojom",
Expand Down
1 change: 1 addition & 0 deletions chrome/browser/ash/arc/DEPS
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
include_rules = [
"+chrome/services/keymanagement/public",
"+chrome/services/keymaster/public",
"+chrome/services/keymint/public",
"+services/tracing/public",
]
2 changes: 1 addition & 1 deletion chrome/browser/ash/arc/keymaster/arc_keymaster_bridge.cc
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ ArcKeymasterBridge::~ArcKeymasterBridge() {
void ArcKeymasterBridge::UpdatePlaceholderKeys(
std::vector<keymaster::mojom::ChromeOsKeyPtr> keys,
UpdatePlaceholderKeysCallback callback) {
if (cert_store_bridge_->is_proxy_bound()) {
if (cert_store_bridge_->IsProxyBound()) {
cert_store_bridge_->UpdatePlaceholderKeysInKeymaster(std::move(keys),
std::move(callback));
} else {
Expand Down
4 changes: 4 additions & 0 deletions chrome/browser/ash/arc/keymaster/cert_store_bridge.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ void CertStoreBridge::UpdatePlaceholderKeysInKeymaster(
}
}

bool CertStoreBridge::IsProxyBound() const {
return cert_store_proxy_.is_bound();
}

void CertStoreBridge::BindToInvitation(mojo::OutgoingInvitation* invitation) {
VLOG(2) << "CertStoreBridge::BootstrapMojoConnection";

Expand Down
10 changes: 4 additions & 6 deletions chrome/browser/ash/arc/keymaster/cert_store_bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ class BrowserContext;

} // namespace content

namespace arc {
namespace keymaster {
namespace arc::keymaster {

class CertStoreBridge {
public:
Expand All @@ -32,9 +31,9 @@ class CertStoreBridge {
// store instance proxy.
void BindToInvitation(mojo::OutgoingInvitation* invitation);

bool is_proxy_bound() const { return cert_store_proxy_.is_bound(); }
bool IsProxyBound() const;

// Send the latest information about Chrome OS keys to arc-keymasterd.
// Updates the latest information about Chrome OS keys to arc-keymasterd.
void UpdatePlaceholderKeysInKeymaster(
std::vector<mojom::ChromeOsKeyPtr> keys,
mojom::CertStoreInstance::UpdatePlaceholderKeysCallback callback);
Expand All @@ -46,7 +45,6 @@ class CertStoreBridge {
base::WeakPtrFactory<CertStoreBridge> weak_ptr_factory_;
};

} // namespace keymaster
} // namespace arc
} // namespace arc::keymaster

#endif // CHROME_BROWSER_ASH_ARC_KEYMASTER_CERT_STORE_BRIDGE_H_
163 changes: 163 additions & 0 deletions chrome/browser/ash/arc/keymint/arc_keymint_bridge.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ash/arc/keymint/arc_keymint_bridge.h"

#include "ash/components/arc/arc_browser_context_keyed_service_factory_base.h"
#include "ash/components/arc/session/arc_bridge_service.h"
#include "base/memory/singleton.h"
#include "chrome/browser/ash/arc/keymint/cert_store_bridge_keymint.h"
#include "chromeos/ash/components/dbus/arc/arc_keymaster_client.h" // XXX
#include "mojo/core/embedder/embedder.h"
#include "mojo/public/cpp/platform/platform_channel.h"

namespace arc {

namespace {

// Singleton factory for ArcKeyMintBridge
class ArcKeyMintBridgeFactory
: public internal::ArcBrowserContextKeyedServiceFactoryBase<
ArcKeyMintBridge,
ArcKeyMintBridgeFactory> {
public:
// Factory name used by ArcBrowserContextKeyedServiceFactoryBase.
static constexpr const char* kName = "ArcKeyMintBridgeFactory";

static ArcKeyMintBridgeFactory* GetInstance() {
return base::Singleton<ArcKeyMintBridgeFactory>::get();
}

private:
friend base::DefaultSingletonTraits<ArcKeyMintBridgeFactory>;
ArcKeyMintBridgeFactory() = default;
~ArcKeyMintBridgeFactory() override = default;
};

} // namespace

// static
BrowserContextKeyedServiceFactory* ArcKeyMintBridge::GetFactory() {
return ArcKeyMintBridgeFactory::GetInstance();
}

// static
ArcKeyMintBridge* ArcKeyMintBridge::GetForBrowserContext(
content::BrowserContext* context) {
return ArcKeyMintBridgeFactory::GetForBrowserContext(context);
}

ArcKeyMintBridge::ArcKeyMintBridge(content::BrowserContext* context,
ArcBridgeService* bridge_service)
: arc_bridge_service_(bridge_service),
cert_store_bridge_(
std::make_unique<keymint::CertStoreBridgeKeyMint>(context)),
weak_factory_(this) {
if (arc_bridge_service_) {
arc_bridge_service_->keymint()->SetHost(this);
}
}

ArcKeyMintBridge::~ArcKeyMintBridge() {
if (arc_bridge_service_) {
arc_bridge_service_->keymint()->SetHost(nullptr);
}
}

void ArcKeyMintBridge::UpdatePlaceholderKeys(
std::vector<keymint::mojom::ChromeOsKeyPtr> keys,
UpdatePlaceholderKeysCallback callback) {
if (cert_store_bridge_->IsProxyBound()) {
cert_store_bridge_->UpdatePlaceholderKeysInKeyMint(std::move(keys),
std::move(callback));
} else {
BootstrapMojoConnection(base::BindOnce(
&ArcKeyMintBridge::UpdatePlaceholderKeysAfterBootstrap,
weak_factory_.GetWeakPtr(), std::move(keys), std::move(callback)));
}
}

void ArcKeyMintBridge::UpdatePlaceholderKeysAfterBootstrap(
std::vector<keymint::mojom::ChromeOsKeyPtr> keys,
UpdatePlaceholderKeysCallback callback,
bool bootstrapResult) {
if (bootstrapResult) {
cert_store_bridge_->UpdatePlaceholderKeysInKeyMint(std::move(keys),
std::move(callback));
} else {
std::move(callback).Run(/*success=*/false);
}
}

void ArcKeyMintBridge::GetServer(GetServerCallback callback) {
if (keymint_server_proxy_.is_bound()) {
std::move(callback).Run(keymint_server_proxy_.Unbind());
} else {
BootstrapMojoConnection(
base::BindOnce(&ArcKeyMintBridge::GetServerAfterBootstrap,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
}

void ArcKeyMintBridge::GetServerAfterBootstrap(GetServerCallback callback,
bool bootstrapResult) {
if (bootstrapResult) {
std::move(callback).Run(keymint_server_proxy_.Unbind());
} else {
std::move(callback).Run(mojo::NullRemote());
}
}

void ArcKeyMintBridge::OnBootstrapMojoConnection(
BootstrapMojoConnectionCallback callback,
bool result) {
if (result) {
DVLOG(1) << "Success bootstrapping Mojo in arc-keymasterd.";
} else {
LOG(ERROR) << "Error bootstrapping Mojo in arc-keymasterd.";
keymint_server_proxy_.reset();
}
std::move(callback).Run(result);
}

void ArcKeyMintBridge::BootstrapMojoConnection(
BootstrapMojoConnectionCallback callback) {
DVLOG(1) << "Bootstrapping arc-keymasterd Mojo connection via D-Bus.";

mojo::OutgoingInvitation invitation;
mojo::PlatformChannel channel;
mojo::ScopedMessagePipeHandle server_pipe;
if (mojo::core::IsMojoIpczEnabled()) {
constexpr uint64_t kKeyMintPipeAttachment = 0;
server_pipe = invitation.AttachMessagePipe(kKeyMintPipeAttachment);
} else {
server_pipe = invitation.AttachMessagePipe("arc-keymint-pipe");
}
if (!server_pipe.is_valid()) {
LOG(ERROR) << "ArcKeyMintBridge could not bind to invitation";
std::move(callback).Run(false);
return;
}

// Bootstrap cert_store channel attached to the same invitation.
cert_store_bridge_->BindToInvitation(&invitation);

mojo::OutgoingInvitation::Send(std::move(invitation),
base::kNullProcessHandle,
channel.TakeLocalEndpoint());

keymint_server_proxy_.Bind(mojo::PendingRemote<mojom::keymint::KeyMintServer>(
std::move(server_pipe), 0u));
DVLOG(1) << "Bound remote KeyMintServer interface to pipe.";
keymint_server_proxy_.set_disconnect_handler(
base::BindOnce(&mojo::Remote<mojom::keymint::KeyMintServer>::reset,
base::Unretained(&keymint_server_proxy_)));
// TODO(b/247941366): Create ArcKeyMintClient.
ash::ArcKeymasterClient::Get()->BootstrapMojoConnection(
channel.TakeRemoteEndpoint().TakePlatformHandle().TakeFD(),
base::BindOnce(&ArcKeyMintBridge::OnBootstrapMojoConnection,
weak_factory_.GetWeakPtr(), std::move(callback)));
}

} // namespace arc
86 changes: 86 additions & 0 deletions chrome/browser/ash/arc/keymint/arc_keymint_bridge.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_ASH_ARC_KEYMINT_ARC_KEYMINT_BRIDGE_H_
#define CHROME_BROWSER_ASH_ARC_KEYMINT_ARC_KEYMINT_BRIDGE_H_

#include "ash/components/arc/arc_browser_context_keyed_service_factory_base.h"
#include "ash/components/arc/mojom/keymint.mojom.h"
#include "chrome/browser/ash/arc/keymint/cert_store_bridge_keymint.h"
#include "components/keyed_service/core/keyed_service.h"
#include "mojo/public/cpp/bindings/remote.h"

namespace content {
class BrowserContext;
} // namespace content

namespace arc {

class ArcBridgeService;

// This class is responsible for providing a KeyMintServer proxy by
// bootstrapping a mojo connection with the arc-keymintd daemon. The mojo
// connection is bootstrapped lazily during the first call to GetServer. Chrome
// has no further involvement once the KeyMintServer proxy has been forwarded
// to the KeyMintInstance in ARC.
class ArcKeyMintBridge : public KeyedService,
public mojom::keymint::KeyMintHost {
public:
using mojom::keymint::KeyMintHost::GetServerCallback;
using UpdatePlaceholderKeysCallback = base::OnceCallback<void(bool)>;

// Returns singleton instance for the given BrowserContext, or nullptr if the
// browser |context| is not allowed to use ARC.
static ArcKeyMintBridge* GetForBrowserContext(
content::BrowserContext* context);

ArcKeyMintBridge(content::BrowserContext* context,
ArcBridgeService* bridge_service);

ArcKeyMintBridge(const ArcKeyMintBridge&) = delete;
ArcKeyMintBridge& operator=(const ArcKeyMintBridge&) = delete;

~ArcKeyMintBridge() override;

// Return the factory instance for this class.
static BrowserContextKeyedServiceFactory* GetFactory();

// Update the list of placeholder keys to be instlaled in arc-keymasterd.
//
// Made virtual for override in tests.
virtual void UpdatePlaceholderKeys(
std::vector<keymint::mojom::ChromeOsKeyPtr> keys,
UpdatePlaceholderKeysCallback callback);
void UpdatePlaceholderKeysAfterBootstrap(
std::vector<keymint::mojom::ChromeOsKeyPtr> keys,
UpdatePlaceholderKeysCallback callback,
bool bootstrapResult);
// KeyMintHost mojo interface.
void GetServer(GetServerCallback callback) override;

private:
using BootstrapMojoConnectionCallback = base::OnceCallback<void(bool)>;

void BootstrapMojoConnection(BootstrapMojoConnectionCallback callback);
void OnBootstrapMojoConnection(BootstrapMojoConnectionCallback callback,
bool bootstrapResult);
void GetServerAfterBootstrap(GetServerCallback callback,
bool bootstrapResult);

ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager.
//
// Points to a proxy bound to the implementation in arc-keymintd.
mojo::Remote<mojom::keymint::KeyMintServer> keymint_server_proxy_;

// Points to the host implementation in Chrome, used to interact with the
// arc-keymintd daemon.
std::unique_ptr<keymint::CertStoreBridgeKeyMint> cert_store_bridge_;

// WeakPtrFactory to use for callbacks.
base::WeakPtrFactory<ArcKeyMintBridge> weak_factory_;
};

} // namespace arc

#endif // CHROME_BROWSER_ASH_ARC_KEYMINT_ARC_KEYMINT_BRIDGE_H_
64 changes: 64 additions & 0 deletions chrome/browser/ash/arc/keymint/cert_store_bridge_keymint.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ash/arc/keymint/cert_store_bridge_keymint.h"

#include <cstdint>
#include <utility>

#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/logging.h"
#include "mojo/core/embedder/embedder.h"
#include "mojo/public/cpp/bindings/pending_remote.h"

namespace arc::keymint {

CertStoreBridgeKeyMint::CertStoreBridgeKeyMint(content::BrowserContext* context)
: weak_ptr_factory_(this) {}

CertStoreBridgeKeyMint::~CertStoreBridgeKeyMint() = default;

void CertStoreBridgeKeyMint::UpdatePlaceholderKeysInKeyMint(
std::vector<mojom::ChromeOsKeyPtr> keys,
mojom::CertStoreInstance::UpdatePlaceholderKeysCallback callback) {
if (cert_store_proxy_.is_bound()) {
cert_store_proxy_->UpdatePlaceholderKeys(std::move(keys),
std::move(callback));
} else {
LOG(ERROR) << "Tried to update placeholders but cert store is not bound";
std::move(callback).Run(/*success=*/false);
}
}

bool CertStoreBridgeKeyMint::IsProxyBound() const {
return cert_store_proxy_.is_bound();
}

void CertStoreBridgeKeyMint::BindToInvitation(
mojo::OutgoingInvitation* invitation) {
VLOG(2) << "CertStoreBridgeKeyMint::BootstrapMojoConnection";

mojo::ScopedMessagePipeHandle pipe;
if (mojo::core::IsMojoIpczEnabled()) {
constexpr uint64_t kCertStorePipeAttachment = 1;
pipe = invitation->AttachMessagePipe(kCertStorePipeAttachment);
} else {
pipe = invitation->AttachMessagePipe("arc-cert-store-keymint-pipe");
}

if (!pipe.is_valid()) {
LOG(ERROR) << "CertStoreBridgeKeyMint could not bind to invitation";
return;
}

cert_store_proxy_.Bind(mojo::PendingRemote<keymint::mojom::CertStoreInstance>(
std::move(pipe), 0u));
VLOG(2) << "Bound remote CertStoreInstance interface to pipe.";
cert_store_proxy_.set_disconnect_handler(
base::BindOnce(&mojo::Remote<keymint::mojom::CertStoreInstance>::reset,
base::Unretained(&cert_store_proxy_)));
}

} // namespace arc::keymint

0 comments on commit 215bdb1

Please sign in to comment.