Commit de25c91f authored by dkrahn@chromium.org's avatar dkrahn@chromium.org

Added prefs for content protection attestation.

The prefs are integrated into the PlatformVerificationFlow class.

BUG=chromium:270316
TEST=unit

Review URL: https://chromiumcodereview.appspot.com/23765004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@221614 0039d316-1c4b-4281-b951-d872f2087c98
parent 8609621a
......@@ -5,14 +5,19 @@
#include "platform_verification_flow.h"
#include "base/logging.h"
#include "base/prefs/pref_service.h"
#include "chrome/browser/chromeos/attestation/attestation_ca_client.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/chromeos/system/statistics_provider.h"
#include "chrome/browser/prefs/scoped_user_pref_update.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/user_prefs/pref_registry_syncable.h"
#include "components/user_prefs/user_prefs.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
......@@ -60,7 +65,7 @@ void PlatformVerificationFlow::ChallengePlatformKey(
const std::string& challenge,
const ChallengeCallback& callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if (delegate_->IsAttestationDisabled()) {
if (!IsAttestationEnabled(web_contents)) {
LOG(INFO) << "PlatformVerificationFlow: Feature disabled.";
callback.Run(POLICY_REJECTED, std::string(), std::string());
return;
......@@ -105,11 +110,9 @@ void PlatformVerificationFlow::CheckConsent(content::WebContents* web_contents,
const ChallengeCallback& callback,
bool attestation_enrolled) {
ConsentType consent_type = CONSENT_TYPE_NONE;
if (!attestation_enrolled) {
if (!attestation_enrolled || IsFirstUse(web_contents)) {
consent_type = CONSENT_TYPE_ATTESTATION;
} else if (delegate_->IsOriginConsentRequired(web_contents)) {
consent_type = CONSENT_TYPE_ORIGIN;
} else if (delegate_->IsAlwaysAskRequired(web_contents)) {
} else if (IsAlwaysAskRequired(web_contents)) {
consent_type = CONSENT_TYPE_ALWAYS;
}
Delegate::ConsentCallback consent_callback = base::Bind(
......@@ -129,6 +132,19 @@ void PlatformVerificationFlow::CheckConsent(content::WebContents* web_contents,
}
}
void PlatformVerificationFlow::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* prefs) {
prefs->RegisterBooleanPref(prefs::kRAConsentFirstTime,
false,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
prefs->RegisterDictionaryPref(
prefs::kRAConsentDomains,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
prefs->RegisterBooleanPref(prefs::kRAConsentAlways,
false,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
}
void PlatformVerificationFlow::OnConsentResponse(
content::WebContents* web_contents,
const std::string& service_id,
......@@ -143,9 +159,7 @@ void PlatformVerificationFlow::OnConsentResponse(
callback.Run(USER_REJECTED, std::string(), std::string());
return;
}
if (!delegate_->UpdateSettings(web_contents,
consent_type,
consent_response)) {
if (!UpdateSettings(web_contents, consent_type, consent_response)) {
callback.Run(INTERNAL_ERROR, std::string(), std::string());
return;
}
......@@ -210,5 +224,130 @@ void PlatformVerificationFlow::OnChallengeReady(
callback.Run(SUCCESS, response_data, certificate);
}
PrefService* PlatformVerificationFlow::GetPrefs(
content::WebContents* web_contents) {
if (testing_prefs_)
return testing_prefs_;
return user_prefs::UserPrefs::Get(web_contents->GetBrowserContext());
}
const GURL& PlatformVerificationFlow::GetURL(
content::WebContents* web_contents) {
if (!testing_url_.is_empty())
return testing_url_;
return web_contents->GetLastCommittedURL();
}
bool PlatformVerificationFlow::IsAttestationEnabled(
content::WebContents* web_contents) {
// Check the device policy for the feature.
bool enabled_for_device = false;
if (!CrosSettings::Get()->GetBoolean(kAttestationForContentProtectionEnabled,
&enabled_for_device)) {
LOG(ERROR) << "Failed to get device setting.";
return false;
}
if (!enabled_for_device)
return false;
// Check the user preference for the feature.
PrefService* pref_service = GetPrefs(web_contents);
if (!pref_service) {
LOG(ERROR) << "Failed to get user prefs.";
return false;
}
if (!pref_service->GetBoolean(prefs::kEnableDRM))
return false;
// Check the user preference for this domain.
bool enabled_for_domain = false;
bool found = GetDomainPref(web_contents, &enabled_for_domain);
return (!found || enabled_for_domain);
}
bool PlatformVerificationFlow::IsFirstUse(content::WebContents* web_contents) {
PrefService* pref_service = GetPrefs(web_contents);
if (!pref_service) {
LOG(ERROR) << "Failed to get user prefs.";
return true;
}
return !pref_service->GetBoolean(prefs::kRAConsentFirstTime);
}
bool PlatformVerificationFlow::IsAlwaysAskRequired(
content::WebContents* web_contents) {
PrefService* pref_service = GetPrefs(web_contents);
if (!pref_service) {
LOG(ERROR) << "Failed to get user prefs.";
return true;
}
if (!pref_service->GetBoolean(prefs::kRAConsentAlways))
return false;
// Show the consent UI if the user has not already explicitly allowed or
// denied for this domain.
return !GetDomainPref(web_contents, NULL);
}
bool PlatformVerificationFlow::UpdateSettings(
content::WebContents* web_contents,
ConsentType consent_type,
ConsentResponse consent_response) {
PrefService* pref_service = GetPrefs(web_contents);
if (!pref_service) {
LOG(ERROR) << "Failed to get user prefs.";
return false;
}
if (consent_type == CONSENT_TYPE_ATTESTATION) {
if (consent_response == CONSENT_RESPONSE_DENY) {
pref_service->SetBoolean(prefs::kEnableDRM, false);
} else if (consent_response == CONSENT_RESPONSE_ALLOW) {
pref_service->SetBoolean(prefs::kRAConsentFirstTime, true);
RecordDomainConsent(web_contents, true);
} else if (consent_response == CONSENT_RESPONSE_ALWAYS_ASK) {
pref_service->SetBoolean(prefs::kRAConsentFirstTime, true);
pref_service->SetBoolean(prefs::kRAConsentAlways, true);
RecordDomainConsent(web_contents, true);
}
} else if (consent_type == CONSENT_TYPE_ALWAYS) {
bool allowed = (consent_response == CONSENT_RESPONSE_ALLOW ||
consent_response == CONSENT_RESPONSE_ALWAYS_ASK);
RecordDomainConsent(web_contents, allowed);
}
return true;
}
bool PlatformVerificationFlow::GetDomainPref(
content::WebContents* web_contents,
bool* pref_value) {
PrefService* pref_service = GetPrefs(web_contents);
CHECK(pref_service);
base::DictionaryValue::Iterator iter(
*pref_service->GetDictionary(prefs::kRAConsentDomains));
const GURL& url = GetURL(web_contents);
while (!iter.IsAtEnd()) {
if (url.DomainIs(iter.key().c_str())) {
if (pref_value) {
if (!iter.value().GetAsBoolean(pref_value)) {
LOG(ERROR) << "Unexpected pref type.";
*pref_value = false;
}
}
return true;
}
iter.Advance();
}
return false;
}
void PlatformVerificationFlow::RecordDomainConsent(
content::WebContents* web_contents,
bool allow_domain) {
PrefService* pref_service = GetPrefs(web_contents);
CHECK(pref_service);
DictionaryPrefUpdate updater(pref_service, prefs::kRAConsentDomains);
const GURL& url = GetURL(web_contents);
updater->SetBoolean(url.host(), allow_domain);
}
} // namespace attestation
} // namespace chromeos
......@@ -11,6 +11,9 @@
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "url/gurl.h"
class PrefService;
namespace content {
class WebContents;
......@@ -20,6 +23,10 @@ namespace cryptohome {
class AsyncMethodCaller;
}
namespace user_prefs {
class PrefRegistrySyncable;
}
namespace chromeos {
class CryptohomeClient;
......@@ -54,7 +61,6 @@ class PlatformVerificationFlow {
enum ConsentType {
CONSENT_TYPE_NONE, // No consent necessary.
CONSENT_TYPE_ATTESTATION, // Consent to use attestation.
CONSENT_TYPE_ORIGIN, // Consent to proceed with an unfamiliar origin.
CONSENT_TYPE_ALWAYS, // Consent because 'Always Ask' was requested.
};
......@@ -80,23 +86,6 @@ class PlatformVerificationFlow {
virtual void ShowConsentPrompt(ConsentType type,
content::WebContents* web_contents,
const ConsentCallback& callback) = 0;
// Returns true if settings indicate that attestation should be disabled.
virtual bool IsAttestationDisabled() = 0;
// Checks if the web origin represented by |web_contents| is unfamiliar and
// requires special user consent.
virtual bool IsOriginConsentRequired(
content::WebContents* web_contents) = 0;
// Checks if settings indicate that consent is required for the web origin
// represented by |web_contents| because the user requested to be prompted.
virtual bool IsAlwaysAskRequired(content::WebContents* web_contents) = 0;
// Updates user settings based on their response to the consent request.
virtual bool UpdateSettings(content::WebContents* web_contents,
ConsentType consent_type,
ConsentResponse consent_response) = 0;
};
// This callback will be called when a challenge operation completes. If
......@@ -150,6 +139,16 @@ class PlatformVerificationFlow {
// or false. If an error occurs, |result| will be false.
void CheckPlatformState(const base::Callback<void(bool result)>& callback);
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* prefs);
void set_testing_prefs(PrefService* testing_prefs) {
testing_prefs_ = testing_prefs;
}
void set_testing_url(const GURL& testing_url) {
testing_url_ = testing_url;
}
private:
// Checks whether we need to prompt the user for consent before proceeding and
// invokes the consent UI if so. All parameters are the same as in
......@@ -196,6 +195,47 @@ class PlatformVerificationFlow {
bool operation_success,
const std::string& response_data);
// Gets prefs associated with the given |web_contents|. If prefs have been
// set explicitly using set_testing_prefs(), then these are always returned.
// If no prefs are associated with |web_contents| then NULL is returned.
PrefService* GetPrefs(content::WebContents* web_contents);
// Gets the URL associated with the given |web_contents|. If a URL as been
// set explicitly using set_testing_url(), then this value is always returned.
const GURL& GetURL(content::WebContents* web_contents);
// Checks whether policy or profile settings associated with |web_contents|
// have attestation for content protection explicitly disabled.
bool IsAttestationEnabled(content::WebContents* web_contents);
// Checks whether this is the first use on this device for the user associated
// with |web_contents|.
bool IsFirstUse(content::WebContents* web_contents);
// Checks if settings indicate that consent is required for the web origin
// represented by |web_contents| because the user requested to be prompted.
bool IsAlwaysAskRequired(content::WebContents* web_contents);
// Updates user settings for the profile associated with |web_contents| based
// on the |consent_response| to the request of type |consent_type|.
bool UpdateSettings(content::WebContents* web_contents,
ConsentType consent_type,
ConsentResponse consent_response);
// Finds the domain-specific consent pref for the domain associated with
// |web_contents|. If a pref exists for the domain, returns true and sets
// |pref_value| if it is not NULL.
//
// Precondition: A valid PrefService must be available via GetPrefs().
bool GetDomainPref(content::WebContents* web_contents, bool* pref_value);
// Records the domain-specific consent pref for the domain associated with
// |web_contents|. The pref will be set to |allow_domain|.
//
// Precondition: A valid PrefService must be available via GetPrefs().
void RecordDomainConsent(content::WebContents* web_contents,
bool allow_domain);
AttestationFlow* attestation_flow_;
scoped_ptr<AttestationFlow> default_attestation_flow_;
cryptohome::AsyncMethodCaller* async_caller_;
......@@ -204,6 +244,8 @@ class PlatformVerificationFlow {
system::StatisticsProvider* statistics_provider_;
Delegate* delegate_;
scoped_ptr<Delegate> default_delegate_;
PrefService* testing_prefs_;
GURL testing_url_;
// Note: This should remain the last member so it'll be destroyed and
// invalidate the weak pointers before any other members are destroyed.
......
......@@ -149,8 +149,6 @@ class Preferences : public PrefServiceSyncableObserver,
IntegerPrefMember xkb_auto_repeat_delay_pref_;
IntegerPrefMember xkb_auto_repeat_interval_pref_;
BooleanPrefMember enable_drm_;
DISALLOW_COPY_AND_ASSIGN(Preferences);
};
......
......@@ -125,6 +125,7 @@
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
#include "chrome/browser/chromeos/attestation/platform_verification_flow.h"
#include "chrome/browser/chromeos/audio/audio_devices_pref_handler_impl.h"
#include "chrome/browser/chromeos/customization_document.h"
#include "chrome/browser/chromeos/display/display_preferences.h"
......@@ -387,12 +388,14 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
#endif
#if defined(OS_CHROMEOS)
chromeos::attestation::PlatformVerificationFlow::RegisterProfilePrefs(
registry);
chromeos::Preferences::RegisterProfilePrefs(registry);
chromeos::proxy_config::RegisterProfilePrefs(registry);
chromeos::UserImageSyncObserver::RegisterProfilePrefs(registry);
extensions::EnterprisePlatformKeysPrivateChallengeUserKeyFunction::
RegisterProfilePrefs(registry);
FlagsUI::RegisterProfilePrefs(registry);
chromeos::UserImageSyncObserver::RegisterProfilePrefs(registry);
#endif
#if defined(OS_WIN)
......
......@@ -65,8 +65,6 @@ bool DeviceIDFetcher::Start(const IDCallback& callback) {
// static
void DeviceIDFetcher::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* prefs) {
// TODO(wad): Once UI is connected, a final default can be set. At that point
// change this pref from UNSYNCABLE to SYNCABLE.
prefs->RegisterBooleanPref(prefs::kEnableDRM,
true,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
......
......@@ -936,6 +936,16 @@ const char kTouchHudProjectionEnabled[] = "touch_hud.projection_enabled";
// Currently, this pref is only used to store the policy. The user's
// configuration is still stored in Shill.
const char kOpenNetworkConfiguration[] = "onc";
// A boolean pref that tracks whether the user has already given consent for
// enabling remote attestation for content protection.
const char kRAConsentFirstTime[] = "settings.privacy.ra_consent";
// A DictionaryValue pref that tracks domains for which the user has explicitly
// allowed or denied.
const char kRAConsentDomains[] = "settings.privacy.ra_consent_domains";
// A boolean pref that tracks whether the user indicated they wish to be asked
// for consent for every site that uses remote attestation.
const char kRAConsentAlways[] = "settings.privacy.ra_consent_always";
#endif // defined(OS_CHROMEOS)
// The disabled messages in IPC logging.
......@@ -2577,7 +2587,8 @@ extern const char kModuleConflictBubbleShown[] = "module_conflict.bubble_shown";
// A string pref for storing the salt used to compute the pepper device ID.
const char kDRMSalt[] = "settings.privacy.drm_salt";
// A boolean pref that enables the (private) pepper GetDeviceID() call.
// A boolean pref that enables the (private) pepper GetDeviceID() call and
// enables the use of remote attestation for content protection.
const char kEnableDRM[] = "settings.privacy.drm_enabled";
// A boolean per-profile pref that signals if the watchdog extension is
......
......@@ -328,6 +328,9 @@ extern const char kAttestationEnabled[];
extern const char kAttestationExtensionWhitelist[];
extern const char kTouchHudProjectionEnabled[];
extern const char kOpenNetworkConfiguration[];
extern const char kRAConsentFirstTime[];
extern const char kRAConsentDomains[];
extern const char kRAConsentAlways[];
#endif // defined(OS_CHROMEOS)
extern const char kIpcDisabledMessages[];
extern const char kShowHomeButton[];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment