enterprise_platform_keys_apitest_nss.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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 "content/test/net/url_request_mock_http_job.h" 23#include "crypto/nss_util_internal.h" 24#include "crypto/scoped_test_system_nss_key_slot.h" 25#include "extensions/browser/notification_types.h" 26#include "net/base/net_errors.h" 27#include "net/cert/nss_cert_database.h" 28#include "policy/policy_constants.h" 29#include "testing/gmock/include/gmock/gmock.h" 30 31namespace { 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 40const 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. 73const 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 105const base::FilePath::CharType kTestExtensionDir[] = 106 FILE_PATH_LITERAL("extensions/api_test/enterprise_platform_keys"); 107const base::FilePath::CharType kUpdateManifestFileName[] = 108 FILE_PATH_LITERAL("update_manifest.xml"); 109 110void 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. 135const char kTestExtensionID[] = "aecpbnckhoppanpmefllkdkohionpmig"; 136 137class EnterprisePlatformKeysTest : public ExtensionApiTest { 138 public: 139 EnterprisePlatformKeysTest() : nss_db_(NULL) {} 140 141 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 142 ExtensionApiTest::SetUpCommandLine(command_line); 143 144 // Enable the WebCrypto API. 145 command_line->AppendSwitch( 146 switches::kEnableExperimentalWebPlatformFeatures); 147 148 command_line->AppendSwitchASCII(chromeos::switches::kLoginUser, 149 chromeos::login::kStubUser); 150 } 151 152 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 153 ExtensionApiTest::SetUpInProcessBrowserTestFixture(); 154 155 device_policy_test_helper_.device_policy()->policy_data().set_username( 156 chromeos::login::kStubUser); 157 158 device_policy_test_helper_.device_policy()->Build(); 159 device_policy_test_helper_.MarkAsEnterpriseOwned(); 160 161 EXPECT_CALL(policy_provider_, IsInitializationComplete(testing::_)) 162 .WillRepeatedly(testing::Return(true)); 163 policy_provider_.SetAutoRefresh(); 164 policy::BrowserPolicyConnector::SetPolicyProviderForTesting( 165 &policy_provider_); 166 } 167 168 virtual void SetUpOnMainThread() OVERRIDE { 169 ExtensionApiTest::SetUpOnMainThread(); 170 171 // Enable the URLRequestMock, which is required for force-installing the 172 // test extension through policy. 173 content::BrowserThread::PostTask( 174 content::BrowserThread::IO, 175 FROM_HERE, 176 base::Bind(chrome_browser_net::SetUrlRequestMocksEnabled, true)); 177 178 { 179 base::RunLoop loop; 180 GetNSSCertDatabaseForProfile( 181 browser()->profile(), 182 base::Bind(&EnterprisePlatformKeysTest::DidGetCertDatabase, 183 base::Unretained(this), 184 loop.QuitClosure())); 185 loop.Run(); 186 } 187 188 SetPolicy(); 189 } 190 191 void SetUpTestSystemSlot() { 192 base::RunLoop loop; 193 content::BrowserThread::PostTask( 194 content::BrowserThread::IO, 195 FROM_HERE, 196 base::Bind(&EnterprisePlatformKeysTest::SetUpTestSystemSlotOnIO, 197 base::Unretained(this), 198 browser()->profile()->GetResourceContext(), 199 loop.QuitClosure())); 200 loop.Run(); 201 } 202 203 void TearDownTestSystemSlot() { 204 base::RunLoop loop; 205 content::BrowserThread::PostTask( 206 content::BrowserThread::IO, 207 FROM_HERE, 208 base::Bind(&EnterprisePlatformKeysTest::TearDownTestSystemSlotOnIO, 209 base::Unretained(this), 210 loop.QuitClosure())); 211 loop.Run(); 212 } 213 214 private: 215 void DidGetCertDatabase(const base::Closure& done_callback, 216 net::NSSCertDatabase* cert_db) { 217 nss_db_ = cert_db; 218 219 // In order to use a prepared certificate, import a private key to the 220 // user's token for which the Javscript test will import the certificate. 221 ImportPrivateKeyPKCS8ToSlot(privateKeyPkcs8User, 222 arraysize(privateKeyPkcs8User), 223 cert_db->GetPrivateSlot().get()); 224 done_callback.Run(); 225 } 226 227 void SetUpTestSystemSlotOnIO(content::ResourceContext* context, 228 const base::Closure& done_callback) { 229 test_system_slot_.reset(new crypto::ScopedTestSystemNSSKeySlot()); 230 ASSERT_TRUE(test_system_slot_->ConstructedSuccessfully()); 231 232 // Import a private key to the system slot. The Javascript part of this 233 // test has a prepared certificate for this key. 234 ImportPrivateKeyPKCS8ToSlot(privateKeyPkcs8System, 235 arraysize(privateKeyPkcs8System), 236 test_system_slot_->slot()); 237 238 content::BrowserThread::PostTask( 239 content::BrowserThread::UI, FROM_HERE, done_callback); 240 } 241 242 void TearDownTestSystemSlotOnIO(const base::Closure& done_callback) { 243 test_system_slot_.reset(); 244 245 content::BrowserThread::PostTask( 246 content::BrowserThread::UI, FROM_HERE, done_callback); 247 } 248 249 void SetPolicy() { 250 // Extensions that are force-installed come from an update URL, which 251 // defaults to the webstore. Use a mock URL for this test with an update 252 // manifest that includes the crx file of the test extension. 253 base::FilePath update_manifest_path = 254 base::FilePath(kTestExtensionDir).Append(kUpdateManifestFileName); 255 GURL update_manifest_url( 256 content::URLRequestMockHTTPJob::GetMockUrl(update_manifest_path)); 257 258 scoped_ptr<base::ListValue> forcelist(new base::ListValue); 259 forcelist->AppendString(base::StringPrintf( 260 "%s;%s", kTestExtensionID, update_manifest_url.spec().c_str())); 261 262 policy::PolicyMap policy; 263 policy.Set(policy::key::kExtensionInstallForcelist, 264 policy::POLICY_LEVEL_MANDATORY, 265 policy::POLICY_SCOPE_MACHINE, 266 forcelist.release(), 267 NULL); 268 269 // Set the policy and wait until the extension is installed. 270 content::WindowedNotificationObserver observer( 271 extensions::NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED, 272 content::NotificationService::AllSources()); 273 policy_provider_.UpdateChromePolicy(policy); 274 observer.Wait(); 275 } 276 277 net::NSSCertDatabase* nss_db_; 278 policy::DevicePolicyCrosTestHelper device_policy_test_helper_; 279 scoped_ptr<crypto::ScopedTestSystemNSSKeySlot> test_system_slot_; 280 policy::MockConfigurationPolicyProvider policy_provider_; 281}; 282 283} // namespace 284 285IN_PROC_BROWSER_TEST_F(EnterprisePlatformKeysTest, SystemTokenEnabled) { 286 SetUpTestSystemSlot(); 287 ASSERT_TRUE(RunExtensionSubtest( 288 "", 289 base::StringPrintf("chrome-extension://%s/basic.html?systemTokenEnabled", 290 kTestExtensionID))) 291 << message_; 292 TearDownTestSystemSlot(); 293} 294 295IN_PROC_BROWSER_TEST_F(EnterprisePlatformKeysTest, SystemTokenDisabled) { 296 ASSERT_TRUE(RunExtensionSubtest( 297 "", 298 base::StringPrintf("chrome-extension://%s/basic.html", kTestExtensionID))) 299 << message_; 300} 301 302// Ensure that extensions that are not pre-installed by policy throw an install 303// warning if they request the enterprise.platformKeys permission in the 304// manifest and that such extensions don't see the 305// chrome.enterprise.platformKeys namespace. 306IN_PROC_BROWSER_TEST_F(ExtensionApiTest, 307 EnterprisePlatformKeysIsRestrictedToPolicyExtension) { 308 ASSERT_TRUE(RunExtensionSubtest("enterprise_platform_keys", 309 "api_not_available.html", 310 kFlagIgnoreManifestWarnings)); 311 312 base::FilePath extension_path = 313 test_data_dir_.AppendASCII("enterprise_platform_keys"); 314 ExtensionService* service = extensions::ExtensionSystem::Get( 315 profile())->extension_service(); 316 const extensions::Extension* extension = 317 GetExtensionByPath(service->extensions(), extension_path); 318 ASSERT_FALSE(extension->install_warnings().empty()); 319 EXPECT_EQ( 320 "'enterprise.platformKeys' is not allowed for specified install " 321 "location.", 322 extension->install_warnings()[0].message); 323} 324