1 // Copyright 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. 4 5 #include "chromeos/network/network_cert_migrator.h" 6 7 #include <cert.h> 8 9 #include "base/files/file_path.h" 10 #include "base/files/file_util.h" 11 #include "base/run_loop.h" 12 #include "base/strings/string_number_conversions.h" 13 #include "chromeos/cert_loader.h" 14 #include "chromeos/dbus/dbus_thread_manager.h" 15 #include "chromeos/dbus/shill_profile_client.h" 16 #include "chromeos/dbus/shill_service_client.h" 17 #include "chromeos/network/network_state_handler.h" 18 #include "chromeos/tpm_token_loader.h" 19 #include "crypto/nss_util_internal.h" 20 #include "crypto/scoped_test_nss_chromeos_user.h" 21 #include "net/base/crypto_module.h" 22 #include "net/base/net_errors.h" 23 #include "net/base/test_data_directory.h" 24 #include "net/cert/nss_cert_database_chromeos.h" 25 #include "net/cert/x509_certificate.h" 26 #include "net/test/cert_test_util.h" 27 #include "testing/gtest/include/gtest/gtest.h" 28 #include "third_party/cros_system_api/dbus/service_constants.h" 29 30 namespace chromeos { 31 32 namespace { 33 34 const char* kWifiStub = "wifi_stub"; 35 const char* kEthernetEapStub = "ethernet_eap_stub"; 36 const char* kVPNStub = "vpn_stub"; 37 const char* kNSSNickname = "nss_nickname"; 38 const char* kFakePEM = "pem"; 39 const char* kProfile = "/profile/profile1"; 40 41 } // namespace 42 43 class NetworkCertMigratorTest : public testing::Test { 44 public: 45 NetworkCertMigratorTest() : service_test_(NULL), 46 user_("user_hash") { 47 } 48 virtual ~NetworkCertMigratorTest() {} 49 50 virtual void SetUp() OVERRIDE { 51 // Initialize NSS db for the user. 52 ASSERT_TRUE(user_.constructed_successfully()); 53 user_.FinishInit(); 54 test_nssdb_.reset(new net::NSSCertDatabaseChromeOS( 55 crypto::GetPublicSlotForChromeOSUser(user_.username_hash()), 56 crypto::GetPrivateSlotForChromeOSUser( 57 user_.username_hash(), 58 base::Callback<void(crypto::ScopedPK11Slot)>()))); 59 test_nssdb_->SetSlowTaskRunnerForTest(message_loop_.message_loop_proxy()); 60 61 DBusThreadManager::Initialize(); 62 service_test_ = 63 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface(); 64 DBusThreadManager::Get() 65 ->GetShillProfileClient() 66 ->GetTestInterface() 67 ->AddProfile(kProfile, "" /* userhash */); 68 base::RunLoop().RunUntilIdle(); 69 service_test_->ClearServices(); 70 base::RunLoop().RunUntilIdle(); 71 72 CertLoader::Initialize(); 73 CertLoader* cert_loader_ = CertLoader::Get(); 74 cert_loader_->StartWithNSSDB(test_nssdb_.get()); 75 } 76 77 virtual void TearDown() OVERRIDE { 78 network_cert_migrator_.reset(); 79 network_state_handler_.reset(); 80 CertLoader::Shutdown(); 81 DBusThreadManager::Shutdown(); 82 CleanupTestCert(); 83 } 84 85 protected: 86 void SetupTestCACert() { 87 scoped_refptr<net::X509Certificate> cert_wo_nickname = 88 net::CreateCertificateListFromFile(net::GetTestCertsDirectory(), 89 "eku-test-root.pem", 90 net::X509Certificate::FORMAT_AUTO) 91 .back(); 92 net::X509Certificate::GetPEMEncoded(cert_wo_nickname->os_cert_handle(), 93 &test_ca_cert_pem_); 94 std::string der_encoded; 95 net::X509Certificate::GetDEREncoded(cert_wo_nickname->os_cert_handle(), 96 &der_encoded); 97 cert_wo_nickname = NULL; 98 99 test_ca_cert_ = net::X509Certificate::CreateFromBytesWithNickname( 100 der_encoded.data(), der_encoded.size(), kNSSNickname); 101 net::CertificateList cert_list; 102 cert_list.push_back(test_ca_cert_); 103 net::NSSCertDatabase::ImportCertFailureList failures; 104 EXPECT_TRUE(test_nssdb_->ImportCACerts( 105 cert_list, net::NSSCertDatabase::TRUST_DEFAULT, &failures)); 106 ASSERT_TRUE(failures.empty()) << net::ErrorToString(failures[0].net_error); 107 } 108 109 void SetupTestClientCert() { 110 std::string pkcs12_data; 111 ASSERT_TRUE(base::ReadFileToString( 112 net::GetTestCertsDirectory().Append("websocket_client_cert.p12"), 113 &pkcs12_data)); 114 115 net::CertificateList client_cert_list; 116 scoped_refptr<net::CryptoModule> module(net::CryptoModule::CreateFromHandle( 117 test_nssdb_->GetPrivateSlot().get())); 118 ASSERT_EQ(net::OK, 119 test_nssdb_->ImportFromPKCS12(module.get(), 120 pkcs12_data, 121 base::string16(), 122 false, 123 &client_cert_list)); 124 ASSERT_TRUE(!client_cert_list.empty()); 125 test_client_cert_ = client_cert_list[0]; 126 127 int slot_id = -1; 128 test_client_cert_pkcs11_id_ = CertLoader::GetPkcs11IdAndSlotForCert( 129 *test_client_cert_, &slot_id); 130 ASSERT_FALSE(test_client_cert_pkcs11_id_.empty()); 131 ASSERT_NE(-1, slot_id); 132 test_client_cert_slot_id_ = base::IntToString(slot_id); 133 } 134 135 void SetupNetworkHandlers() { 136 network_state_handler_.reset(NetworkStateHandler::InitializeForTest()); 137 network_cert_migrator_.reset(new NetworkCertMigrator); 138 network_cert_migrator_->Init(network_state_handler_.get()); 139 } 140 141 void AddService(const std::string& network_id, 142 const std::string& type, 143 const std::string& state) { 144 service_test_->AddService(network_id /* service_path */, 145 network_id /* guid */, 146 network_id /* name */, 147 type, 148 state, 149 true /* add_to_visible */); 150 151 // Ensure that the service appears as 'configured', i.e. is associated to a 152 // Shill profile. 153 service_test_->SetServiceProperty( 154 network_id, shill::kProfileProperty, base::StringValue(kProfile)); 155 } 156 157 void SetupWifiWithNss() { 158 AddService(kWifiStub, shill::kTypeWifi, shill::kStateOnline); 159 service_test_->SetServiceProperty(kWifiStub, 160 shill::kEapCaCertNssProperty, 161 base::StringValue(kNSSNickname)); 162 } 163 164 void SetupNetworkWithEapCertId(bool wifi, const std::string& cert_id) { 165 std::string type = wifi ? shill::kTypeWifi: shill::kTypeEthernetEap; 166 std::string name = wifi ? kWifiStub : kEthernetEapStub; 167 AddService(name, type, shill::kStateOnline); 168 service_test_->SetServiceProperty( 169 name, shill::kEapCertIdProperty, base::StringValue(cert_id)); 170 service_test_->SetServiceProperty( 171 name, shill::kEapKeyIdProperty, base::StringValue(cert_id)); 172 173 if (wifi) { 174 service_test_->SetServiceProperty( 175 name, 176 shill::kSecurityProperty, 177 base::StringValue(shill::kSecurity8021x)); 178 } 179 } 180 181 void GetEapCertId(bool wifi, std::string* cert_id) { 182 cert_id->clear(); 183 184 std::string name = wifi ? kWifiStub : kEthernetEapStub; 185 const base::DictionaryValue* properties = 186 service_test_->GetServiceProperties(name); 187 properties->GetStringWithoutPathExpansion(shill::kEapCertIdProperty, 188 cert_id); 189 } 190 191 void SetupVpnWithCertId(bool open_vpn, 192 const std::string& slot_id, 193 const std::string& pkcs11_id) { 194 AddService(kVPNStub, shill::kTypeVPN, shill::kStateIdle); 195 base::DictionaryValue provider; 196 if (open_vpn) { 197 provider.SetStringWithoutPathExpansion(shill::kTypeProperty, 198 shill::kProviderOpenVpn); 199 provider.SetStringWithoutPathExpansion( 200 shill::kOpenVPNClientCertIdProperty, pkcs11_id); 201 } else { 202 provider.SetStringWithoutPathExpansion(shill::kTypeProperty, 203 shill::kProviderL2tpIpsec); 204 provider.SetStringWithoutPathExpansion( 205 shill::kL2tpIpsecClientCertSlotProperty, slot_id); 206 provider.SetStringWithoutPathExpansion( 207 shill::kL2tpIpsecClientCertIdProperty, pkcs11_id); 208 } 209 service_test_->SetServiceProperty( 210 kVPNStub, shill::kProviderProperty, provider); 211 } 212 213 void GetVpnCertId(bool open_vpn, 214 std::string* slot_id, 215 std::string* pkcs11_id) { 216 slot_id->clear(); 217 pkcs11_id->clear(); 218 219 const base::DictionaryValue* properties = 220 service_test_->GetServiceProperties(kVPNStub); 221 ASSERT_TRUE(properties); 222 const base::DictionaryValue* provider = NULL; 223 properties->GetDictionaryWithoutPathExpansion(shill::kProviderProperty, 224 &provider); 225 if (!provider) 226 return; 227 if (open_vpn) { 228 provider->GetStringWithoutPathExpansion( 229 shill::kOpenVPNClientCertIdProperty, pkcs11_id); 230 } else { 231 provider->GetStringWithoutPathExpansion( 232 shill::kL2tpIpsecClientCertSlotProperty, slot_id); 233 provider->GetStringWithoutPathExpansion( 234 shill::kL2tpIpsecClientCertIdProperty, pkcs11_id); 235 } 236 } 237 238 void GetEapCACertProperties(std::string* nss_nickname, std::string* ca_pem) { 239 nss_nickname->clear(); 240 ca_pem->clear(); 241 const base::DictionaryValue* properties = 242 service_test_->GetServiceProperties(kWifiStub); 243 properties->GetStringWithoutPathExpansion(shill::kEapCaCertNssProperty, 244 nss_nickname); 245 const base::ListValue* ca_pems = NULL; 246 properties->GetListWithoutPathExpansion(shill::kEapCaCertPemProperty, 247 &ca_pems); 248 if (ca_pems && !ca_pems->empty()) 249 ca_pems->GetString(0, ca_pem); 250 } 251 252 void SetupVpnWithNss(bool open_vpn) { 253 AddService(kVPNStub, shill::kTypeVPN, shill::kStateIdle); 254 base::DictionaryValue provider; 255 const char* nss_property = open_vpn ? shill::kOpenVPNCaCertNSSProperty 256 : shill::kL2tpIpsecCaCertNssProperty; 257 provider.SetStringWithoutPathExpansion(nss_property, kNSSNickname); 258 service_test_->SetServiceProperty( 259 kVPNStub, shill::kProviderProperty, provider); 260 } 261 262 void GetVpnCACertProperties(bool open_vpn, 263 std::string* nss_nickname, 264 std::string* ca_pem) { 265 nss_nickname->clear(); 266 ca_pem->clear(); 267 const base::DictionaryValue* properties = 268 service_test_->GetServiceProperties(kVPNStub); 269 const base::DictionaryValue* provider = NULL; 270 properties->GetDictionaryWithoutPathExpansion(shill::kProviderProperty, 271 &provider); 272 if (!provider) 273 return; 274 const char* nss_property = open_vpn ? shill::kOpenVPNCaCertNSSProperty 275 : shill::kL2tpIpsecCaCertNssProperty; 276 provider->GetStringWithoutPathExpansion(nss_property, nss_nickname); 277 const base::ListValue* ca_pems = NULL; 278 const char* pem_property = open_vpn ? shill::kOpenVPNCaCertPemProperty 279 : shill::kL2tpIpsecCaCertPemProperty; 280 provider->GetListWithoutPathExpansion(pem_property, &ca_pems); 281 if (ca_pems && !ca_pems->empty()) 282 ca_pems->GetString(0, ca_pem); 283 } 284 285 ShillServiceClient::TestInterface* service_test_; 286 scoped_refptr<net::X509Certificate> test_ca_cert_; 287 scoped_refptr<net::X509Certificate> test_client_cert_; 288 std::string test_client_cert_pkcs11_id_; 289 std::string test_client_cert_slot_id_; 290 std::string test_ca_cert_pem_; 291 base::MessageLoop message_loop_; 292 293 private: 294 void CleanupTestCert() { 295 if (test_ca_cert_.get()) 296 ASSERT_TRUE(test_nssdb_->DeleteCertAndKey(test_ca_cert_.get())); 297 298 if (test_client_cert_.get()) 299 ASSERT_TRUE(test_nssdb_->DeleteCertAndKey(test_client_cert_.get())); 300 } 301 302 scoped_ptr<NetworkStateHandler> network_state_handler_; 303 scoped_ptr<NetworkCertMigrator> network_cert_migrator_; 304 crypto::ScopedTestNSSChromeOSUser user_; 305 scoped_ptr<net::NSSCertDatabaseChromeOS> test_nssdb_; 306 307 DISALLOW_COPY_AND_ASSIGN(NetworkCertMigratorTest); 308 }; 309 310 TEST_F(NetworkCertMigratorTest, MigrateNssOnInitialization) { 311 // Add a new network for migration before the handlers are initialized. 312 SetupWifiWithNss(); 313 SetupTestCACert(); 314 SetupNetworkHandlers(); 315 316 base::RunLoop().RunUntilIdle(); 317 std::string nss_nickname, ca_pem; 318 GetEapCACertProperties(&nss_nickname, &ca_pem); 319 EXPECT_TRUE(nss_nickname.empty()); 320 EXPECT_EQ(test_ca_cert_pem_, ca_pem); 321 } 322 323 TEST_F(NetworkCertMigratorTest, MigrateNssOnNetworkAppearance) { 324 SetupTestCACert(); 325 SetupNetworkHandlers(); 326 base::RunLoop().RunUntilIdle(); 327 328 // Add a new network for migration after the handlers are initialized. 329 SetupWifiWithNss(); 330 331 base::RunLoop().RunUntilIdle(); 332 std::string nss_nickname, ca_pem; 333 GetEapCACertProperties(&nss_nickname, &ca_pem); 334 EXPECT_TRUE(nss_nickname.empty()); 335 EXPECT_EQ(test_ca_cert_pem_, ca_pem); 336 } 337 338 TEST_F(NetworkCertMigratorTest, DoNotMigrateNssIfPemSet) { 339 // Add a new network with an already set PEM property. 340 SetupWifiWithNss(); 341 base::ListValue ca_pems; 342 ca_pems.AppendString(kFakePEM); 343 service_test_->SetServiceProperty( 344 kWifiStub, shill::kEapCaCertPemProperty, ca_pems); 345 346 SetupTestCACert(); 347 SetupNetworkHandlers(); 348 base::RunLoop().RunUntilIdle(); 349 350 std::string nss_nickname, ca_pem; 351 GetEapCACertProperties(&nss_nickname, &ca_pem); 352 EXPECT_TRUE(nss_nickname.empty()); 353 EXPECT_EQ(kFakePEM, ca_pem); 354 } 355 356 TEST_F(NetworkCertMigratorTest, MigrateNssOpenVpn) { 357 // Add a new network for migration before the handlers are initialized. 358 SetupVpnWithNss(true /* OpenVPN */); 359 360 SetupTestCACert(); 361 SetupNetworkHandlers(); 362 363 base::RunLoop().RunUntilIdle(); 364 std::string nss_nickname, ca_pem; 365 GetVpnCACertProperties(true /* OpenVPN */, &nss_nickname, &ca_pem); 366 EXPECT_TRUE(nss_nickname.empty()); 367 EXPECT_EQ(test_ca_cert_pem_, ca_pem); 368 } 369 370 TEST_F(NetworkCertMigratorTest, MigrateNssIpsecVpn) { 371 // Add a new network for migration before the handlers are initialized. 372 SetupVpnWithNss(false /* not OpenVPN */); 373 374 SetupTestCACert(); 375 SetupNetworkHandlers(); 376 377 base::RunLoop().RunUntilIdle(); 378 std::string nss_nickname, ca_pem; 379 GetVpnCACertProperties(false /* not OpenVPN */, &nss_nickname, &ca_pem); 380 EXPECT_TRUE(nss_nickname.empty()); 381 EXPECT_EQ(test_ca_cert_pem_, ca_pem); 382 } 383 384 TEST_F(NetworkCertMigratorTest, MigrateEapCertIdNoMatchingCert) { 385 SetupTestClientCert(); 386 SetupNetworkHandlers(); 387 base::RunLoop().RunUntilIdle(); 388 389 // Add a new network for migration after the handlers are initialized. 390 SetupNetworkWithEapCertId(true /* wifi */, "unknown pkcs11 id"); 391 392 base::RunLoop().RunUntilIdle(); 393 // Since the PKCS11 ID is unknown, the certificate configuration will be 394 // cleared. 395 std::string cert_id; 396 GetEapCertId(true /* wifi */, &cert_id); 397 EXPECT_EQ(std::string(), cert_id); 398 } 399 400 TEST_F(NetworkCertMigratorTest, MigrateEapCertIdNoSlotId) { 401 SetupTestClientCert(); 402 SetupNetworkHandlers(); 403 base::RunLoop().RunUntilIdle(); 404 405 // Add a new network for migration after the handlers are initialized. 406 SetupNetworkWithEapCertId(true /* wifi */, test_client_cert_pkcs11_id_); 407 408 base::RunLoop().RunUntilIdle(); 409 410 std::string cert_id; 411 GetEapCertId(true /* wifi */, &cert_id); 412 std::string expected_cert_id = 413 test_client_cert_slot_id_ + ":" + test_client_cert_pkcs11_id_; 414 EXPECT_EQ(expected_cert_id, cert_id); 415 } 416 417 TEST_F(NetworkCertMigratorTest, MigrateWifiEapCertIdWrongSlotId) { 418 SetupTestClientCert(); 419 SetupNetworkHandlers(); 420 base::RunLoop().RunUntilIdle(); 421 422 // Add a new network for migration after the handlers are initialized. 423 SetupNetworkWithEapCertId(true /* wifi */, 424 "123:" + test_client_cert_pkcs11_id_); 425 426 base::RunLoop().RunUntilIdle(); 427 428 std::string cert_id; 429 GetEapCertId(true /* wifi */, &cert_id); 430 std::string expected_cert_id = 431 test_client_cert_slot_id_ + ":" + test_client_cert_pkcs11_id_; 432 EXPECT_EQ(expected_cert_id, cert_id); 433 } 434 435 TEST_F(NetworkCertMigratorTest, DoNotChangeEapCertIdWithCorrectSlotId) { 436 SetupTestClientCert(); 437 SetupNetworkHandlers(); 438 base::RunLoop().RunUntilIdle(); 439 440 std::string expected_cert_id = 441 test_client_cert_slot_id_ + ":" + test_client_cert_pkcs11_id_; 442 443 // Add a new network for migration after the handlers are initialized. 444 SetupNetworkWithEapCertId(true /* wifi */, expected_cert_id); 445 446 base::RunLoop().RunUntilIdle(); 447 448 std::string cert_id; 449 GetEapCertId(true /* wifi */, &cert_id); 450 EXPECT_EQ(expected_cert_id, cert_id); 451 } 452 453 TEST_F(NetworkCertMigratorTest, IgnoreOpenVPNCertId) { 454 SetupTestClientCert(); 455 SetupNetworkHandlers(); 456 base::RunLoop().RunUntilIdle(); 457 458 const char kPkcs11Id[] = "any slot id"; 459 460 // Add a new network for migration after the handlers are initialized. 461 SetupVpnWithCertId( 462 true /* OpenVPN */, std::string() /* no slot id */, kPkcs11Id); 463 464 base::RunLoop().RunUntilIdle(); 465 466 std::string pkcs11_id; 467 std::string unused_slot_id; 468 GetVpnCertId(true /* OpenVPN */, &unused_slot_id, &pkcs11_id); 469 EXPECT_EQ(kPkcs11Id, pkcs11_id); 470 } 471 472 TEST_F(NetworkCertMigratorTest, MigrateEthernetEapCertIdWrongSlotId) { 473 SetupTestClientCert(); 474 SetupNetworkHandlers(); 475 base::RunLoop().RunUntilIdle(); 476 477 // Add a new network for migration after the handlers are initialized. 478 SetupNetworkWithEapCertId( 479 false /* ethernet */, "123:" + test_client_cert_pkcs11_id_); 480 481 base::RunLoop().RunUntilIdle(); 482 483 std::string cert_id; 484 GetEapCertId(false /* ethernet */, &cert_id); 485 std::string expected_cert_id = 486 test_client_cert_slot_id_ + ":" + test_client_cert_pkcs11_id_; 487 EXPECT_EQ(expected_cert_id, cert_id); 488 } 489 490 TEST_F(NetworkCertMigratorTest, MigrateIpsecCertIdWrongSlotId) { 491 SetupTestClientCert(); 492 SetupNetworkHandlers(); 493 base::RunLoop().RunUntilIdle(); 494 495 // Add a new network for migration after the handlers are initialized. 496 SetupVpnWithCertId(false /* IPsec */, "123", test_client_cert_pkcs11_id_); 497 498 base::RunLoop().RunUntilIdle(); 499 500 std::string pkcs11_id; 501 std::string slot_id; 502 GetVpnCertId(false /* IPsec */, &slot_id, &pkcs11_id); 503 EXPECT_EQ(test_client_cert_pkcs11_id_, pkcs11_id); 504 EXPECT_EQ(test_client_cert_slot_id_, slot_id); 505 } 506 507 } // namespace chromeos 508