Skip to content

Commit

Permalink
Added multi-profile support for attestation on chromeos.
Browse files Browse the repository at this point in the history
All certified keys and certificates will be associated with the correct
profile when multiple profiles are used.

BUG=chromium:205206
TEST=unit, manual

Review URL: https://codereview.chromium.org/27044004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@229891 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
dkrahn@chromium.org committed Oct 21, 2013
1 parent 903a1f4 commit 1260076
Show file tree
Hide file tree
Showing 23 changed files with 285 additions and 112 deletions.
1 change: 1 addition & 0 deletions chrome/browser/chromeos/attestation/OWNERS
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
mnissler@chromium.org
pastarmovj@chromium.org
bartfab@chromium.org
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ void AttestationPolicyObserver::Start() {
weak_factory_.GetWeakPtr());
cryptohome_client_->TpmAttestationDoesKeyExist(
KEY_DEVICE,
std::string(), // Not used.
kEnterpriseMachineKey,
base::Bind(DBusBoolRedirectCallback,
on_does_exist,
Expand Down Expand Up @@ -198,6 +199,7 @@ void AttestationPolicyObserver::GetNewCertificate() {
void AttestationPolicyObserver::GetExistingCertificate() {
cryptohome_client_->TpmAttestationGetCertificate(
KEY_DEVICE,
std::string(), // Not used.
kEnterpriseMachineKey,
base::Bind(DBusStringCallback,
base::Bind(&AttestationPolicyObserver::CheckCertificateExpiry,
Expand Down Expand Up @@ -255,6 +257,7 @@ void AttestationPolicyObserver::GetKeyPayload(
base::Callback<void(const std::string&)> callback) {
cryptohome_client_->TpmAttestationGetKeyPayload(
KEY_DEVICE,
std::string(), // Not used.
kEnterpriseMachineKey,
base::Bind(DBusStringCallback,
callback,
Expand Down Expand Up @@ -283,6 +286,7 @@ void AttestationPolicyObserver::MarkAsUploaded(const std::string& key_payload) {
}
cryptohome_client_->TpmAttestationSetKeyPayload(
KEY_DEVICE,
std::string(), // Not used.
kEnterpriseMachineKey,
new_payload,
base::Bind(DBusBoolRedirectCallback,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,20 +148,20 @@ class AttestationPolicyObserverTest : public ::testing::Test {
bool key_exists = (mock_options & MOCK_KEY_EXISTS);
// Setup expected key / cert queries.
if (key_exists) {
EXPECT_CALL(cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _))
.WillRepeatedly(WithArgs<2>(Invoke(DBusCallbackTrue)));
EXPECT_CALL(cryptohome_client_, TpmAttestationGetCertificate(_, _, _))
.WillRepeatedly(WithArgs<2>(Invoke(FakeDBusData(certificate))));
EXPECT_CALL(cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
.WillRepeatedly(WithArgs<3>(Invoke(DBusCallbackTrue)));
EXPECT_CALL(cryptohome_client_, TpmAttestationGetCertificate(_, _, _, _))
.WillRepeatedly(WithArgs<3>(Invoke(FakeDBusData(certificate))));
} else {
EXPECT_CALL(cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _))
.WillRepeatedly(WithArgs<2>(Invoke(DBusCallbackFalse)));
EXPECT_CALL(cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
.WillRepeatedly(WithArgs<3>(Invoke(DBusCallbackFalse)));
}

// Setup expected key payload queries.
bool key_uploaded = (mock_options & MOCK_KEY_UPLOADED);
std::string payload = CreatePayload();
EXPECT_CALL(cryptohome_client_, TpmAttestationGetKeyPayload(_, _, _))
.WillRepeatedly(WithArgs<2>(Invoke(
EXPECT_CALL(cryptohome_client_, TpmAttestationGetKeyPayload(_, _, _, _))
.WillRepeatedly(WithArgs<3>(Invoke(
FakeDBusData(key_uploaded ? payload : ""))));

// Setup expected key uploads. Use WillOnce() so StrictMock will trigger an
Expand All @@ -175,8 +175,8 @@ class AttestationPolicyObserverTest : public ::testing::Test {
UploadCertificate(new_key ? "fake_cert" : certificate, _))
.WillOnce(WithArgs<1>(Invoke(StatusCallbackSuccess)));
EXPECT_CALL(cryptohome_client_,
TpmAttestationSetKeyPayload(_, _, payload, _))
.WillOnce(WithArgs<3>(Invoke(DBusCallbackTrue)));
TpmAttestationSetKeyPayload(_, _, _, payload, _))
.WillOnce(WithArgs<4>(Invoke(DBusCallbackTrue)));
}

// Setup expected key generations. Again use WillOnce(). Key generation is
Expand Down Expand Up @@ -297,9 +297,9 @@ TEST_F(AttestationPolicyObserverTest, IgnoreUnknownCertFormat) {
TEST_F(AttestationPolicyObserverTest, DBusFailureRetry) {
SetupMocks(MOCK_NEW_KEY, "");
// Simulate a DBus failure.
EXPECT_CALL(cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _))
.WillOnce(WithArgs<2>(Invoke(DBusCallbackError)))
.WillRepeatedly(WithArgs<2>(Invoke(DBusCallbackFalse)));
EXPECT_CALL(cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
.WillOnce(WithArgs<3>(Invoke(DBusCallbackError)))
.WillRepeatedly(WithArgs<3>(Invoke(DBusCallbackFalse)));
Run();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,19 @@
#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/login/user.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/prefs/scoped_user_pref_update.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/user_prefs/pref_registry_syncable.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/user_metrics.h"
#include "content/public/browser/web_contents.h"
Expand Down Expand Up @@ -212,21 +215,29 @@ void PlatformVerificationFlow::OnConsentResponse(

// At this point all user interaction is complete and we can proceed with the
// certificate request.
chromeos::User* user = GetUser(web_contents);
if (!user) {
ReportError(callback, INTERNAL_ERROR);
LOG(ERROR) << "Profile does not map to a valid user.";
return;
}
AttestationFlow::CertificateCallback certificate_callback = base::Bind(
&PlatformVerificationFlow::OnCertificateReady,
weak_factory_.GetWeakPtr(),
user->email(),
service_id,
challenge,
callback);
attestation_flow_->GetCertificate(
PROFILE_CONTENT_PROTECTION_CERTIFICATE,
user_manager_->GetActiveUser()->email(),
user->email(),
service_id,
false, // Don't force a new key.
certificate_callback);
}

void PlatformVerificationFlow::OnCertificateReady(
const std::string& user_id,
const std::string& service_id,
const std::string& challenge,
const ChallengeCallback& callback,
Expand All @@ -246,6 +257,7 @@ void PlatformVerificationFlow::OnCertificateReady(
std::string key_name = kContentProtectionKeyPrefix;
key_name += service_id;
async_caller_->TpmAttestationSignSimpleChallenge(KEY_USER,
user_id,
key_name,
challenge,
cryptohome_callback);
Expand Down Expand Up @@ -289,6 +301,13 @@ const GURL& PlatformVerificationFlow::GetURL(
return web_contents->GetLastCommittedURL();
}

User* PlatformVerificationFlow::GetUser(content::WebContents* web_contents) {
if (!web_contents)
return user_manager_->GetActiveUser();
return user_manager_->GetUserByProfile(
Profile::FromBrowserContext(web_contents->GetBrowserContext()));
}

bool PlatformVerificationFlow::IsAttestationEnabled(
content::WebContents* web_contents) {
// Check the device policy for the feature.
Expand Down
12 changes: 10 additions & 2 deletions chrome/browser/chromeos/attestation/platform_verification_flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ namespace chromeos {

class CryptohomeClient;
class UserManager;
class User;

namespace attestation {

Expand Down Expand Up @@ -162,11 +163,13 @@ class PlatformVerificationFlow {

// A callback called when an attestation certificate request operation
// completes. |service_id|, |challenge|, and |callback| are the same as in
// ChallengePlatformKey. |operation_success| is true iff the certificate
// ChallengePlatformKey. |user_id| identifies the user for which the
// certificate was requested. |operation_success| is true iff the certificate
// request operation succeeded. |certificate| holds the certificate for the
// platform key on success. If the certificate request was successful, this
// method invokes a request to sign the challenge.
void OnCertificateReady(const std::string& service_id,
void OnCertificateReady(const std::string& user_id,
const std::string& service_id,
const std::string& challenge,
const ChallengeCallback& callback,
bool operation_success,
Expand All @@ -193,6 +196,11 @@ class PlatformVerificationFlow {
// set explicitly using set_testing_url(), then this value is always returned.
const GURL& GetURL(content::WebContents* web_contents);

// Gets the user associated with the given |web_contents|. NULL may be
// returned. If |web_contents| is NULL (e.g. during testing), then the
// current active user will be returned.
User* GetUser(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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,10 @@ class PlatformVerificationFlowTest : public ::testing::Test {
std::string expected_key_name = std::string(kContentProtectionKeyPrefix) +
std::string(kTestID);
EXPECT_CALL(mock_async_caller_,
TpmAttestationSignSimpleChallenge(KEY_USER, expected_key_name,
TpmAttestationSignSimpleChallenge(KEY_USER, kTestEmail,
expected_key_name,
kTestChallenge, _))
.WillRepeatedly(WithArgs<3>(Invoke(
.WillRepeatedly(WithArgs<4>(Invoke(
this, &PlatformVerificationFlowTest::FakeSignChallenge)));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
mnissler@chromium.org

pastarmovj@chromium.org
bartfab@chromium.org
Original file line number Diff line number Diff line change
Expand Up @@ -146,18 +146,20 @@ std::string EPKPChallengeKeyBase::GetDeviceId() const {

void EPKPChallengeKeyBase::PrepareKey(
chromeos::attestation::AttestationKeyType key_type,
const std::string& user_id,
const std::string& key_name,
chromeos::attestation::AttestationCertificateProfile certificate_profile,
bool require_user_consent,
const base::Callback<void(PrepareKeyResult)>& callback) {
cryptohome_client_->TpmAttestationDoesKeyExist(
key_type, key_name, base::Bind(
key_type, user_id, key_name, base::Bind(
&EPKPChallengeKeyBase::DoesKeyExistCallback, this,
certificate_profile, require_user_consent, callback));
certificate_profile, user_id, require_user_consent, callback));
}

void EPKPChallengeKeyBase::DoesKeyExistCallback(
chromeos::attestation::AttestationCertificateProfile certificate_profile,
const std::string& user_id,
bool require_user_consent,
const base::Callback<void(PrepareKeyResult)>& callback,
chromeos::DBusMethodCallStatus status,
Expand All @@ -177,10 +179,11 @@ void EPKPChallengeKeyBase::DoesKeyExistCallback(
// information to PCA.
AskForUserConsent(
base::Bind(&EPKPChallengeKeyBase::AskForUserConsentCallback, this,
certificate_profile, callback));
certificate_profile, user_id, callback));
} else {
// User consent is not required. Skip to the next step.
AskForUserConsentCallback(certificate_profile, callback, true);
AskForUserConsentCallback(certificate_profile, user_id, callback,
true);
}
}
}
Expand All @@ -194,6 +197,7 @@ void EPKPChallengeKeyBase::AskForUserConsent(

void EPKPChallengeKeyBase::AskForUserConsentCallback(
chromeos::attestation::AttestationCertificateProfile certificate_profile,
const std::string& user_id,
const base::Callback<void(PrepareKeyResult)>& callback,
bool result) {
if (!result) {
Expand All @@ -205,7 +209,7 @@ void EPKPChallengeKeyBase::AskForUserConsentCallback(
// Generate a new key and have it signed by PCA.
attestation_flow_->GetCertificate(
certificate_profile,
std::string(), // Not used.
user_id,
std::string(), // Not used.
true, // Force a new key to be generated.
base::Bind(&EPKPChallengeKeyBase::GetCertificateCallback, this,
Expand Down Expand Up @@ -296,6 +300,7 @@ void EPKPChallengeMachineKey::GetDeviceAttestationEnabledCallback(
}

PrepareKey(chromeos::attestation::KEY_DEVICE,
std::string(), // Not used.
kKeyName,
chromeos::attestation::PROFILE_ENTERPRISE_MACHINE_CERTIFICATE,
false, // user consent is not required.
Expand All @@ -314,6 +319,7 @@ void EPKPChallengeMachineKey::PrepareKeyCallback(
// Everything is checked. Sign the challenge.
async_caller_->TpmAttestationSignEnterpriseChallenge(
chromeos::attestation::KEY_DEVICE,
std::string(), // Not used.
kKeyName,
GetEnterpriseDomain(),
GetDeviceId(),
Expand Down Expand Up @@ -441,6 +447,7 @@ void EPKPChallengeUserKey::GetDeviceAttestationEnabledCallback(
}

PrepareKey(chromeos::attestation::KEY_USER,
GetUserEmail(),
kKeyName,
chromeos::attestation::PROFILE_ENTERPRISE_USER_CERTIFICATE,
require_user_consent,
Expand All @@ -460,6 +467,7 @@ void EPKPChallengeUserKey::PrepareKeyCallback(const std::string& challenge,
// Everything is checked. Sign the challenge.
async_caller_->TpmAttestationSignEnterpriseChallenge(
chromeos::attestation::KEY_USER,
GetUserEmail(),
kKeyName,
GetUserEmail(),
GetDeviceId(),
Expand All @@ -483,6 +491,7 @@ void EPKPChallengeUserKey::SignChallengeCallback(bool register_key,
if (register_key) {
async_caller_->TpmAttestationRegisterKey(
chromeos::attestation::KEY_USER,
GetUserEmail(),
kKeyName,
base::Bind(&EPKPChallengeUserKey::RegisterKeyCallback, this, response));
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class EPKPChallengeKeyBase : public AsyncExtensionFunction {
// user consent before calling GetCertificate().
void PrepareKey(
chromeos::attestation::AttestationKeyType key_type,
const std::string& user_id,
const std::string& key_name,
chromeos::attestation::AttestationCertificateProfile certificate_profile,
bool require_user_consent,
Expand All @@ -105,13 +106,15 @@ class EPKPChallengeKeyBase : public AsyncExtensionFunction {
private:
void DoesKeyExistCallback(
chromeos::attestation::AttestationCertificateProfile certificate_profile,
const std::string& user_id,
bool require_user_consent,
const base::Callback<void(PrepareKeyResult)>& callback,
chromeos::DBusMethodCallStatus status,
bool result);
void AskForUserConsent(const base::Callback<void(bool)>& callback) const;
void AskForUserConsentCallback(
chromeos::attestation::AttestationCertificateProfile certificate_profile,
const std::string& user_id,
const base::Callback<void(PrepareKeyResult)>& callback,
bool result);
void GetCertificateCallback(
Expand Down
Loading

0 comments on commit 1260076

Please sign in to comment.