| Index: chrome/browser/chromeos/attestation/platform_verification_flow.cc
|
| diff --git a/chrome/browser/chromeos/attestation/platform_verification_flow.cc b/chrome/browser/chromeos/attestation/platform_verification_flow.cc
|
| index 5e03617a663ee3926ee42e0cdc02ae352d4a3695..a1db8b0ab665b241d66fba6db443361ce1834509 100644
|
| --- a/chrome/browser/chromeos/attestation/platform_verification_flow.cc
|
| +++ b/chrome/browser/chromeos/attestation/platform_verification_flow.cc
|
| @@ -8,27 +8,27 @@
|
| #include "base/logging.h"
|
| #include "base/message_loop/message_loop.h"
|
| #include "base/metrics/histogram.h"
|
| -#include "base/prefs/pref_service.h"
|
| #include "base/time/time.h"
|
| #include "base/timer/timer.h"
|
| #include "chrome/browser/chromeos/attestation/attestation_ca_client.h"
|
| #include "chrome/browser/chromeos/attestation/attestation_signed_data.pb.h"
|
| -#include "chrome/browser/chromeos/attestation/platform_verification_dialog.h"
|
| #include "chrome/browser/chromeos/profiles/profile_helper.h"
|
| #include "chrome/browser/chromeos/settings/cros_settings.h"
|
| +#include "chrome/browser/media/protected_media_identifier_permission_context.h"
|
| +#include "chrome/browser/media/protected_media_identifier_permission_context_factory.h"
|
| #include "chrome/browser/profiles/profile.h"
|
| -#include "chrome/common/pref_names.h"
|
| #include "chromeos/attestation/attestation_flow.h"
|
| #include "chromeos/cryptohome/async_method_caller.h"
|
| #include "chromeos/dbus/cryptohome_client.h"
|
| #include "chromeos/dbus/dbus_thread_manager.h"
|
| #include "components/content_settings/core/browser/host_content_settings_map.h"
|
| #include "components/content_settings/core/common/content_settings_pattern.h"
|
| -#include "components/pref_registry/pref_registry_syncable.h"
|
| +#include "components/content_settings/core/common/permission_request_id.h"
|
| #include "components/user_manager/user.h"
|
| -#include "components/user_prefs/user_prefs.h"
|
| #include "content/public/browser/browser_context.h"
|
| #include "content/public/browser/browser_thread.h"
|
| +#include "content/public/browser/render_process_host.h"
|
| +#include "content/public/browser/render_view_host.h"
|
| #include "content/public/browser/user_metrics.h"
|
| #include "content/public/browser/web_contents.h"
|
| #include "content/public/common/url_constants.h"
|
| @@ -36,7 +36,6 @@
|
|
|
| namespace {
|
|
|
| -const char kDefaultHttpsPort[] = "443";
|
| const int kTimeoutInSeconds = 8;
|
| const char kAttestationResultHistogram[] =
|
| "ChromeOS.PlatformVerification.Result";
|
| @@ -77,19 +76,6 @@ class DefaultDelegate : public PlatformVerificationFlow::Delegate {
|
| DefaultDelegate() {}
|
| ~DefaultDelegate() override {}
|
|
|
| - void ShowConsentPrompt(
|
| - content::WebContents* web_contents,
|
| - const GURL& requesting_origin,
|
| - const PlatformVerificationFlow::Delegate::ConsentCallback& callback)
|
| - override {
|
| - PlatformVerificationDialog::ShowDialog(web_contents, requesting_origin,
|
| - callback);
|
| - }
|
| -
|
| - PrefService* GetPrefs(content::WebContents* web_contents) override {
|
| - return user_prefs::UserPrefs::Get(web_contents->GetBrowserContext());
|
| - }
|
| -
|
| const GURL& GetURL(content::WebContents* web_contents) override {
|
| const GURL& url = web_contents->GetLastCommittedURL();
|
| if (!url.is_valid())
|
| @@ -103,10 +89,22 @@ class DefaultDelegate : public PlatformVerificationFlow::Delegate {
|
| Profile::FromBrowserContext(web_contents->GetBrowserContext()));
|
| }
|
|
|
| - HostContentSettingsMap* GetContentSettings(
|
| - content::WebContents* web_contents) override {
|
| - return Profile::FromBrowserContext(web_contents->GetBrowserContext())->
|
| - GetHostContentSettingsMap();
|
| + bool IsPermittedByUser(content::WebContents* web_contents) override {
|
| + ProtectedMediaIdentifierPermissionContext* permission_context =
|
| + ProtectedMediaIdentifierPermissionContextFactory::GetForProfile(
|
| + Profile::FromBrowserContext(web_contents->GetBrowserContext()));
|
| +
|
| + // TODO(xhwang): Using delegate_->GetURL() here is not right. The platform
|
| + // verification may be requested by a frame from a different origin. This
|
| + // will be solved when http://crbug.com/454847 is fixed.
|
| + const GURL& requesting_origin = GetURL(web_contents).GetOrigin();
|
| +
|
| + GURL embedding_origin = web_contents->GetLastCommittedURL().GetOrigin();
|
| +
|
| + ContentSetting content_setting = permission_context->GetPermissionStatus(
|
| + requesting_origin, embedding_origin);
|
| +
|
| + return content_setting == CONTENT_SETTING_ALLOW;
|
| }
|
|
|
| bool IsGuestOrIncognito(content::WebContents* web_contents) override {
|
| @@ -174,129 +172,61 @@ void PlatformVerificationFlow::ChallengePlatformKey(
|
| const std::string& challenge,
|
| const ChallengeCallback& callback) {
|
| DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| +
|
| if (!delegate_->GetURL(web_contents).is_valid()) {
|
| LOG(WARNING) << "PlatformVerificationFlow: Invalid URL.";
|
| ReportError(callback, INTERNAL_ERROR);
|
| return;
|
| }
|
| - if (!IsAttestationEnabled(web_contents)) {
|
| +
|
| + // Note: The following two checks are also checked in GetPermissionStatus.
|
| + // Checking them here explicitly to report the correct error type.
|
| +
|
| + if (!IsAttestationAllowedByPolicy()) {
|
| + VLOG(1) << "Platform verification not allowed by device policy.";
|
| ReportError(callback, POLICY_REJECTED);
|
| return;
|
| }
|
| - // A platform key must be bound to a user. They are not allowed in incognito
|
| +
|
| + // A platform key must be bound to a user. They are not allowed in incognito
|
| // or guest mode.
|
| + // TODO(xhwang): Change to DCHECK when prefixed EME support is removed.
|
| + // See http://crbug.com/249976
|
| if (delegate_->IsGuestOrIncognito(web_contents)) {
|
| VLOG(1) << "Platform verification denied because the current session is "
|
| << "guest or incognito.";
|
| ReportError(callback, PLATFORM_NOT_VERIFIED);
|
| return;
|
| }
|
| +
|
| + if (!delegate_->IsPermittedByUser(web_contents)) {
|
| + VLOG(1) << "Platform verification not permitted by user.";
|
| + ReportError(callback, USER_REJECTED);
|
| + return;
|
| + }
|
| +
|
| ChallengeContext context(web_contents, service_id, challenge, callback);
|
| // Check if the device has been prepared to use attestation.
|
| - BoolDBusMethodCallback dbus_callback = base::Bind(
|
| - &DBusCallback,
|
| - base::Bind(&PlatformVerificationFlow::CheckEnrollment, this, context),
|
| - base::Bind(&ReportError, callback, INTERNAL_ERROR));
|
| + BoolDBusMethodCallback dbus_callback =
|
| + base::Bind(&DBusCallback,
|
| + base::Bind(&PlatformVerificationFlow::OnAttestationPrepared,
|
| + this, context),
|
| + base::Bind(&ReportError, callback, INTERNAL_ERROR));
|
| cryptohome_client_->TpmAttestationIsPrepared(dbus_callback);
|
| }
|
|
|
| -void PlatformVerificationFlow::CheckEnrollment(const ChallengeContext& context,
|
| - bool attestation_prepared) {
|
| +void PlatformVerificationFlow::OnAttestationPrepared(
|
| + const ChallengeContext& context,
|
| + bool attestation_prepared) {
|
| UMA_HISTOGRAM_BOOLEAN(kAttestationAvailableHistogram, attestation_prepared);
|
| +
|
| if (!attestation_prepared) {
|
| // This device is not currently able to use attestation features.
|
| ReportError(context.callback, PLATFORM_NOT_VERIFIED);
|
| return;
|
| }
|
| - BoolDBusMethodCallback dbus_callback = base::Bind(
|
| - &DBusCallback,
|
| - base::Bind(&PlatformVerificationFlow::CheckConsent, this, context),
|
| - base::Bind(&ReportError, context.callback, INTERNAL_ERROR));
|
| - cryptohome_client_->TpmAttestationIsEnrolled(dbus_callback);
|
| -}
|
| -
|
| -void PlatformVerificationFlow::CheckConsent(const ChallengeContext& context,
|
| - bool /* attestation_enrolled */) {
|
| - content::WebContents* web_contents = context.web_contents;
|
| -
|
| - bool enabled_for_origin = false;
|
| - bool found =
|
| - GetOriginPref(delegate_->GetContentSettings(web_contents),
|
| - delegate_->GetURL(web_contents), &enabled_for_origin);
|
| - if (found && !enabled_for_origin) {
|
| - VLOG(1) << "Platform verification denied because the origin has been "
|
| - << "blocked by the user.";
|
| - ReportError(context.callback, USER_REJECTED);
|
| - return;
|
| - }
|
| -
|
| - PrefService* pref_service = delegate_->GetPrefs(web_contents);
|
| - if (!pref_service) {
|
| - LOG(ERROR) << "Failed to get user prefs.";
|
| - ReportError(context.callback, INTERNAL_ERROR);
|
| - return;
|
| - }
|
| -
|
| - // Consent required if user has never given consent for this origin, or if
|
| - // user has never given consent to attestation for content protection on this
|
| - // device.
|
| - bool consent_required =
|
| - !found || !pref_service->GetBoolean(prefs::kRAConsentGranted);
|
|
|
| - Delegate::ConsentCallback consent_callback = base::Bind(
|
| - &PlatformVerificationFlow::OnConsentResponse,
|
| - this,
|
| - context,
|
| - consent_required);
|
| - if (consent_required) {
|
| - // TODO(xhwang): Using delegate_->GetURL() here is not right. The consent
|
| - // may be requested by a frame from a different origin. This will be solved
|
| - // when http://crbug.com/454847 is fixed.
|
| - delegate_->ShowConsentPrompt(
|
| - context.web_contents,
|
| - delegate_->GetURL(context.web_contents).GetOrigin(), consent_callback);
|
| - } else {
|
| - consent_callback.Run(CONSENT_RESPONSE_NONE);
|
| - }
|
| -}
|
| -
|
| -void PlatformVerificationFlow::RegisterProfilePrefs(
|
| - user_prefs::PrefRegistrySyncable* prefs) {
|
| - prefs->RegisterBooleanPref(prefs::kRAConsentGranted,
|
| - false, // Default value.
|
| - user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
|
| -}
|
| -
|
| -void PlatformVerificationFlow::OnConsentResponse(
|
| - const ChallengeContext& context,
|
| - bool consent_required,
|
| - ConsentResponse consent_response) {
|
| - if (consent_required) {
|
| - if (consent_response == CONSENT_RESPONSE_NONE) {
|
| - // No user response - do not proceed and do not modify any settings.
|
| - LOG(WARNING) << "PlatformVerificationFlow: No response from user.";
|
| - ReportError(context.callback, USER_REJECTED);
|
| - return;
|
| - }
|
| - if (!UpdateSettings(context.web_contents, consent_response)) {
|
| - ReportError(context.callback, INTERNAL_ERROR);
|
| - return;
|
| - }
|
| - if (consent_response == CONSENT_RESPONSE_DENY) {
|
| - content::RecordAction(
|
| - base::UserMetricsAction("PlatformVerificationRejected"));
|
| - VLOG(1) << "Platform verification denied by user.";
|
| - ReportError(context.callback, USER_REJECTED);
|
| - return;
|
| - } else if (consent_response == CONSENT_RESPONSE_ALLOW) {
|
| - content::RecordAction(
|
| - base::UserMetricsAction("PlatformVerificationAccepted"));
|
| - VLOG(1) << "Platform verification accepted by user.";
|
| - }
|
| - }
|
| -
|
| - // At this point all user interaction is complete and we can proceed with the
|
| - // certificate request.
|
| + // Permission allowed. Now proceed to get certificate.
|
| const user_manager::User* user = delegate_->GetUser(context.web_contents);
|
| if (!user) {
|
| ReportError(context.callback, INTERNAL_ERROR);
|
| @@ -402,8 +332,7 @@ void PlatformVerificationFlow::OnChallengeReady(
|
| certificate);
|
| }
|
|
|
| -bool PlatformVerificationFlow::IsAttestationEnabled(
|
| - content::WebContents* web_contents) {
|
| +bool PlatformVerificationFlow::IsAttestationAllowedByPolicy() {
|
| // Check the device policy for the feature.
|
| bool enabled_for_device = false;
|
| if (!CrosSettings::Get()->GetBoolean(kAttestationForContentProtectionEnabled,
|
| @@ -417,102 +346,9 @@ bool PlatformVerificationFlow::IsAttestationEnabled(
|
| return false;
|
| }
|
|
|
| - // Check the user preference for the feature.
|
| - PrefService* pref_service = delegate_->GetPrefs(web_contents);
|
| - if (!pref_service) {
|
| - LOG(ERROR) << "Failed to get user prefs.";
|
| - return false;
|
| - }
|
| - if (!pref_service->GetBoolean(prefs::kEnableDRM)) {
|
| - VLOG(1) << "Platform verification denied because content protection "
|
| - << "identifiers have been disabled by the user.";
|
| - return false;
|
| - }
|
| -
|
| - // Check the user preference for this origin.
|
| - bool enabled_for_origin = false;
|
| - bool found =
|
| - GetOriginPref(delegate_->GetContentSettings(web_contents),
|
| - delegate_->GetURL(web_contents), &enabled_for_origin);
|
| - if (found && !enabled_for_origin) {
|
| - VLOG(1) << "Platform verification denied because the origin has been "
|
| - << "blocked by the user.";
|
| - return false;
|
| - }
|
| return true;
|
| }
|
|
|
| -bool PlatformVerificationFlow::UpdateSettings(
|
| - content::WebContents* web_contents,
|
| - ConsentResponse consent_response) {
|
| - PrefService* pref_service = delegate_->GetPrefs(web_contents);
|
| - if (!pref_service) {
|
| - LOG(ERROR) << "Failed to get user prefs.";
|
| - return false;
|
| - }
|
| -
|
| - if (consent_response == CONSENT_RESPONSE_ALLOW) {
|
| - pref_service->SetBoolean(prefs::kRAConsentGranted, true);
|
| - }
|
| -
|
| - RecordOriginConsent(delegate_->GetContentSettings(web_contents),
|
| - delegate_->GetURL(web_contents),
|
| - (consent_response == CONSENT_RESPONSE_ALLOW));
|
| - return true;
|
| -}
|
| -
|
| -bool PlatformVerificationFlow::GetOriginPref(
|
| - HostContentSettingsMap* content_settings,
|
| - const GURL& url,
|
| - bool* pref_value) {
|
| - CHECK(content_settings);
|
| - CHECK(url.is_valid());
|
| - ContentSetting setting = content_settings->GetContentSetting(
|
| - url,
|
| - url,
|
| - CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER,
|
| - std::string());
|
| - if (setting != CONTENT_SETTING_ALLOW && setting != CONTENT_SETTING_BLOCK)
|
| - return false;
|
| - if (pref_value)
|
| - *pref_value = (setting == CONTENT_SETTING_ALLOW);
|
| - return true;
|
| -}
|
| -
|
| -void PlatformVerificationFlow::RecordOriginConsent(
|
| - HostContentSettingsMap* content_settings,
|
| - const GURL& url,
|
| - bool allow_origin) {
|
| - CHECK(content_settings);
|
| - CHECK(url.is_valid());
|
| - // Build a pattern to represent scheme and host.
|
| - scoped_ptr<ContentSettingsPattern::BuilderInterface> builder(
|
| - ContentSettingsPattern::CreateBuilder(false));
|
| - builder->WithScheme(url.scheme())
|
| - ->WithDomainWildcard()
|
| - ->WithHost(url.host())
|
| - ->WithPathWildcard();
|
| - if (!url.port().empty())
|
| - builder->WithPort(url.port());
|
| - else if (url.SchemeIs(url::kHttpsScheme))
|
| - builder->WithPort(kDefaultHttpsPort);
|
| - else if (url.SchemeIs(url::kHttpScheme))
|
| - builder->WithPortWildcard();
|
| - ContentSettingsPattern pattern = builder->Build();
|
| - if (pattern.IsValid()) {
|
| - ContentSetting setting =
|
| - allow_origin ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
|
| - content_settings->SetContentSetting(
|
| - pattern,
|
| - pattern,
|
| - CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER,
|
| - std::string(),
|
| - setting);
|
| - } else {
|
| - LOG(WARNING) << "Not recording action: invalid URL pattern";
|
| - }
|
| -}
|
| -
|
| bool PlatformVerificationFlow::IsExpired(const std::string& certificate) {
|
| scoped_refptr<net::X509Certificate> x509(
|
| net::X509Certificate::CreateFromBytes(certificate.data(),
|
|
|