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(), |