1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h"
10 #include "base/location.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/values.h"
15 #include "chrome/browser/chromeos/policy/stub_enterprise_install_attributes.h"
16 #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
17 #include "chrome/browser/extensions/extension_function_test_utils.h"
18 #include "chrome/common/pref_names.h"
19 #include "chrome/test/base/browser_with_test_window_test.h"
20 #include "chromeos/attestation/attestation_constants.h"
21 #include "chromeos/attestation/mock_attestation_flow.h"
22 #include "chromeos/cryptohome/async_method_caller.h"
23 #include "chromeos/cryptohome/mock_async_method_caller.h"
24 #include "chromeos/dbus/dbus_method_call_status.h"
25 #include "chromeos/dbus/mock_cryptohome_client.h"
26 #include "chromeos/settings/cros_settings_provider.h"
27 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
28 #include "extensions/common/test_util.h"
29 #include "testing/gmock/include/gmock/gmock.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31 #include "third_party/cros_system_api/dbus/service_constants.h"
34 using testing::Invoke;
35 using testing::NiceMock;
36 using testing::Return;
37 using testing::WithArgs;
39 namespace utils = extension_function_test_utils;
41 namespace extensions {
44 // Certificate errors as reported to the calling extension.
45 const int kDBusError = 1;
46 const int kUserRejected = 2;
47 const int kGetCertificateFailed = 3;
48 const int kResetRequired = 4;
50 // A simple functor to invoke a callback with predefined arguments.
51 class FakeBoolDBusMethod {
53 FakeBoolDBusMethod(chromeos::DBusMethodCallStatus status, bool value)
57 void operator() (const chromeos::BoolDBusMethodCallback& callback) {
58 base::MessageLoopProxy::current()->PostTask(
60 base::Bind(callback, status_, value_));
64 chromeos::DBusMethodCallStatus status_;
68 void RegisterKeyCallbackTrue(
69 chromeos::attestation::AttestationKeyType key_type,
70 const std::string& user_id,
71 const std::string& key_name,
72 const cryptohome::AsyncMethodCaller::Callback& callback) {
73 base::MessageLoopProxy::current()->PostTask(
75 base::Bind(callback, true, cryptohome::MOUNT_ERROR_NONE));
78 void RegisterKeyCallbackFalse(
79 chromeos::attestation::AttestationKeyType key_type,
80 const std::string& user_id,
81 const std::string& key_name,
82 const cryptohome::AsyncMethodCaller::Callback& callback) {
83 base::MessageLoopProxy::current()->PostTask(
85 base::Bind(callback, false, cryptohome::MOUNT_ERROR_NONE));
88 void SignChallengeCallbackTrue(
89 chromeos::attestation::AttestationKeyType key_type,
90 const std::string& user_id,
91 const std::string& key_name,
92 const std::string& domain,
93 const std::string& device_id,
94 chromeos::attestation::AttestationChallengeOptions options,
95 const std::string& challenge,
96 const cryptohome::AsyncMethodCaller::DataCallback& callback) {
97 base::MessageLoopProxy::current()->PostTask(
99 base::Bind(callback, true, "response"));
102 void SignChallengeCallbackFalse(
103 chromeos::attestation::AttestationKeyType key_type,
104 const std::string& user_id,
105 const std::string& key_name,
106 const std::string& domain,
107 const std::string& device_id,
108 chromeos::attestation::AttestationChallengeOptions options,
109 const std::string& challenge,
110 const cryptohome::AsyncMethodCaller::DataCallback& callback) {
111 base::MessageLoopProxy::current()->PostTask(
113 base::Bind(callback, false, ""));
116 void GetCertificateCallbackTrue(
117 chromeos::attestation::AttestationCertificateProfile certificate_profile,
118 const std::string& user_id,
119 const std::string& request_origin,
121 const chromeos::attestation::AttestationFlow::CertificateCallback&
123 base::MessageLoopProxy::current()->PostTask(
125 base::Bind(callback, true, "certificate"));
128 void GetCertificateCallbackFalse(
129 chromeos::attestation::AttestationCertificateProfile certificate_profile,
130 const std::string& user_id,
131 const std::string& request_origin,
133 const chromeos::attestation::AttestationFlow::CertificateCallback&
135 base::MessageLoopProxy::current()->PostTask(
137 base::Bind(callback, false, ""));
140 class EPKPChallengeKeyTestBase : public BrowserWithTestWindowTest {
142 EPKPChallengeKeyTestBase() : extension_(test_util::CreateEmptyExtension()) {
143 // Set up the default behavior of mocks.
144 ON_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
145 .WillByDefault(WithArgs<3>(Invoke(FakeBoolDBusMethod(
146 chromeos::DBUS_METHOD_CALL_SUCCESS, false))));
147 ON_CALL(mock_cryptohome_client_, TpmAttestationIsPrepared(_))
148 .WillByDefault(Invoke(FakeBoolDBusMethod(
149 chromeos::DBUS_METHOD_CALL_SUCCESS, true)));
150 ON_CALL(mock_async_method_caller_, TpmAttestationRegisterKey(_, _, _, _))
151 .WillByDefault(Invoke(RegisterKeyCallbackTrue));
152 ON_CALL(mock_async_method_caller_,
153 TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _))
154 .WillByDefault(Invoke(SignChallengeCallbackTrue));
155 ON_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
156 .WillByDefault(Invoke(GetCertificateCallbackTrue));
158 // Set the Enterprise install attributes.
159 stub_install_attributes_.SetDomain("google.com");
160 stub_install_attributes_.SetRegistrationUser("test@google.com");
161 stub_install_attributes_.SetDeviceId("device_id");
162 stub_install_attributes_.SetMode(policy::DEVICE_MODE_ENTERPRISE);
164 // Replace the default device setting provider with the stub.
165 device_settings_provider_ = chromeos::CrosSettings::Get()->GetProvider(
166 chromeos::kReportDeviceVersionInfo);
167 EXPECT_TRUE(device_settings_provider_ != NULL);
168 EXPECT_TRUE(chromeos::CrosSettings::Get()->
169 RemoveSettingsProvider(device_settings_provider_));
170 chromeos::CrosSettings::Get()->
171 AddSettingsProvider(&stub_settings_provider_);
173 // Set the device settings.
174 stub_settings_provider_.Set(chromeos::kDeviceAttestationEnabled,
175 base::FundamentalValue(true));
178 virtual ~EPKPChallengeKeyTestBase() {
179 EXPECT_TRUE(chromeos::CrosSettings::Get()->
180 RemoveSettingsProvider(&stub_settings_provider_));
181 chromeos::CrosSettings::Get()->
182 AddSettingsProvider(device_settings_provider_);
185 virtual void SetUp() OVERRIDE {
186 BrowserWithTestWindowTest::SetUp();
188 // Set the user preferences.
189 prefs_ = browser()->profile()->GetPrefs();
190 prefs_->SetString(prefs::kGoogleServicesUsername, "test@google.com");
191 base::ListValue whitelist;
192 whitelist.AppendString(extension_->id());
193 prefs_->Set(prefs::kAttestationExtensionWhitelist, whitelist);
196 NiceMock<chromeos::MockCryptohomeClient> mock_cryptohome_client_;
197 NiceMock<cryptohome::MockAsyncMethodCaller> mock_async_method_caller_;
198 NiceMock<chromeos::attestation::MockAttestationFlow> mock_attestation_flow_;
199 scoped_refptr<extensions::Extension> extension_;
200 policy::StubEnterpriseInstallAttributes stub_install_attributes_;
201 chromeos::CrosSettingsProvider* device_settings_provider_;
202 chromeos::StubCrosSettingsProvider stub_settings_provider_;
206 class EPKPChallengeMachineKeyTest : public EPKPChallengeKeyTestBase {
208 static const char kArgs[];
210 EPKPChallengeMachineKeyTest()
211 : func_(new EPKPChallengeMachineKey(&mock_cryptohome_client_,
212 &mock_async_method_caller_,
213 &mock_attestation_flow_,
214 &stub_install_attributes_)) {
215 func_->set_extension(extension_.get());
218 // Returns an error string for the given code.
219 std::string GetCertificateError(int error_code) {
220 return base::StringPrintf(
221 EPKPChallengeMachineKey::kGetCertificateFailedError,
225 scoped_refptr<EPKPChallengeMachineKey> func_;
228 // Base 64 encoding of 'challenge'.
229 const char EPKPChallengeMachineKeyTest::kArgs[] = "[\"Y2hhbGxlbmdl\"]";
231 TEST_F(EPKPChallengeMachineKeyTest, ChallengeBadBase64) {
232 EXPECT_EQ(EPKPChallengeKeyBase::kChallengeBadBase64Error,
233 utils::RunFunctionAndReturnError(
234 func_.get(), "[\"****\"]", browser()));
237 TEST_F(EPKPChallengeMachineKeyTest, NonEnterpriseDevice) {
238 stub_install_attributes_.SetRegistrationUser("");
240 EXPECT_EQ(EPKPChallengeMachineKey::kNonEnterpriseDeviceError,
241 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
244 TEST_F(EPKPChallengeMachineKeyTest, ExtensionNotWhitelisted) {
245 base::ListValue empty_whitelist;
246 prefs_->Set(prefs::kAttestationExtensionWhitelist, empty_whitelist);
248 EXPECT_EQ(EPKPChallengeKeyBase::kExtensionNotWhitelistedError,
249 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
252 TEST_F(EPKPChallengeMachineKeyTest, UserNotManaged) {
253 prefs_->SetString(prefs::kGoogleServicesUsername, "test@chromium.org");
255 EXPECT_EQ(EPKPChallengeKeyBase::kUserNotManaged,
256 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
259 TEST_F(EPKPChallengeMachineKeyTest, DevicePolicyDisabled) {
260 stub_settings_provider_.Set(chromeos::kDeviceAttestationEnabled,
261 base::FundamentalValue(false));
263 EXPECT_EQ(EPKPChallengeKeyBase::kDevicePolicyDisabledError,
264 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
267 TEST_F(EPKPChallengeMachineKeyTest, DoesKeyExistDbusFailed) {
268 EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
269 .WillRepeatedly(WithArgs<3>(Invoke(FakeBoolDBusMethod(
270 chromeos::DBUS_METHOD_CALL_FAILURE, false))));
272 EXPECT_EQ(GetCertificateError(kDBusError),
273 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
276 TEST_F(EPKPChallengeMachineKeyTest, GetCertificateFailed) {
277 EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
278 .WillRepeatedly(Invoke(GetCertificateCallbackFalse));
280 EXPECT_EQ(GetCertificateError(kGetCertificateFailed),
281 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
284 TEST_F(EPKPChallengeMachineKeyTest, SignChallengeFailed) {
285 EXPECT_CALL(mock_async_method_caller_,
286 TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _))
287 .WillRepeatedly(Invoke(SignChallengeCallbackFalse));
289 EXPECT_EQ(EPKPChallengeKeyBase::kSignChallengeFailedError,
290 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
293 TEST_F(EPKPChallengeMachineKeyTest, KeyExists) {
294 EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
295 .WillRepeatedly(WithArgs<3>(Invoke(FakeBoolDBusMethod(
296 chromeos::DBUS_METHOD_CALL_SUCCESS, true))));
297 // GetCertificate must not be called if the key exists.
298 EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
301 EXPECT_TRUE(utils::RunFunction(func_.get(), kArgs, browser(), utils::NONE));
304 TEST_F(EPKPChallengeMachineKeyTest, Success) {
305 // GetCertificate must be called exactly once.
306 EXPECT_CALL(mock_attestation_flow_,
308 chromeos::attestation::PROFILE_ENTERPRISE_MACHINE_CERTIFICATE,
311 // SignEnterpriseChallenge must be called exactly once.
312 EXPECT_CALL(mock_async_method_caller_,
313 TpmAttestationSignEnterpriseChallenge(
314 chromeos::attestation::KEY_DEVICE, "", "attest-ent-machine",
315 "google.com", "device_id", _, "challenge", _))
318 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
319 func_.get(), kArgs, browser(), utils::NONE));
321 std::string response;
322 value->GetAsString(&response);
323 EXPECT_EQ("cmVzcG9uc2U=" /* Base64 encoding of 'response' */, response);
326 TEST_F(EPKPChallengeMachineKeyTest, AttestationNotPrepared) {
327 EXPECT_CALL(mock_cryptohome_client_, TpmAttestationIsPrepared(_))
328 .WillRepeatedly(Invoke(FakeBoolDBusMethod(
329 chromeos::DBUS_METHOD_CALL_SUCCESS, false)));
331 EXPECT_EQ(GetCertificateError(kResetRequired),
332 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
335 TEST_F(EPKPChallengeMachineKeyTest, AttestationPreparedDbusFailed) {
336 EXPECT_CALL(mock_cryptohome_client_, TpmAttestationIsPrepared(_))
337 .WillRepeatedly(Invoke(FakeBoolDBusMethod(
338 chromeos::DBUS_METHOD_CALL_FAILURE, true)));
340 EXPECT_EQ(GetCertificateError(kDBusError),
341 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
344 class EPKPChallengeUserKeyTest : public EPKPChallengeKeyTestBase {
346 static const char kArgs[];
348 EPKPChallengeUserKeyTest() :
349 func_(new EPKPChallengeUserKey(&mock_cryptohome_client_,
350 &mock_async_method_caller_,
351 &mock_attestation_flow_,
352 &stub_install_attributes_)) {
353 func_->set_extension(extension_.get());
356 virtual void SetUp() OVERRIDE {
357 EPKPChallengeKeyTestBase::SetUp();
359 // Set the user preferences.
360 prefs_->SetBoolean(prefs::kAttestationEnabled, true);
363 // Returns an error string for the given code.
364 std::string GetCertificateError(int error_code) {
365 return base::StringPrintf(EPKPChallengeUserKey::kGetCertificateFailedError,
369 scoped_refptr<EPKPChallengeUserKey> func_;
372 // Base 64 encoding of 'challenge'
373 const char EPKPChallengeUserKeyTest::kArgs[] = "[\"Y2hhbGxlbmdl\", true]";
375 TEST_F(EPKPChallengeUserKeyTest, ChallengeBadBase64) {
376 EXPECT_EQ(EPKPChallengeKeyBase::kChallengeBadBase64Error,
377 utils::RunFunctionAndReturnError(
378 func_.get(), "[\"****\", true]", browser()));
381 TEST_F(EPKPChallengeUserKeyTest, UserPolicyDisabled) {
382 prefs_->SetBoolean(prefs::kAttestationEnabled, false);
384 EXPECT_EQ(EPKPChallengeUserKey::kUserPolicyDisabledError,
385 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
388 TEST_F(EPKPChallengeUserKeyTest, ExtensionNotWhitelisted) {
389 base::ListValue empty_whitelist;
390 prefs_->Set(prefs::kAttestationExtensionWhitelist, empty_whitelist);
392 EXPECT_EQ(EPKPChallengeKeyBase::kExtensionNotWhitelistedError,
393 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
396 TEST_F(EPKPChallengeUserKeyTest, UserNotManaged) {
397 prefs_->SetString(prefs::kGoogleServicesUsername, "test@chromium.org");
399 EXPECT_EQ(EPKPChallengeKeyBase::kUserNotManaged,
400 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
403 TEST_F(EPKPChallengeUserKeyTest, DevicePolicyDisabled) {
404 stub_settings_provider_.Set(chromeos::kDeviceAttestationEnabled,
405 base::FundamentalValue(false));
407 EXPECT_EQ(EPKPChallengeKeyBase::kDevicePolicyDisabledError,
408 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
411 TEST_F(EPKPChallengeUserKeyTest, DoesKeyExistDbusFailed) {
412 EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
413 .WillRepeatedly(WithArgs<3>(Invoke(FakeBoolDBusMethod(
414 chromeos::DBUS_METHOD_CALL_FAILURE, false))));
416 EXPECT_EQ(GetCertificateError(kDBusError),
417 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
420 TEST_F(EPKPChallengeUserKeyTest, GetCertificateFailed) {
421 EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
422 .WillRepeatedly(Invoke(GetCertificateCallbackFalse));
424 EXPECT_EQ(GetCertificateError(kGetCertificateFailed),
425 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
428 TEST_F(EPKPChallengeUserKeyTest, SignChallengeFailed) {
429 EXPECT_CALL(mock_async_method_caller_,
430 TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _))
431 .WillRepeatedly(Invoke(SignChallengeCallbackFalse));
433 EXPECT_EQ(EPKPChallengeKeyBase::kSignChallengeFailedError,
434 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
437 TEST_F(EPKPChallengeUserKeyTest, KeyRegistrationFailed) {
438 EXPECT_CALL(mock_async_method_caller_, TpmAttestationRegisterKey(_, _, _, _))
439 .WillRepeatedly(Invoke(RegisterKeyCallbackFalse));
441 EXPECT_EQ(EPKPChallengeUserKey::kKeyRegistrationFailedError,
442 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
445 TEST_F(EPKPChallengeUserKeyTest, KeyExists) {
446 EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
447 .WillRepeatedly(WithArgs<3>(Invoke(FakeBoolDBusMethod(
448 chromeos::DBUS_METHOD_CALL_SUCCESS, true))));
449 // GetCertificate must not be called if the key exists.
450 EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
453 EXPECT_TRUE(utils::RunFunction(func_.get(), kArgs, browser(), utils::NONE));
456 TEST_F(EPKPChallengeUserKeyTest, KeyNotRegistered) {
457 EXPECT_CALL(mock_async_method_caller_, TpmAttestationRegisterKey(_, _, _, _))
460 EXPECT_TRUE(utils::RunFunction(
461 func_.get(), "[\"Y2hhbGxlbmdl\", false]", browser(), utils::NONE));
464 TEST_F(EPKPChallengeUserKeyTest, PersonalDevice) {
465 stub_install_attributes_.SetRegistrationUser("");
467 // Currently personal devices are not supported.
468 EXPECT_EQ(GetCertificateError(kUserRejected),
469 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
472 TEST_F(EPKPChallengeUserKeyTest, Success) {
473 // GetCertificate must be called exactly once.
474 EXPECT_CALL(mock_attestation_flow_,
476 chromeos::attestation::PROFILE_ENTERPRISE_USER_CERTIFICATE,
479 // SignEnterpriseChallenge must be called exactly once.
480 EXPECT_CALL(mock_async_method_caller_,
481 TpmAttestationSignEnterpriseChallenge(
482 chromeos::attestation::KEY_USER, "test@google.com",
483 "attest-ent-user", "test@google.com", "device_id", _,
486 // RegisterKey must be called exactly once.
487 EXPECT_CALL(mock_async_method_caller_,
488 TpmAttestationRegisterKey(chromeos::attestation::KEY_USER,
490 "attest-ent-user", _))
493 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
494 func_.get(), kArgs, browser(), utils::NONE));
496 std::string response;
497 value->GetAsString(&response);
498 EXPECT_EQ("cmVzcG9uc2U=" /* Base64 encoding of 'response' */, response);
501 TEST_F(EPKPChallengeUserKeyTest, AttestationNotPrepared) {
502 EXPECT_CALL(mock_cryptohome_client_, TpmAttestationIsPrepared(_))
503 .WillRepeatedly(Invoke(FakeBoolDBusMethod(
504 chromeos::DBUS_METHOD_CALL_SUCCESS, false)));
506 EXPECT_EQ(GetCertificateError(kResetRequired),
507 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
510 TEST_F(EPKPChallengeUserKeyTest, AttestationPreparedDbusFailed) {
511 EXPECT_CALL(mock_cryptohome_client_, TpmAttestationIsPrepared(_))
512 .WillRepeatedly(Invoke(FakeBoolDBusMethod(
513 chromeos::DBUS_METHOD_CALL_FAILURE, true)));
515 EXPECT_EQ(GetCertificateError(kDBusError),
516 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
520 } // namespace extensions