network_cert_migrator_unittest.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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/file_util.h" 10#include "base/files/file_path.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 30namespace chromeos { 31 32namespace { 33 34const char* kWifiStub = "wifi_stub"; 35const char* kEthernetEapStub = "ethernet_eap_stub"; 36const char* kVPNStub = "vpn_stub"; 37const char* kNSSNickname = "nss_nickname"; 38const char* kFakePEM = "pem"; 39const char* kProfile = "/profile/profile1"; 40 41} // namespace 42 43class 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::InitializeWithStub(); 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( 119 net::OK, 120 test_nssdb_->ImportFromPKCS12( 121 module, pkcs12_data, base::string16(), false, &client_cert_list)); 122 ASSERT_TRUE(!client_cert_list.empty()); 123 test_client_cert_ = client_cert_list[0]; 124 125 int slot_id = -1; 126 test_client_cert_pkcs11_id_ = CertLoader::GetPkcs11IdAndSlotForCert( 127 *test_client_cert_, &slot_id); 128 ASSERT_FALSE(test_client_cert_pkcs11_id_.empty()); 129 ASSERT_NE(-1, slot_id); 130 test_client_cert_slot_id_ = base::IntToString(slot_id); 131 } 132 133 void SetupNetworkHandlers() { 134 network_state_handler_.reset(NetworkStateHandler::InitializeForTest()); 135 network_cert_migrator_.reset(new NetworkCertMigrator); 136 network_cert_migrator_->Init(network_state_handler_.get()); 137 } 138 139 void AddService(const std::string& network_id, 140 const std::string& type, 141 const std::string& state) { 142 service_test_->AddService(network_id /* service_path */, 143 network_id /* guid */, 144 network_id /* name */, 145 type, 146 state, 147 true /* add_to_visible */); 148 149 // Ensure that the service appears as 'configured', i.e. is associated to a 150 // Shill profile. 151 service_test_->SetServiceProperty( 152 network_id, shill::kProfileProperty, base::StringValue(kProfile)); 153 } 154 155 void SetupWifiWithNss() { 156 AddService(kWifiStub, shill::kTypeWifi, shill::kStateOnline); 157 service_test_->SetServiceProperty(kWifiStub, 158 shill::kEapCaCertNssProperty, 159 base::StringValue(kNSSNickname)); 160 } 161 162 void SetupNetworkWithEapCertId(bool wifi, const std::string& cert_id) { 163 std::string type = wifi ? shill::kTypeWifi: shill::kTypeEthernetEap; 164 std::string name = wifi ? kWifiStub : kEthernetEapStub; 165 AddService(name, type, shill::kStateOnline); 166 service_test_->SetServiceProperty( 167 name, shill::kEapCertIdProperty, base::StringValue(cert_id)); 168 service_test_->SetServiceProperty( 169 name, shill::kEapKeyIdProperty, base::StringValue(cert_id)); 170 171 if (wifi) { 172 service_test_->SetServiceProperty( 173 name, 174 shill::kSecurityProperty, 175 base::StringValue(shill::kSecurity8021x)); 176 } 177 } 178 179 void GetEapCertId(bool wifi, std::string* cert_id) { 180 cert_id->clear(); 181 182 std::string name = wifi ? kWifiStub : kEthernetEapStub; 183 const base::DictionaryValue* properties = 184 service_test_->GetServiceProperties(name); 185 properties->GetStringWithoutPathExpansion(shill::kEapCertIdProperty, 186 cert_id); 187 } 188 189 void SetupVpnWithCertId(bool open_vpn, 190 const std::string& slot_id, 191 const std::string& pkcs11_id) { 192 AddService(kVPNStub, shill::kTypeVPN, shill::kStateIdle); 193 base::DictionaryValue provider; 194 if (open_vpn) { 195 provider.SetStringWithoutPathExpansion(shill::kTypeProperty, 196 shill::kProviderOpenVpn); 197 provider.SetStringWithoutPathExpansion( 198 shill::kOpenVPNClientCertIdProperty, pkcs11_id); 199 } else { 200 provider.SetStringWithoutPathExpansion(shill::kTypeProperty, 201 shill::kProviderL2tpIpsec); 202 provider.SetStringWithoutPathExpansion( 203 shill::kL2tpIpsecClientCertSlotProperty, slot_id); 204 provider.SetStringWithoutPathExpansion( 205 shill::kL2tpIpsecClientCertIdProperty, pkcs11_id); 206 } 207 service_test_->SetServiceProperty( 208 kVPNStub, shill::kProviderProperty, provider); 209 } 210 211 void GetVpnCertId(bool open_vpn, 212 std::string* slot_id, 213 std::string* pkcs11_id) { 214 slot_id->clear(); 215 pkcs11_id->clear(); 216 217 const base::DictionaryValue* properties = 218 service_test_->GetServiceProperties(kVPNStub); 219 ASSERT_TRUE(properties); 220 const base::DictionaryValue* provider = NULL; 221 properties->GetDictionaryWithoutPathExpansion(shill::kProviderProperty, 222 &provider); 223 if (!provider) 224 return; 225 if (open_vpn) { 226 provider->GetStringWithoutPathExpansion( 227 shill::kOpenVPNClientCertIdProperty, pkcs11_id); 228 } else { 229 provider->GetStringWithoutPathExpansion( 230 shill::kL2tpIpsecClientCertSlotProperty, slot_id); 231 provider->GetStringWithoutPathExpansion( 232 shill::kL2tpIpsecClientCertIdProperty, pkcs11_id); 233 } 234 } 235 236 void GetEapCACertProperties(std::string* nss_nickname, std::string* ca_pem) { 237 nss_nickname->clear(); 238 ca_pem->clear(); 239 const base::DictionaryValue* properties = 240 service_test_->GetServiceProperties(kWifiStub); 241 properties->GetStringWithoutPathExpansion(shill::kEapCaCertNssProperty, 242 nss_nickname); 243 const base::ListValue* ca_pems = NULL; 244 properties->GetListWithoutPathExpansion(shill::kEapCaCertPemProperty, 245 &ca_pems); 246 if (ca_pems && !ca_pems->empty()) 247 ca_pems->GetString(0, ca_pem); 248 } 249 250 void SetupVpnWithNss(bool open_vpn) { 251 AddService(kVPNStub, shill::kTypeVPN, shill::kStateIdle); 252 base::DictionaryValue provider; 253 const char* nss_property = open_vpn ? shill::kOpenVPNCaCertNSSProperty 254 : shill::kL2tpIpsecCaCertNssProperty; 255 provider.SetStringWithoutPathExpansion(nss_property, kNSSNickname); 256 service_test_->SetServiceProperty( 257 kVPNStub, shill::kProviderProperty, provider); 258 } 259 260 void GetVpnCACertProperties(bool open_vpn, 261 std::string* nss_nickname, 262 std::string* ca_pem) { 263 nss_nickname->clear(); 264 ca_pem->clear(); 265 const base::DictionaryValue* properties = 266 service_test_->GetServiceProperties(kVPNStub); 267 const base::DictionaryValue* provider = NULL; 268 properties->GetDictionaryWithoutPathExpansion(shill::kProviderProperty, 269 &provider); 270 if (!provider) 271 return; 272 const char* nss_property = open_vpn ? shill::kOpenVPNCaCertNSSProperty 273 : shill::kL2tpIpsecCaCertNssProperty; 274 provider->GetStringWithoutPathExpansion(nss_property, nss_nickname); 275 const base::ListValue* ca_pems = NULL; 276 const char* pem_property = open_vpn ? shill::kOpenVPNCaCertPemProperty 277 : shill::kL2tpIpsecCaCertPemProperty; 278 provider->GetListWithoutPathExpansion(pem_property, &ca_pems); 279 if (ca_pems && !ca_pems->empty()) 280 ca_pems->GetString(0, ca_pem); 281 } 282 283 ShillServiceClient::TestInterface* service_test_; 284 scoped_refptr<net::X509Certificate> test_ca_cert_; 285 scoped_refptr<net::X509Certificate> test_client_cert_; 286 std::string test_client_cert_pkcs11_id_; 287 std::string test_client_cert_slot_id_; 288 std::string test_ca_cert_pem_; 289 base::MessageLoop message_loop_; 290 291 private: 292 void CleanupTestCert() { 293 if (test_ca_cert_) 294 ASSERT_TRUE(test_nssdb_->DeleteCertAndKey(test_ca_cert_.get())); 295 296 if (test_client_cert_) 297 ASSERT_TRUE(test_nssdb_->DeleteCertAndKey(test_client_cert_.get())); 298 } 299 300 scoped_ptr<NetworkStateHandler> network_state_handler_; 301 scoped_ptr<NetworkCertMigrator> network_cert_migrator_; 302 crypto::ScopedTestNSSChromeOSUser user_; 303 scoped_ptr<net::NSSCertDatabaseChromeOS> test_nssdb_; 304 305 DISALLOW_COPY_AND_ASSIGN(NetworkCertMigratorTest); 306}; 307 308TEST_F(NetworkCertMigratorTest, MigrateNssOnInitialization) { 309 // Add a new network for migration before the handlers are initialized. 310 SetupWifiWithNss(); 311 SetupTestCACert(); 312 SetupNetworkHandlers(); 313 314 base::RunLoop().RunUntilIdle(); 315 std::string nss_nickname, ca_pem; 316 GetEapCACertProperties(&nss_nickname, &ca_pem); 317 EXPECT_TRUE(nss_nickname.empty()); 318 EXPECT_EQ(test_ca_cert_pem_, ca_pem); 319} 320 321TEST_F(NetworkCertMigratorTest, MigrateNssOnNetworkAppearance) { 322 SetupTestCACert(); 323 SetupNetworkHandlers(); 324 base::RunLoop().RunUntilIdle(); 325 326 // Add a new network for migration after the handlers are initialized. 327 SetupWifiWithNss(); 328 329 base::RunLoop().RunUntilIdle(); 330 std::string nss_nickname, ca_pem; 331 GetEapCACertProperties(&nss_nickname, &ca_pem); 332 EXPECT_TRUE(nss_nickname.empty()); 333 EXPECT_EQ(test_ca_cert_pem_, ca_pem); 334} 335 336TEST_F(NetworkCertMigratorTest, DoNotMigrateNssIfPemSet) { 337 // Add a new network with an already set PEM property. 338 SetupWifiWithNss(); 339 base::ListValue ca_pems; 340 ca_pems.AppendString(kFakePEM); 341 service_test_->SetServiceProperty( 342 kWifiStub, shill::kEapCaCertPemProperty, ca_pems); 343 344 SetupTestCACert(); 345 SetupNetworkHandlers(); 346 base::RunLoop().RunUntilIdle(); 347 348 std::string nss_nickname, ca_pem; 349 GetEapCACertProperties(&nss_nickname, &ca_pem); 350 EXPECT_TRUE(nss_nickname.empty()); 351 EXPECT_EQ(kFakePEM, ca_pem); 352} 353 354TEST_F(NetworkCertMigratorTest, MigrateNssOpenVpn) { 355 // Add a new network for migration before the handlers are initialized. 356 SetupVpnWithNss(true /* OpenVPN */); 357 358 SetupTestCACert(); 359 SetupNetworkHandlers(); 360 361 base::RunLoop().RunUntilIdle(); 362 std::string nss_nickname, ca_pem; 363 GetVpnCACertProperties(true /* OpenVPN */, &nss_nickname, &ca_pem); 364 EXPECT_TRUE(nss_nickname.empty()); 365 EXPECT_EQ(test_ca_cert_pem_, ca_pem); 366} 367 368TEST_F(NetworkCertMigratorTest, MigrateNssIpsecVpn) { 369 // Add a new network for migration before the handlers are initialized. 370 SetupVpnWithNss(false /* not OpenVPN */); 371 372 SetupTestCACert(); 373 SetupNetworkHandlers(); 374 375 base::RunLoop().RunUntilIdle(); 376 std::string nss_nickname, ca_pem; 377 GetVpnCACertProperties(false /* not OpenVPN */, &nss_nickname, &ca_pem); 378 EXPECT_TRUE(nss_nickname.empty()); 379 EXPECT_EQ(test_ca_cert_pem_, ca_pem); 380} 381 382TEST_F(NetworkCertMigratorTest, MigrateEapCertIdNoMatchingCert) { 383 SetupTestClientCert(); 384 SetupNetworkHandlers(); 385 base::RunLoop().RunUntilIdle(); 386 387 // Add a new network for migration after the handlers are initialized. 388 SetupNetworkWithEapCertId(true /* wifi */, "unknown pkcs11 id"); 389 390 base::RunLoop().RunUntilIdle(); 391 // Since the PKCS11 ID is unknown, the certificate configuration will be 392 // cleared. 393 std::string cert_id; 394 GetEapCertId(true /* wifi */, &cert_id); 395 EXPECT_EQ(std::string(), cert_id); 396} 397 398TEST_F(NetworkCertMigratorTest, MigrateEapCertIdNoSlotId) { 399 SetupTestClientCert(); 400 SetupNetworkHandlers(); 401 base::RunLoop().RunUntilIdle(); 402 403 // Add a new network for migration after the handlers are initialized. 404 SetupNetworkWithEapCertId(true /* wifi */, test_client_cert_pkcs11_id_); 405 406 base::RunLoop().RunUntilIdle(); 407 408 std::string cert_id; 409 GetEapCertId(true /* wifi */, &cert_id); 410 std::string expected_cert_id = 411 test_client_cert_slot_id_ + ":" + test_client_cert_pkcs11_id_; 412 EXPECT_EQ(expected_cert_id, cert_id); 413} 414 415TEST_F(NetworkCertMigratorTest, MigrateWifiEapCertIdWrongSlotId) { 416 SetupTestClientCert(); 417 SetupNetworkHandlers(); 418 base::RunLoop().RunUntilIdle(); 419 420 // Add a new network for migration after the handlers are initialized. 421 SetupNetworkWithEapCertId(true /* wifi */, 422 "123:" + test_client_cert_pkcs11_id_); 423 424 base::RunLoop().RunUntilIdle(); 425 426 std::string cert_id; 427 GetEapCertId(true /* wifi */, &cert_id); 428 std::string expected_cert_id = 429 test_client_cert_slot_id_ + ":" + test_client_cert_pkcs11_id_; 430 EXPECT_EQ(expected_cert_id, cert_id); 431} 432 433TEST_F(NetworkCertMigratorTest, DoNotChangeEapCertIdWithCorrectSlotId) { 434 SetupTestClientCert(); 435 SetupNetworkHandlers(); 436 base::RunLoop().RunUntilIdle(); 437 438 std::string expected_cert_id = 439 test_client_cert_slot_id_ + ":" + test_client_cert_pkcs11_id_; 440 441 // Add a new network for migration after the handlers are initialized. 442 SetupNetworkWithEapCertId(true /* wifi */, expected_cert_id); 443 444 base::RunLoop().RunUntilIdle(); 445 446 std::string cert_id; 447 GetEapCertId(true /* wifi */, &cert_id); 448 EXPECT_EQ(expected_cert_id, cert_id); 449} 450 451TEST_F(NetworkCertMigratorTest, IgnoreOpenVPNCertId) { 452 SetupTestClientCert(); 453 SetupNetworkHandlers(); 454 base::RunLoop().RunUntilIdle(); 455 456 const char kPkcs11Id[] = "any slot id"; 457 458 // Add a new network for migration after the handlers are initialized. 459 SetupVpnWithCertId( 460 true /* OpenVPN */, std::string() /* no slot id */, kPkcs11Id); 461 462 base::RunLoop().RunUntilIdle(); 463 464 std::string pkcs11_id; 465 std::string unused_slot_id; 466 GetVpnCertId(true /* OpenVPN */, &unused_slot_id, &pkcs11_id); 467 EXPECT_EQ(kPkcs11Id, pkcs11_id); 468} 469 470TEST_F(NetworkCertMigratorTest, MigrateEthernetEapCertIdWrongSlotId) { 471 SetupTestClientCert(); 472 SetupNetworkHandlers(); 473 base::RunLoop().RunUntilIdle(); 474 475 // Add a new network for migration after the handlers are initialized. 476 SetupNetworkWithEapCertId( 477 false /* ethernet */, "123:" + test_client_cert_pkcs11_id_); 478 479 base::RunLoop().RunUntilIdle(); 480 481 std::string cert_id; 482 GetEapCertId(false /* ethernet */, &cert_id); 483 std::string expected_cert_id = 484 test_client_cert_slot_id_ + ":" + test_client_cert_pkcs11_id_; 485 EXPECT_EQ(expected_cert_id, cert_id); 486} 487 488TEST_F(NetworkCertMigratorTest, MigrateIpsecCertIdWrongSlotId) { 489 SetupTestClientCert(); 490 SetupNetworkHandlers(); 491 base::RunLoop().RunUntilIdle(); 492 493 // Add a new network for migration after the handlers are initialized. 494 SetupVpnWithCertId(false /* IPsec */, "123", test_client_cert_pkcs11_id_); 495 496 base::RunLoop().RunUntilIdle(); 497 498 std::string pkcs11_id; 499 std::string slot_id; 500 GetVpnCertId(false /* IPsec */, &slot_id, &pkcs11_id); 501 EXPECT_EQ(test_client_cert_pkcs11_id_, pkcs11_id); 502 EXPECT_EQ(test_client_cert_slot_id_, slot_id); 503} 504 505} // namespace chromeos 506