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"
9 #include "base/prefs/pref_service.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/values.h"
12 #include "chrome/browser/chromeos/policy/stub_enterprise_install_attributes.h"
13 #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
14 #include "chrome/browser/extensions/extension_function_test_utils.h"
15 #include "chrome/browser/policy/cloud/cloud_policy_constants.h"
16 #include "chrome/common/pref_names.h"
17 #include "chrome/test/base/browser_with_test_window_test.h"
18 #include "chromeos/attestation/attestation_constants.h"
19 #include "chromeos/attestation/mock_attestation_flow.h"
20 #include "chromeos/cryptohome/async_method_caller.h"
21 #include "chromeos/cryptohome/mock_async_method_caller.h"
22 #include "chromeos/dbus/dbus_method_call_status.h"
23 #include "chromeos/dbus/mock_cryptohome_client.h"
24 #include "chromeos/settings/cros_settings_provider.h"
25 #include "testing/gmock/include/gmock/gmock.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 #include "third_party/cros_system_api/dbus/service_constants.h"
30 using testing::Invoke;
31 using testing::NiceMock;
32 using testing::Return;
33 using testing::WithArgs;
35 namespace utils = extension_function_test_utils;
37 namespace extensions {
40 // Certificate errors as reported to the calling extension.
41 const int kDBusError = 1;
42 const int kUserRejected = 2;
43 const int kGetCertificateFailed = 3;
44 const int kResetRequired = 4;
46 // A simple functor to invoke a callback with predefined arguments.
47 class FakeBoolDBusMethod {
49 FakeBoolDBusMethod(chromeos::DBusMethodCallStatus status, bool value)
53 void operator() (const chromeos::BoolDBusMethodCallback& callback) {
54 callback.Run(status_, value_);
58 chromeos::DBusMethodCallStatus status_;
62 void RegisterKeyCallbackTrue(
63 chromeos::attestation::AttestationKeyType key_type,
64 const std::string& user_id,
65 const std::string& key_name,
66 const cryptohome::AsyncMethodCaller::Callback& callback) {
67 callback.Run(true, cryptohome::MOUNT_ERROR_NONE);
70 void RegisterKeyCallbackFalse(
71 chromeos::attestation::AttestationKeyType key_type,
72 const std::string& user_id,
73 const std::string& key_name,
74 const cryptohome::AsyncMethodCaller::Callback& callback) {
75 callback.Run(false, cryptohome::MOUNT_ERROR_NONE);
78 void SignChallengeCallbackTrue(
79 chromeos::attestation::AttestationKeyType key_type,
80 const std::string& user_id,
81 const std::string& key_name,
82 const std::string& domain,
83 const std::string& device_id,
84 chromeos::attestation::AttestationChallengeOptions options,
85 const std::string& challenge,
86 const cryptohome::AsyncMethodCaller::DataCallback& callback) {
87 callback.Run(true, "response");
90 void SignChallengeCallbackFalse(
91 chromeos::attestation::AttestationKeyType key_type,
92 const std::string& user_id,
93 const std::string& key_name,
94 const std::string& domain,
95 const std::string& device_id,
96 chromeos::attestation::AttestationChallengeOptions options,
97 const std::string& challenge,
98 const cryptohome::AsyncMethodCaller::DataCallback& callback) {
99 callback.Run(false, "");
102 void GetCertificateCallbackTrue(
103 chromeos::attestation::AttestationCertificateProfile certificate_profile,
104 const std::string& user_id,
105 const std::string& request_origin,
107 const chromeos::attestation::AttestationFlow::CertificateCallback&
109 callback.Run(true, "certificate");
112 void GetCertificateCallbackFalse(
113 chromeos::attestation::AttestationCertificateProfile certificate_profile,
114 const std::string& user_id,
115 const std::string& request_origin,
117 const chromeos::attestation::AttestationFlow::CertificateCallback&
119 callback.Run(false, "");
122 class EPKPChallengeKeyTestBase : public BrowserWithTestWindowTest {
124 EPKPChallengeKeyTestBase()
125 : extension_(utils::CreateEmptyExtension("")) {
126 // Set up the default behavior of mocks.
127 ON_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
128 .WillByDefault(WithArgs<3>(Invoke(FakeBoolDBusMethod(
129 chromeos::DBUS_METHOD_CALL_SUCCESS, false))));
130 ON_CALL(mock_cryptohome_client_, TpmAttestationIsPrepared(_))
131 .WillByDefault(Invoke(FakeBoolDBusMethod(
132 chromeos::DBUS_METHOD_CALL_SUCCESS, true)));
133 ON_CALL(mock_async_method_caller_, TpmAttestationRegisterKey(_, _, _, _))
134 .WillByDefault(Invoke(RegisterKeyCallbackTrue));
135 ON_CALL(mock_async_method_caller_,
136 TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _))
137 .WillByDefault(Invoke(SignChallengeCallbackTrue));
138 ON_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
139 .WillByDefault(Invoke(GetCertificateCallbackTrue));
141 // Set the Enterprise install attributes.
142 stub_install_attributes_.SetDomain("google.com");
143 stub_install_attributes_.SetRegistrationUser("test@google.com");
144 stub_install_attributes_.SetDeviceId("device_id");
145 stub_install_attributes_.SetMode(policy::DEVICE_MODE_ENTERPRISE);
147 // Replace the default device setting provider with the stub.
148 device_settings_provider_ = chromeos::CrosSettings::Get()->GetProvider(
149 chromeos::kReportDeviceVersionInfo);
150 EXPECT_TRUE(device_settings_provider_ != NULL);
151 EXPECT_TRUE(chromeos::CrosSettings::Get()->
152 RemoveSettingsProvider(device_settings_provider_));
153 chromeos::CrosSettings::Get()->
154 AddSettingsProvider(&stub_settings_provider_);
156 // Set the device settings.
157 stub_settings_provider_.Set(chromeos::kDeviceAttestationEnabled,
158 base::FundamentalValue(true));
161 virtual ~EPKPChallengeKeyTestBase() {
162 EXPECT_TRUE(chromeos::CrosSettings::Get()->
163 RemoveSettingsProvider(&stub_settings_provider_));
164 chromeos::CrosSettings::Get()->
165 AddSettingsProvider(device_settings_provider_);
168 virtual void SetUp() OVERRIDE {
169 BrowserWithTestWindowTest::SetUp();
171 // Set the user preferences.
172 prefs_ = browser()->profile()->GetPrefs();
173 prefs_->SetString(prefs::kGoogleServicesUsername, "test@google.com");
174 base::ListValue whitelist;
175 whitelist.AppendString(extension_->id());
176 prefs_->Set(prefs::kAttestationExtensionWhitelist, whitelist);
179 NiceMock<chromeos::MockCryptohomeClient> mock_cryptohome_client_;
180 NiceMock<cryptohome::MockAsyncMethodCaller> mock_async_method_caller_;
181 NiceMock<chromeos::attestation::MockAttestationFlow> mock_attestation_flow_;
182 scoped_refptr<extensions::Extension> extension_;
183 policy::StubEnterpriseInstallAttributes stub_install_attributes_;
184 chromeos::CrosSettingsProvider* device_settings_provider_;
185 chromeos::StubCrosSettingsProvider stub_settings_provider_;
189 class EPKPChallengeMachineKeyTest : public EPKPChallengeKeyTestBase {
191 static const char kArgs[];
193 EPKPChallengeMachineKeyTest()
194 : func_(new EPKPChallengeMachineKey(&mock_cryptohome_client_,
195 &mock_async_method_caller_,
196 &mock_attestation_flow_,
197 &stub_install_attributes_)) {
198 func_->set_extension(extension_.get());
201 // Returns an error string for the given code.
202 std::string GetCertificateError(int error_code) {
203 return base::StringPrintf(
204 EPKPChallengeMachineKey::kGetCertificateFailedError,
208 scoped_refptr<EPKPChallengeMachineKey> func_;
211 // Base 64 encoding of 'challenge'.
212 const char EPKPChallengeMachineKeyTest::kArgs[] = "[\"Y2hhbGxlbmdl\"]";
214 TEST_F(EPKPChallengeMachineKeyTest, ChallengeBadBase64) {
215 EXPECT_EQ(EPKPChallengeKeyBase::kChallengeBadBase64Error,
216 utils::RunFunctionAndReturnError(
217 func_.get(), "[\"****\"]", browser()));
220 TEST_F(EPKPChallengeMachineKeyTest, NonEnterpriseDevice) {
221 stub_install_attributes_.SetRegistrationUser("");
223 EXPECT_EQ(EPKPChallengeMachineKey::kNonEnterpriseDeviceError,
224 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
227 TEST_F(EPKPChallengeMachineKeyTest, ExtensionNotWhitelisted) {
228 base::ListValue empty_whitelist;
229 prefs_->Set(prefs::kAttestationExtensionWhitelist, empty_whitelist);
231 EXPECT_EQ(EPKPChallengeKeyBase::kExtensionNotWhitelistedError,
232 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
235 TEST_F(EPKPChallengeMachineKeyTest, UserNotManaged) {
236 prefs_->SetString(prefs::kGoogleServicesUsername, "test@chromium.org");
238 EXPECT_EQ(EPKPChallengeKeyBase::kUserNotManaged,
239 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
242 TEST_F(EPKPChallengeMachineKeyTest, DevicePolicyDisabled) {
243 stub_settings_provider_.Set(chromeos::kDeviceAttestationEnabled,
244 base::FundamentalValue(false));
246 EXPECT_EQ(EPKPChallengeKeyBase::kDevicePolicyDisabledError,
247 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
250 TEST_F(EPKPChallengeMachineKeyTest, DoesKeyExistDbusFailed) {
251 EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
252 .WillRepeatedly(WithArgs<3>(Invoke(FakeBoolDBusMethod(
253 chromeos::DBUS_METHOD_CALL_FAILURE, false))));
255 EXPECT_EQ(GetCertificateError(kDBusError),
256 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
259 TEST_F(EPKPChallengeMachineKeyTest, GetCertificateFailed) {
260 EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
261 .WillRepeatedly(Invoke(GetCertificateCallbackFalse));
263 EXPECT_EQ(GetCertificateError(kGetCertificateFailed),
264 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
267 TEST_F(EPKPChallengeMachineKeyTest, SignChallengeFailed) {
268 EXPECT_CALL(mock_async_method_caller_,
269 TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _))
270 .WillRepeatedly(Invoke(SignChallengeCallbackFalse));
272 EXPECT_EQ(EPKPChallengeKeyBase::kSignChallengeFailedError,
273 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
276 TEST_F(EPKPChallengeMachineKeyTest, KeyExists) {
277 EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
278 .WillRepeatedly(WithArgs<3>(Invoke(FakeBoolDBusMethod(
279 chromeos::DBUS_METHOD_CALL_SUCCESS, true))));
280 // GetCertificate must not be called if the key exists.
281 EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
284 EXPECT_TRUE(utils::RunFunction(func_.get(), kArgs, browser(), utils::NONE));
287 TEST_F(EPKPChallengeMachineKeyTest, Success) {
288 // GetCertificate must be called exactly once.
289 EXPECT_CALL(mock_attestation_flow_,
291 chromeos::attestation::PROFILE_ENTERPRISE_MACHINE_CERTIFICATE,
294 // SignEnterpriseChallenge must be called exactly once.
295 EXPECT_CALL(mock_async_method_caller_,
296 TpmAttestationSignEnterpriseChallenge(
297 chromeos::attestation::KEY_DEVICE, "", "attest-ent-machine",
298 "google.com", "device_id", _, "challenge", _))
301 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
302 func_.get(), kArgs, browser(), utils::NONE));
304 std::string response;
305 value->GetAsString(&response);
306 EXPECT_EQ("cmVzcG9uc2U=" /* Base64 encoding of 'response' */, response);
309 TEST_F(EPKPChallengeMachineKeyTest, AttestationNotPrepared) {
310 EXPECT_CALL(mock_cryptohome_client_, TpmAttestationIsPrepared(_))
311 .WillRepeatedly(Invoke(FakeBoolDBusMethod(
312 chromeos::DBUS_METHOD_CALL_SUCCESS, false)));
314 EXPECT_EQ(GetCertificateError(kResetRequired),
315 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
318 TEST_F(EPKPChallengeMachineKeyTest, AttestationPreparedDbusFailed) {
319 EXPECT_CALL(mock_cryptohome_client_, TpmAttestationIsPrepared(_))
320 .WillRepeatedly(Invoke(FakeBoolDBusMethod(
321 chromeos::DBUS_METHOD_CALL_FAILURE, true)));
323 EXPECT_EQ(GetCertificateError(kDBusError),
324 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
327 class EPKPChallengeUserKeyTest : public EPKPChallengeKeyTestBase {
329 static const char kArgs[];
331 EPKPChallengeUserKeyTest() :
332 func_(new EPKPChallengeUserKey(&mock_cryptohome_client_,
333 &mock_async_method_caller_,
334 &mock_attestation_flow_,
335 &stub_install_attributes_)) {
336 func_->set_extension(extension_.get());
339 virtual void SetUp() OVERRIDE {
340 EPKPChallengeKeyTestBase::SetUp();
342 // Set the user preferences.
343 prefs_->SetBoolean(prefs::kAttestationEnabled, true);
346 // Returns an error string for the given code.
347 std::string GetCertificateError(int error_code) {
348 return base::StringPrintf(EPKPChallengeUserKey::kGetCertificateFailedError,
352 scoped_refptr<EPKPChallengeUserKey> func_;
355 // Base 64 encoding of 'challenge'
356 const char EPKPChallengeUserKeyTest::kArgs[] = "[\"Y2hhbGxlbmdl\", true]";
358 TEST_F(EPKPChallengeUserKeyTest, ChallengeBadBase64) {
359 EXPECT_EQ(EPKPChallengeKeyBase::kChallengeBadBase64Error,
360 utils::RunFunctionAndReturnError(
361 func_.get(), "[\"****\", true]", browser()));
364 TEST_F(EPKPChallengeUserKeyTest, UserPolicyDisabled) {
365 prefs_->SetBoolean(prefs::kAttestationEnabled, false);
367 EXPECT_EQ(EPKPChallengeUserKey::kUserPolicyDisabledError,
368 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
371 TEST_F(EPKPChallengeUserKeyTest, ExtensionNotWhitelisted) {
372 base::ListValue empty_whitelist;
373 prefs_->Set(prefs::kAttestationExtensionWhitelist, empty_whitelist);
375 EXPECT_EQ(EPKPChallengeKeyBase::kExtensionNotWhitelistedError,
376 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
379 TEST_F(EPKPChallengeUserKeyTest, UserNotManaged) {
380 prefs_->SetString(prefs::kGoogleServicesUsername, "test@chromium.org");
382 EXPECT_EQ(EPKPChallengeKeyBase::kUserNotManaged,
383 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
386 TEST_F(EPKPChallengeUserKeyTest, DevicePolicyDisabled) {
387 stub_settings_provider_.Set(chromeos::kDeviceAttestationEnabled,
388 base::FundamentalValue(false));
390 EXPECT_EQ(EPKPChallengeKeyBase::kDevicePolicyDisabledError,
391 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
394 TEST_F(EPKPChallengeUserKeyTest, DoesKeyExistDbusFailed) {
395 EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
396 .WillRepeatedly(WithArgs<3>(Invoke(FakeBoolDBusMethod(
397 chromeos::DBUS_METHOD_CALL_FAILURE, false))));
399 EXPECT_EQ(GetCertificateError(kDBusError),
400 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
403 TEST_F(EPKPChallengeUserKeyTest, GetCertificateFailed) {
404 EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
405 .WillRepeatedly(Invoke(GetCertificateCallbackFalse));
407 EXPECT_EQ(GetCertificateError(kGetCertificateFailed),
408 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
411 TEST_F(EPKPChallengeUserKeyTest, SignChallengeFailed) {
412 EXPECT_CALL(mock_async_method_caller_,
413 TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _))
414 .WillRepeatedly(Invoke(SignChallengeCallbackFalse));
416 EXPECT_EQ(EPKPChallengeKeyBase::kSignChallengeFailedError,
417 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
420 TEST_F(EPKPChallengeUserKeyTest, KeyRegistrationFailed) {
421 EXPECT_CALL(mock_async_method_caller_, TpmAttestationRegisterKey(_, _, _, _))
422 .WillRepeatedly(Invoke(RegisterKeyCallbackFalse));
424 EXPECT_EQ(EPKPChallengeUserKey::kKeyRegistrationFailedError,
425 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
428 TEST_F(EPKPChallengeUserKeyTest, KeyExists) {
429 EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
430 .WillRepeatedly(WithArgs<3>(Invoke(FakeBoolDBusMethod(
431 chromeos::DBUS_METHOD_CALL_SUCCESS, true))));
432 // GetCertificate must not be called if the key exists.
433 EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
436 EXPECT_TRUE(utils::RunFunction(func_.get(), kArgs, browser(), utils::NONE));
439 TEST_F(EPKPChallengeUserKeyTest, KeyNotRegistered) {
440 EXPECT_CALL(mock_async_method_caller_, TpmAttestationRegisterKey(_, _, _, _))
443 EXPECT_TRUE(utils::RunFunction(
444 func_.get(), "[\"Y2hhbGxlbmdl\", false]", browser(), utils::NONE));
447 TEST_F(EPKPChallengeUserKeyTest, PersonalDevice) {
448 stub_install_attributes_.SetRegistrationUser("");
450 // Currently personal devices are not supported.
451 EXPECT_EQ(GetCertificateError(kUserRejected),
452 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
455 TEST_F(EPKPChallengeUserKeyTest, Success) {
456 // GetCertificate must be called exactly once.
457 EXPECT_CALL(mock_attestation_flow_,
459 chromeos::attestation::PROFILE_ENTERPRISE_USER_CERTIFICATE,
462 // SignEnterpriseChallenge must be called exactly once.
463 EXPECT_CALL(mock_async_method_caller_,
464 TpmAttestationSignEnterpriseChallenge(
465 chromeos::attestation::KEY_USER, "test@google.com",
466 "attest-ent-user", "test@google.com", "device_id", _,
469 // RegisterKey must be called exactly once.
470 EXPECT_CALL(mock_async_method_caller_,
471 TpmAttestationRegisterKey(chromeos::attestation::KEY_USER,
473 "attest-ent-user", _))
476 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
477 func_.get(), kArgs, browser(), utils::NONE));
479 std::string response;
480 value->GetAsString(&response);
481 EXPECT_EQ("cmVzcG9uc2U=" /* Base64 encoding of 'response' */, response);
484 TEST_F(EPKPChallengeUserKeyTest, AttestationNotPrepared) {
485 EXPECT_CALL(mock_cryptohome_client_, TpmAttestationIsPrepared(_))
486 .WillRepeatedly(Invoke(FakeBoolDBusMethod(
487 chromeos::DBUS_METHOD_CALL_SUCCESS, false)));
489 EXPECT_EQ(GetCertificateError(kResetRequired),
490 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
493 TEST_F(EPKPChallengeUserKeyTest, AttestationPreparedDbusFailed) {
494 EXPECT_CALL(mock_cryptohome_client_, TpmAttestationIsPrepared(_))
495 .WillRepeatedly(Invoke(FakeBoolDBusMethod(
496 chromeos::DBUS_METHOD_CALL_FAILURE, true)));
498 EXPECT_EQ(GetCertificateError(kDBusError),
499 utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
503 } // namespace extensions