| // Copyright 2021 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/crosapi/content_protection_ash.h" |
| |
| #include "ash/display/output_protection_delegate.h" |
| #include "chrome/browser/ash/crosapi/window_util.h" |
| #include "chrome/browser/ash/settings/cros_settings.h" |
| #include "chromeos/ash/components/cryptohome/system_salt_getter.h" |
| #include "chromeos/ash/components/settings/cros_settings_names.h" |
| #include "components/user_manager/user_manager.h" |
| |
| namespace crosapi { |
| |
| ContentProtectionAsh::ContentProtectionAsh() = default; |
| ContentProtectionAsh::~ContentProtectionAsh() { |
| for (auto& pair : output_protection_delegates_) { |
| pair.first->RemoveObserver(this); |
| } |
| } |
| |
| void ContentProtectionAsh::BindReceiver( |
| mojo::PendingReceiver<mojom::ContentProtection> pending_receiver) { |
| receivers_.Add(this, std::move(pending_receiver)); |
| } |
| |
| ash::OutputProtectionDelegate* |
| ContentProtectionAsh::FindOrCreateOutputProtectionDelegate( |
| aura::Window* window) { |
| auto it = output_protection_delegates_.find(window); |
| if (it != output_protection_delegates_.end()) |
| return it->second.get(); |
| |
| auto delegate = std::make_unique<ash::OutputProtectionDelegate>(window); |
| ash::OutputProtectionDelegate* ptr = delegate.get(); |
| output_protection_delegates_[window] = std::move(delegate); |
| window->AddObserver(this); |
| return ptr; |
| } |
| |
| void ContentProtectionAsh::EnableWindowProtection( |
| const std::string& window_id, |
| uint32_t desired_protection_mask, |
| EnableWindowProtectionCallback callback) { |
| aura::Window* window = crosapi::GetShellSurfaceWindow(window_id); |
| if (!window) { |
| std::move(callback).Run(/*success=*/false); |
| return; |
| } |
| |
| ash::OutputProtectionDelegate* delegate = |
| FindOrCreateOutputProtectionDelegate(window); |
| delegate->SetProtection(desired_protection_mask, std::move(callback)); |
| } |
| |
| void ContentProtectionAsh::QueryWindowStatus( |
| const std::string& window_id, |
| QueryWindowStatusCallback callback) { |
| aura::Window* window = crosapi::GetShellSurfaceWindow(window_id); |
| if (!window) { |
| ExecuteWindowStatusCallback(std::move(callback), /*success=*/false, |
| /*link_mask=*/0, |
| /*protection_mask=*/0); |
| return; |
| } |
| |
| ash::OutputProtectionDelegate* delegate = |
| FindOrCreateOutputProtectionDelegate(window); |
| delegate->QueryStatus( |
| base::BindOnce(&ContentProtectionAsh::ExecuteWindowStatusCallback, |
| weak_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void ContentProtectionAsh::GetSystemSalt(GetSystemSaltCallback callback) { |
| ash::SystemSaltGetter::Get()->GetSystemSalt(std::move(callback)); |
| } |
| |
| void ContentProtectionAsh::ChallengePlatform( |
| const std::string& service_id, |
| const std::string& challenge, |
| ChallengePlatformCallback callback) { |
| // Remote attestation requires a cryptohome user. Since Lacros knows nothing |
| // about cryptohome, we always choose to use the primary logged in user. |
| user_manager::UserManager* user_manager = user_manager::UserManager::Get(); |
| const user_manager::User* user = user_manager->GetPrimaryUser(); |
| if (!user) { |
| std::move(callback).Run(nullptr); |
| return; |
| } |
| |
| if (!platform_verification_flow_) { |
| platform_verification_flow_ = |
| base::MakeRefCounted<ash::attestation::PlatformVerificationFlow>(); |
| } |
| |
| platform_verification_flow_->ChallengePlatformKey( |
| user, service_id, challenge, |
| base::BindOnce(&ContentProtectionAsh::OnChallengePlatform, |
| weak_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void ContentProtectionAsh::IsVerifiedAccessEnabled( |
| IsVerifiedAccessEnabledCallback callback) { |
| bool enabled_for_device = false; |
| ash::CrosSettings::Get()->GetBoolean( |
| ash::kAttestationForContentProtectionEnabled, &enabled_for_device); |
| std::move(callback).Run(enabled_for_device); |
| } |
| |
| void ContentProtectionAsh::OnWindowDestroyed(aura::Window* window) { |
| output_protection_delegates_.erase(window); |
| // No need to call window->RemoveObserver() since Window* handles that before |
| // calling this method. |
| } |
| |
| void ContentProtectionAsh::ExecuteWindowStatusCallback( |
| QueryWindowStatusCallback callback, |
| bool success, |
| uint32_t link_mask, |
| uint32_t protection_mask) { |
| if (success) { |
| mojom::ContentProtectionWindowStatusPtr status = |
| mojom::ContentProtectionWindowStatus::New(); |
| status->link_mask = link_mask; |
| status->protection_mask = protection_mask; |
| std::move(callback).Run(std::move(status)); |
| } else { |
| std::move(callback).Run(nullptr); |
| } |
| } |
| |
| void ContentProtectionAsh::OnChallengePlatform( |
| ChallengePlatformCallback callback, |
| ash::attestation::PlatformVerificationFlow::Result result, |
| const std::string& signed_data, |
| const std::string& signature, |
| const std::string& platform_key_certificate) { |
| if (result != ash::attestation::PlatformVerificationFlow::SUCCESS) { |
| std::move(callback).Run(nullptr); |
| return; |
| } |
| |
| mojom::ChallengePlatformResultPtr output = |
| mojom::ChallengePlatformResult::New(); |
| output->signed_data = signed_data; |
| output->signed_data_signature = signature; |
| output->platform_key_certificate = platform_key_certificate; |
| std::move(callback).Run(std::move(output)); |
| } |
| |
| } // namespace crosapi |