Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / enterprise_platform_keys / enterprise_platform_keys_apitest_nss.cc
1 // Copyright 2014 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.
4
5 #include <cryptohi.h>
6
7 #include "base/macros.h"
8 #include "base/strings/stringprintf.h"
9 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
10 #include "chrome/browser/extensions/extension_apitest.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/net/nss_context.h"
13 #include "chrome/browser/net/url_request_mock_util.h"
14 #include "chromeos/chromeos_switches.h"
15 #include "chromeos/login/user_names.h"
16 #include "components/policy/core/browser/browser_policy_connector.h"
17 #include "components/policy/core/common/mock_configuration_policy_provider.h"
18 #include "components/policy/core/common/policy_map.h"
19 #include "content/public/browser/notification_service.h"
20 #include "content/public/common/content_switches.h"
21 #include "content/public/test/test_utils.h"
22 #include "crypto/nss_util_internal.h"
23 #include "crypto/scoped_test_system_nss_key_slot.h"
24 #include "extensions/browser/notification_types.h"
25 #include "net/base/net_errors.h"
26 #include "net/cert/nss_cert_database.h"
27 #include "net/test/url_request/url_request_mock_http_job.h"
28 #include "policy/policy_constants.h"
29 #include "testing/gmock/include/gmock/gmock.h"
30
31 namespace {
32
33 // The test extension has a certificate referencing this private key which will
34 // be stored in the user's token in the test setup.
35 //
36 // openssl genrsa > privkey.pem
37 // openssl pkcs8 -inform pem -in privkey.pem -topk8
38 //   -outform der -out privkey8.der -nocrypt
39 // xxd -i privkey8.der
40 const unsigned char privateKeyPkcs8User[] = {
41     0x30, 0x82, 0x01, 0x55, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
42     0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
43     0x01, 0x3f, 0x30, 0x82, 0x01, 0x3b, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00,
44     0xc7, 0xc1, 0x4d, 0xd5, 0xdc, 0x3a, 0x2e, 0x1f, 0x42, 0x30, 0x3d, 0x21,
45     0x1e, 0xa2, 0x1f, 0x60, 0xcb, 0x71, 0x11, 0x53, 0xb0, 0x75, 0xa0, 0x62,
46     0xfe, 0x5e, 0x0a, 0xde, 0xb0, 0x0f, 0x48, 0x97, 0x5e, 0x42, 0xa7, 0x3a,
47     0xd1, 0xca, 0x4c, 0xe3, 0xdb, 0x5f, 0x31, 0xc2, 0x99, 0x08, 0x89, 0xcd,
48     0x6d, 0x20, 0xaa, 0x75, 0xe6, 0x2b, 0x98, 0xd2, 0xf3, 0x7b, 0x4b, 0xe5,
49     0x9b, 0xfe, 0xe2, 0x6d, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x40, 0x4a,
50     0xf5, 0x76, 0x10, 0xe7, 0xb8, 0x89, 0x70, 0x3f, 0x75, 0x3c, 0xab, 0x3e,
51     0x04, 0x96, 0x83, 0xcb, 0x34, 0x1d, 0xcd, 0x6a, 0xed, 0x69, 0x07, 0x5c,
52     0xee, 0xcb, 0x63, 0x6f, 0x6b, 0xfc, 0xcf, 0xee, 0xa2, 0xc4, 0x67, 0x05,
53     0x68, 0x4d, 0x21, 0x7e, 0x3e, 0xde, 0x74, 0x72, 0xf8, 0x04, 0x35, 0x66,
54     0x1e, 0x6b, 0x1d, 0xef, 0x77, 0xf7, 0x33, 0xf0, 0x35, 0xcf, 0x35, 0x6e,
55     0x53, 0x3f, 0x9d, 0x02, 0x21, 0x00, 0xee, 0x48, 0x67, 0x1b, 0x24, 0x6e,
56     0x3d, 0x7b, 0xa0, 0xc3, 0xee, 0x8a, 0x2e, 0xc7, 0xd0, 0xa1, 0xdb, 0x25,
57     0x31, 0x12, 0x99, 0x43, 0x06, 0x3c, 0xb0, 0x80, 0x35, 0x2b, 0xf4, 0xc5,
58     0xa2, 0xd3, 0x02, 0x21, 0x00, 0xd6, 0x9b, 0x8b, 0x75, 0x91, 0x52, 0xd4,
59     0xf0, 0x76, 0xcf, 0xa2, 0xbe, 0xa6, 0xaf, 0x72, 0x6c, 0x52, 0xf9, 0xc9,
60     0x0e, 0xea, 0x4a, 0x4c, 0xd2, 0xdf, 0x25, 0x70, 0xc6, 0x66, 0x35, 0x9d,
61     0xbf, 0x02, 0x21, 0x00, 0xe8, 0x9e, 0x40, 0x21, 0xcc, 0x37, 0xde, 0xc7,
62     0xd1, 0x13, 0x55, 0xcd, 0x0a, 0x8c, 0x40, 0xcd, 0xb1, 0xed, 0xa5, 0xf1,
63     0x7d, 0x33, 0x64, 0x64, 0x5c, 0xfe, 0x5c, 0x6a, 0x34, 0x03, 0xb8, 0xc7,
64     0x02, 0x20, 0x17, 0xe1, 0xb5, 0x52, 0x3e, 0xfa, 0xc5, 0xc1, 0x80, 0xa7,
65     0x38, 0x88, 0x18, 0xca, 0x7b, 0x64, 0x3c, 0x93, 0x99, 0x61, 0x34, 0x87,
66     0x52, 0x27, 0x41, 0x37, 0xcc, 0x65, 0xf7, 0xa7, 0xcd, 0xc7, 0x02, 0x21,
67     0x00, 0x8a, 0x17, 0x7f, 0xf9, 0x45, 0xf3, 0xfd, 0xf7, 0x96, 0x62, 0xf3,
68     0x7a, 0x09, 0xfb, 0xe9, 0x9e, 0xc7, 0x7a, 0x1f, 0x53, 0x1a, 0xb8, 0xd5,
69     0x88, 0x9d, 0xd4, 0x79, 0x57, 0x88, 0x68, 0x72, 0x6f};
70
71 // The test extension has a certificate referencing this private key which will
72 // be stored in the system token in the test setup.
73 const unsigned char privateKeyPkcs8System[] = {
74     0x30, 0x82, 0x01, 0x54, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
75     0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
76     0x01, 0x3e, 0x30, 0x82, 0x01, 0x3a, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00,
77     0xe8, 0xb3, 0x04, 0xb1, 0xad, 0xef, 0x6b, 0xe5, 0xbe, 0xc9, 0x05, 0x75,
78     0x07, 0x41, 0xf5, 0x70, 0x50, 0xc2, 0xe8, 0xee, 0xeb, 0x09, 0x9d, 0x49,
79     0x64, 0x4c, 0x60, 0x61, 0x80, 0xbe, 0xc5, 0x41, 0xf3, 0x8c, 0x57, 0x90,
80     0x3a, 0x44, 0x62, 0x6d, 0x51, 0xb8, 0xbb, 0xc6, 0x9a, 0x16, 0xdf, 0xf9,
81     0xce, 0xe3, 0xb8, 0x8c, 0x2e, 0xa2, 0x16, 0xc8, 0xed, 0xc7, 0xf8, 0x4f,
82     0xbd, 0xd3, 0x6e, 0x63, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x40, 0x76,
83     0xc9, 0x83, 0xf8, 0xeb, 0xd0, 0x8f, 0xa4, 0xdd, 0x4a, 0xa2, 0xe5, 0x85,
84     0xc9, 0xee, 0xef, 0xe1, 0xda, 0x4d, 0xac, 0x41, 0x01, 0x4c, 0x70, 0x7d,
85     0xa9, 0xdb, 0x7d, 0x8a, 0x8a, 0x58, 0x09, 0x04, 0x45, 0x43, 0xa4, 0xf3,
86     0xb4, 0x98, 0xf6, 0x34, 0x68, 0x5f, 0xc1, 0xc2, 0xa7, 0x86, 0x3e, 0xec,
87     0x84, 0x0b, 0x18, 0xbc, 0xb1, 0xee, 0x6f, 0x3f, 0xb1, 0x6d, 0xbc, 0x3e,
88     0xbf, 0x6d, 0x31, 0x02, 0x21, 0x00, 0xff, 0x9d, 0x90, 0x4f, 0x0e, 0xe8,
89     0x7e, 0xf3, 0x38, 0xa7, 0xec, 0x73, 0x80, 0xf9, 0x39, 0x2c, 0xaa, 0x33,
90     0x91, 0x72, 0x10, 0x7c, 0x8b, 0xc3, 0x61, 0x6d, 0x40, 0x96, 0xac, 0xb3,
91     0x5e, 0xc9, 0x02, 0x21, 0x00, 0xe9, 0x0c, 0xa1, 0x34, 0xf2, 0x43, 0x3c,
92     0x74, 0xec, 0x1a, 0xf6, 0x80, 0x8e, 0x50, 0x10, 0x6d, 0x55, 0x64, 0xce,
93     0x47, 0x4a, 0x1e, 0x34, 0x27, 0x6c, 0x49, 0x79, 0x6a, 0x23, 0xc6, 0x9d,
94     0xcb, 0x02, 0x20, 0x48, 0xda, 0xa8, 0xc1, 0xcf, 0xb6, 0xf6, 0x4f, 0xee,
95     0x4a, 0xf6, 0x3a, 0xa9, 0x7c, 0xdf, 0x0d, 0xda, 0xe8, 0xdd, 0xc0, 0x8b,
96     0xf0, 0x63, 0x89, 0x69, 0x60, 0x51, 0x33, 0x60, 0xbf, 0xb2, 0xf9, 0x02,
97     0x21, 0x00, 0xb4, 0x77, 0x81, 0x46, 0x7c, 0xec, 0x30, 0x1e, 0xe2, 0xcf,
98     0x26, 0x5f, 0xfa, 0xd4, 0x69, 0x44, 0x21, 0x42, 0x84, 0xb2, 0x93, 0xe4,
99     0xbb, 0xc2, 0x63, 0x8a, 0xaa, 0x28, 0xd5, 0x37, 0x72, 0xed, 0x02, 0x20,
100     0x16, 0xde, 0x3d, 0x57, 0xc5, 0xd5, 0x3d, 0x90, 0x8b, 0xfd, 0x90, 0x3b,
101     0xd8, 0x71, 0x69, 0x5e, 0x8d, 0xb4, 0x48, 0x1c, 0xa4, 0x01, 0xce, 0xc1,
102     0xb5, 0x6f, 0xe9, 0x1b, 0x32, 0x91, 0x34, 0x38
103 };
104
105 const base::FilePath::CharType kTestExtensionDir[] =
106     FILE_PATH_LITERAL("extensions/api_test/enterprise_platform_keys");
107 const base::FilePath::CharType kUpdateManifestFileName[] =
108     FILE_PATH_LITERAL("update_manifest.xml");
109
110 void ImportPrivateKeyPKCS8ToSlot(const unsigned char* pkcs8_der,
111                                  size_t pkcs8_der_size,
112                                  PK11SlotInfo* slot) {
113   SECItem pki_der_user = {
114       siBuffer,
115       // NSS requires non-const data even though it is just for input.
116       const_cast<unsigned char*>(pkcs8_der),
117       pkcs8_der_size};
118
119   SECKEYPrivateKey* seckey = NULL;
120   ASSERT_EQ(SECSuccess,
121             PK11_ImportDERPrivateKeyInfoAndReturnKey(slot,
122                                                      &pki_der_user,
123                                                      NULL,    // nickname
124                                                      NULL,    // publicValue
125                                                      true,    // isPerm
126                                                      true,    // isPrivate
127                                                      KU_ALL,  // usage
128                                                      &seckey,
129                                                      NULL));
130 }
131
132 // The managed_storage extension has a key defined in its manifest, so that
133 // its extension ID is well-known and the policy system can push policies for
134 // the extension.
135 const char kTestExtensionID[] = "aecpbnckhoppanpmefllkdkohionpmig";
136
137 enum SystemToken {
138   SYSTEM_TOKEN_EXISTS,
139   SYSTEM_TOKEN_NOT_EXISTS
140 };
141
142 enum DeviceStatus {
143   DEVICE_STATUS_ENROLLED,
144   DEVICE_STATUS_NOT_ENROLLED
145 };
146
147 enum UserAffiliation {
148   USER_AFFILIATION_ENROLLED_DOMAIN,
149   USER_AFFILIATION_UNRELATED
150 };
151
152 struct Params {
153   Params(SystemToken system_token,
154          DeviceStatus device_status,
155          UserAffiliation user_affiliation)
156       : system_token_(system_token),
157         device_status_(device_status),
158         user_affiliation_(user_affiliation) {}
159
160   SystemToken system_token_;
161   DeviceStatus device_status_;
162   UserAffiliation user_affiliation_;
163 };
164
165 class EnterprisePlatformKeysTest
166     : public ExtensionApiTest,
167       public ::testing::WithParamInterface<Params> {
168  public:
169   EnterprisePlatformKeysTest() {}
170
171   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
172     ExtensionApiTest::SetUpCommandLine(command_line);
173
174     // Enable the WebCrypto API.
175     command_line->AppendSwitch(
176         switches::kEnableExperimentalWebPlatformFeatures);
177
178     std::string user_email = "someuser@anydomain.com";
179
180     // The command line flag kLoginUser determines the user's email and thus
181     // his affiliation to the domain that the device is enrolled to.
182     if (GetParam().user_affiliation_ == USER_AFFILIATION_ENROLLED_DOMAIN)
183       user_email = chromeos::login::kStubUser;
184
185     command_line->AppendSwitchASCII(chromeos::switches::kLoginUser, user_email);
186   }
187
188   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
189     ExtensionApiTest::SetUpInProcessBrowserTestFixture();
190
191     if (GetParam().device_status_ == DEVICE_STATUS_ENROLLED) {
192       device_policy_test_helper_.device_policy()->policy_data().set_username(
193           chromeos::login::kStubUser);
194
195       device_policy_test_helper_.device_policy()->Build();
196       device_policy_test_helper_.MarkAsEnterpriseOwned();
197     }
198
199     EXPECT_CALL(policy_provider_, IsInitializationComplete(testing::_))
200         .WillRepeatedly(testing::Return(true));
201     policy_provider_.SetAutoRefresh();
202     policy::BrowserPolicyConnector::SetPolicyProviderForTesting(
203         &policy_provider_);
204   }
205
206   virtual void SetUpOnMainThread() OVERRIDE {
207     if (GetParam().system_token_ == SYSTEM_TOKEN_EXISTS) {
208       base::RunLoop loop;
209       content::BrowserThread::PostTask(
210           content::BrowserThread::IO,
211           FROM_HERE,
212           base::Bind(&EnterprisePlatformKeysTest::SetUpTestSystemSlotOnIO,
213                      base::Unretained(this),
214                      browser()->profile()->GetResourceContext(),
215                      loop.QuitClosure()));
216       loop.Run();
217     }
218
219     ExtensionApiTest::SetUpOnMainThread();
220
221     // Enable the URLRequestMock, which is required for force-installing the
222     // test extension through policy.
223     content::BrowserThread::PostTask(
224         content::BrowserThread::IO,
225         FROM_HERE,
226         base::Bind(chrome_browser_net::SetUrlRequestMocksEnabled, true));
227
228     {
229       base::RunLoop loop;
230       GetNSSCertDatabaseForProfile(
231           browser()->profile(),
232           base::Bind(&EnterprisePlatformKeysTest::DidGetCertDatabase,
233                      base::Unretained(this),
234                      loop.QuitClosure()));
235       loop.Run();
236     }
237
238     SetPolicy();
239   }
240
241   virtual void TearDownOnMainThread() OVERRIDE {
242     ExtensionApiTest::TearDownOnMainThread();
243
244     if (GetParam().system_token_ == SYSTEM_TOKEN_EXISTS) {
245       base::RunLoop loop;
246       content::BrowserThread::PostTask(
247           content::BrowserThread::IO,
248           FROM_HERE,
249           base::Bind(&EnterprisePlatformKeysTest::TearDownTestSystemSlotOnIO,
250                      base::Unretained(this),
251                      loop.QuitClosure()));
252       loop.Run();
253     }
254   }
255
256  private:
257   void DidGetCertDatabase(const base::Closure& done_callback,
258                           net::NSSCertDatabase* cert_db) {
259     // In order to use a prepared certificate, import a private key to the
260     // user's token for which the Javscript test will import the certificate.
261     ImportPrivateKeyPKCS8ToSlot(privateKeyPkcs8User,
262                                 arraysize(privateKeyPkcs8User),
263                                 cert_db->GetPrivateSlot().get());
264     done_callback.Run();
265   }
266
267   void SetUpTestSystemSlotOnIO(content::ResourceContext* context,
268                                const base::Closure& done_callback) {
269     test_system_slot_.reset(new crypto::ScopedTestSystemNSSKeySlot());
270     ASSERT_TRUE(test_system_slot_->ConstructedSuccessfully());
271
272     // Import a private key to the system slot.  The Javascript part of this
273     // test has a prepared certificate for this key.
274     ImportPrivateKeyPKCS8ToSlot(privateKeyPkcs8System,
275                                 arraysize(privateKeyPkcs8System),
276                                 test_system_slot_->slot());
277
278     content::BrowserThread::PostTask(
279         content::BrowserThread::UI, FROM_HERE, done_callback);
280   }
281
282   void TearDownTestSystemSlotOnIO(const base::Closure& done_callback) {
283     test_system_slot_.reset();
284
285     content::BrowserThread::PostTask(
286         content::BrowserThread::UI, FROM_HERE, done_callback);
287   }
288
289   void SetPolicy() {
290     // Extensions that are force-installed come from an update URL, which
291     // defaults to the webstore. Use a mock URL for this test with an update
292     // manifest that includes the crx file of the test extension.
293     base::FilePath update_manifest_path =
294         base::FilePath(kTestExtensionDir).Append(kUpdateManifestFileName);
295     GURL update_manifest_url(
296         net::URLRequestMockHTTPJob::GetMockUrl(update_manifest_path));
297
298     scoped_ptr<base::ListValue> forcelist(new base::ListValue);
299     forcelist->AppendString(base::StringPrintf(
300         "%s;%s", kTestExtensionID, update_manifest_url.spec().c_str()));
301
302     policy::PolicyMap policy;
303     policy.Set(policy::key::kExtensionInstallForcelist,
304                policy::POLICY_LEVEL_MANDATORY,
305                policy::POLICY_SCOPE_MACHINE,
306                forcelist.release(),
307                NULL);
308
309     // Set the policy and wait until the extension is installed.
310     content::WindowedNotificationObserver observer(
311         extensions::NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED,
312         content::NotificationService::AllSources());
313     policy_provider_.UpdateChromePolicy(policy);
314     observer.Wait();
315   }
316
317   policy::DevicePolicyCrosTestHelper device_policy_test_helper_;
318   scoped_ptr<crypto::ScopedTestSystemNSSKeySlot> test_system_slot_;
319   policy::MockConfigurationPolicyProvider policy_provider_;
320 };
321
322 }  // namespace
323
324 IN_PROC_BROWSER_TEST_P(EnterprisePlatformKeysTest, Basic) {
325   // By default, the system token is disabled.
326   std::string system_token_availability = "";
327
328   // Only if the system token exists, and the current user is of the same domain
329   // as the device is enrolled to, the system token is available to the
330   // extension.
331   if (GetParam().system_token_ == SYSTEM_TOKEN_EXISTS &&
332       GetParam().device_status_ == DEVICE_STATUS_ENROLLED &&
333       GetParam().user_affiliation_ == USER_AFFILIATION_ENROLLED_DOMAIN) {
334     system_token_availability = "systemTokenEnabled";
335   }
336
337   ASSERT_TRUE(RunExtensionSubtest(
338       "",
339       base::StringPrintf("chrome-extension://%s/basic.html?%s",
340                          kTestExtensionID,
341                          system_token_availability.c_str())))
342       << message_;
343 }
344
345 INSTANTIATE_TEST_CASE_P(
346     CheckSystemTokenAvailability,
347     EnterprisePlatformKeysTest,
348     ::testing::Values(Params(SYSTEM_TOKEN_EXISTS,
349                              DEVICE_STATUS_ENROLLED,
350                              USER_AFFILIATION_ENROLLED_DOMAIN),
351                       Params(SYSTEM_TOKEN_EXISTS,
352                              DEVICE_STATUS_ENROLLED,
353                              USER_AFFILIATION_UNRELATED),
354                       Params(SYSTEM_TOKEN_EXISTS,
355                              DEVICE_STATUS_NOT_ENROLLED,
356                              USER_AFFILIATION_UNRELATED),
357                       Params(SYSTEM_TOKEN_NOT_EXISTS,
358                              DEVICE_STATUS_ENROLLED,
359                              USER_AFFILIATION_ENROLLED_DOMAIN)));
360
361 class EnterprisePlatformKeysTestNonPolicyInstalledExtension
362     : public EnterprisePlatformKeysTest {};
363
364 // Ensure that extensions that are not pre-installed by policy throw an install
365 // warning if they request the enterprise.platformKeys permission in the
366 // manifest and that such extensions don't see the
367 // chrome.enterprise.platformKeys namespace.
368 IN_PROC_BROWSER_TEST_F(ExtensionApiTest,
369                        EnterprisePlatformKeysIsRestrictedToPolicyExtension) {
370   ASSERT_TRUE(RunExtensionSubtest("enterprise_platform_keys",
371                                   "api_not_available.html",
372                                   kFlagIgnoreManifestWarnings));
373
374   base::FilePath extension_path =
375       test_data_dir_.AppendASCII("enterprise_platform_keys");
376   ExtensionService* service =
377       extensions::ExtensionSystem::Get(profile())->extension_service();
378   const extensions::Extension* extension =
379       GetExtensionByPath(service->extensions(), extension_path);
380   ASSERT_FALSE(extension->install_warnings().empty());
381   EXPECT_EQ(
382       "'enterprise.platformKeys' is not allowed for specified install "
383       "location.",
384       extension->install_warnings()[0].message);
385 }