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 #include "chromeos/network/client_cert_resolver.h" 5 6 #include <cert.h> 7 #include <pk11pub.h> 8 9 #include "base/files/file_path.h" 10 #include "base/files/file_util.h" 11 #include "base/json/json_reader.h" 12 #include "base/run_loop.h" 13 #include "base/strings/stringprintf.h" 14 #include "base/values.h" 15 #include "chromeos/cert_loader.h" 16 #include "chromeos/dbus/dbus_thread_manager.h" 17 #include "chromeos/dbus/shill_manager_client.h" 18 #include "chromeos/dbus/shill_profile_client.h" 19 #include "chromeos/dbus/shill_service_client.h" 20 #include "chromeos/network/managed_network_configuration_handler_impl.h" 21 #include "chromeos/network/network_configuration_handler.h" 22 #include "chromeos/network/network_profile_handler.h" 23 #include "chromeos/network/network_state_handler.h" 24 #include "chromeos/tpm_token_loader.h" 25 #include "components/onc/onc_constants.h" 26 #include "crypto/nss_util_internal.h" 27 #include "crypto/scoped_test_nss_chromeos_user.h" 28 #include "net/base/crypto_module.h" 29 #include "net/base/net_errors.h" 30 #include "net/base/test_data_directory.h" 31 #include "net/cert/nss_cert_database_chromeos.h" 32 #include "net/cert/x509_certificate.h" 33 #include "net/test/cert_test_util.h" 34 #include "testing/gtest/include/gtest/gtest.h" 35 #include "third_party/cros_system_api/dbus/service_constants.h" 36 37 namespace chromeos { 38 39 namespace { 40 41 const char* kWifiStub = "wifi_stub"; 42 const char* kWifiSSID = "wifi_ssid"; 43 const char* kUserProfilePath = "user_profile"; 44 const char* kUserHash = "user_hash"; 45 46 } // namespace 47 48 class ClientCertResolverTest : public testing::Test { 49 public: 50 ClientCertResolverTest() : service_test_(NULL), 51 profile_test_(NULL), 52 cert_loader_(NULL), 53 user_(kUserHash) { 54 } 55 virtual ~ClientCertResolverTest() {} 56 57 virtual void SetUp() OVERRIDE { 58 // Initialize NSS db for the user. 59 ASSERT_TRUE(user_.constructed_successfully()); 60 user_.FinishInit(); 61 private_slot_ = crypto::GetPrivateSlotForChromeOSUser( 62 user_.username_hash(), 63 base::Callback<void(crypto::ScopedPK11Slot)>()); 64 ASSERT_TRUE(private_slot_.get()); 65 test_nssdb_.reset(new net::NSSCertDatabaseChromeOS( 66 crypto::GetPublicSlotForChromeOSUser(user_.username_hash()), 67 crypto::GetPrivateSlotForChromeOSUser( 68 user_.username_hash(), 69 base::Callback<void(crypto::ScopedPK11Slot)>()))); 70 test_nssdb_->SetSlowTaskRunnerForTest(message_loop_.message_loop_proxy()); 71 72 DBusThreadManager::Initialize(); 73 service_test_ = 74 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface(); 75 profile_test_ = 76 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface(); 77 base::RunLoop().RunUntilIdle(); 78 service_test_->ClearServices(); 79 base::RunLoop().RunUntilIdle(); 80 81 TPMTokenLoader::InitializeForTest(); 82 83 CertLoader::Initialize(); 84 cert_loader_ = CertLoader::Get(); 85 cert_loader_->force_hardware_backed_for_test(); 86 } 87 88 virtual void TearDown() OVERRIDE { 89 client_cert_resolver_.reset(); 90 managed_config_handler_.reset(); 91 network_config_handler_.reset(); 92 network_profile_handler_.reset(); 93 network_state_handler_.reset(); 94 CertLoader::Shutdown(); 95 TPMTokenLoader::Shutdown(); 96 DBusThreadManager::Shutdown(); 97 CleanupSlotContents(); 98 } 99 100 protected: 101 void StartCertLoader() { 102 cert_loader_->StartWithNSSDB(test_nssdb_.get()); 103 if (test_client_cert_.get()) { 104 int slot_id = 0; 105 const std::string pkcs11_id = 106 CertLoader::GetPkcs11IdAndSlotForCert(*test_client_cert_, &slot_id); 107 test_cert_id_ = base::StringPrintf("%i:%s", slot_id, pkcs11_id.c_str()); 108 } 109 } 110 111 // Imports a CA cert (stored as PEM in test_ca_cert_pem_) and a client 112 // certificate signed by that CA. Its PKCS#11 ID is stored in 113 // |test_cert_id_|. 114 void SetupTestCerts() { 115 // Import a CA cert. 116 net::CertificateList ca_cert_list = 117 net::CreateCertificateListFromFile(net::GetTestCertsDirectory(), 118 "websocket_cacert.pem", 119 net::X509Certificate::FORMAT_AUTO); 120 ASSERT_TRUE(!ca_cert_list.empty()); 121 net::NSSCertDatabase::ImportCertFailureList failures; 122 EXPECT_TRUE(test_nssdb_->ImportCACerts( 123 ca_cert_list, net::NSSCertDatabase::TRUST_DEFAULT, &failures)); 124 ASSERT_TRUE(failures.empty()) << net::ErrorToString(failures[0].net_error); 125 126 net::X509Certificate::GetPEMEncoded(ca_cert_list[0]->os_cert_handle(), 127 &test_ca_cert_pem_); 128 ASSERT_TRUE(!test_ca_cert_pem_.empty()); 129 130 // Import a client cert signed by that CA. 131 std::string pkcs12_data; 132 ASSERT_TRUE(base::ReadFileToString( 133 net::GetTestCertsDirectory().Append("websocket_client_cert.p12"), 134 &pkcs12_data)); 135 136 net::CertificateList client_cert_list; 137 scoped_refptr<net::CryptoModule> module( 138 net::CryptoModule::CreateFromHandle(private_slot_.get())); 139 ASSERT_EQ(net::OK, 140 test_nssdb_->ImportFromPKCS12(module.get(), 141 pkcs12_data, 142 base::string16(), 143 false, 144 &client_cert_list)); 145 ASSERT_TRUE(!client_cert_list.empty()); 146 test_client_cert_ = client_cert_list[0]; 147 } 148 149 void SetupNetworkHandlers() { 150 network_state_handler_.reset(NetworkStateHandler::InitializeForTest()); 151 network_profile_handler_.reset(new NetworkProfileHandler()); 152 network_config_handler_.reset(new NetworkConfigurationHandler()); 153 managed_config_handler_.reset(new ManagedNetworkConfigurationHandlerImpl()); 154 client_cert_resolver_.reset(new ClientCertResolver()); 155 156 network_profile_handler_->Init(); 157 network_config_handler_->Init(network_state_handler_.get()); 158 managed_config_handler_->Init(network_state_handler_.get(), 159 network_profile_handler_.get(), 160 network_config_handler_.get(), 161 NULL /* network_device_handler */); 162 client_cert_resolver_->Init(network_state_handler_.get(), 163 managed_config_handler_.get()); 164 client_cert_resolver_->SetSlowTaskRunnerForTest( 165 message_loop_.message_loop_proxy()); 166 167 profile_test_->AddProfile(kUserProfilePath, kUserHash); 168 } 169 170 void SetupWifi() { 171 service_test_->SetServiceProperties(kWifiStub, 172 kWifiStub, 173 kWifiSSID, 174 shill::kTypeWifi, 175 shill::kStateOnline, 176 true /* visible */); 177 // Set an arbitrary cert id, so that we can check afterwards whether we 178 // cleared the property or not. 179 service_test_->SetServiceProperty( 180 kWifiStub, shill::kEapCertIdProperty, base::StringValue("invalid id")); 181 profile_test_->AddService(kUserProfilePath, kWifiStub); 182 183 DBusThreadManager::Get() 184 ->GetShillManagerClient() 185 ->GetTestInterface() 186 ->AddManagerService(kWifiStub, true); 187 } 188 189 // Setup a policy with a certificate pattern that matches any client cert that 190 // is signed by the test CA cert (stored in |test_ca_cert_pem_|). In 191 // particular it will match the test client cert. 192 void SetupPolicy() { 193 const char* kTestPolicyTemplate = 194 "[ { \"GUID\": \"wifi_stub\"," 195 " \"Name\": \"wifi_stub\"," 196 " \"Type\": \"WiFi\"," 197 " \"WiFi\": {" 198 " \"Security\": \"WPA-EAP\"," 199 " \"SSID\": \"wifi_ssid\"," 200 " \"EAP\": {" 201 " \"Outer\": \"EAP-TLS\"," 202 " \"ClientCertType\": \"Pattern\"," 203 " \"ClientCertPattern\": {" 204 " \"IssuerCAPEMs\": [ \"%s\" ]" 205 " }" 206 " }" 207 " }" 208 "} ]"; 209 std::string policy_json = 210 base::StringPrintf(kTestPolicyTemplate, test_ca_cert_pem_.c_str()); 211 212 std::string error; 213 scoped_ptr<base::Value> policy_value(base::JSONReader::ReadAndReturnError( 214 policy_json, base::JSON_ALLOW_TRAILING_COMMAS, NULL, &error)); 215 ASSERT_TRUE(policy_value) << error; 216 217 base::ListValue* policy = NULL; 218 ASSERT_TRUE(policy_value->GetAsList(&policy)); 219 220 managed_config_handler_->SetPolicy( 221 onc::ONC_SOURCE_USER_POLICY, 222 kUserHash, 223 *policy, 224 base::DictionaryValue() /* no global network config */); 225 } 226 227 void GetClientCertProperties(std::string* pkcs11_id) { 228 pkcs11_id->clear(); 229 const base::DictionaryValue* properties = 230 service_test_->GetServiceProperties(kWifiStub); 231 if (!properties) 232 return; 233 properties->GetStringWithoutPathExpansion(shill::kEapCertIdProperty, 234 pkcs11_id); 235 } 236 237 ShillServiceClient::TestInterface* service_test_; 238 ShillProfileClient::TestInterface* profile_test_; 239 std::string test_cert_id_; 240 scoped_refptr<net::X509Certificate> test_ca_cert_; 241 std::string test_ca_cert_pem_; 242 base::MessageLoop message_loop_; 243 244 private: 245 void CleanupSlotContents() { 246 CERTCertList* cert_list = PK11_ListCertsInSlot(private_slot_.get()); 247 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); 248 !CERT_LIST_END(node, cert_list); 249 node = CERT_LIST_NEXT(node)) { 250 scoped_refptr<net::X509Certificate> cert( 251 net::X509Certificate::CreateFromHandle( 252 node->cert, net::X509Certificate::OSCertHandles())); 253 test_nssdb_->DeleteCertAndKey(cert.get()); 254 } 255 CERT_DestroyCertList(cert_list); 256 } 257 258 CertLoader* cert_loader_; 259 scoped_refptr<net::X509Certificate> test_client_cert_; 260 scoped_ptr<NetworkStateHandler> network_state_handler_; 261 scoped_ptr<NetworkProfileHandler> network_profile_handler_; 262 scoped_ptr<NetworkConfigurationHandler> network_config_handler_; 263 scoped_ptr<ManagedNetworkConfigurationHandlerImpl> managed_config_handler_; 264 scoped_ptr<ClientCertResolver> client_cert_resolver_; 265 crypto::ScopedTestNSSChromeOSUser user_; 266 scoped_ptr<net::NSSCertDatabaseChromeOS> test_nssdb_; 267 crypto::ScopedPK11Slot private_slot_; 268 269 DISALLOW_COPY_AND_ASSIGN(ClientCertResolverTest); 270 }; 271 272 TEST_F(ClientCertResolverTest, NoMatchingCertificates) { 273 SetupNetworkHandlers(); 274 SetupWifi(); 275 StartCertLoader(); 276 SetupPolicy(); 277 base::RunLoop().RunUntilIdle(); 278 279 // Verify that no client certificate was configured. 280 std::string pkcs11_id; 281 GetClientCertProperties(&pkcs11_id); 282 EXPECT_EQ(std::string(), pkcs11_id); 283 } 284 285 TEST_F(ClientCertResolverTest, ResolveOnCertificatesLoaded) { 286 SetupNetworkHandlers(); 287 SetupWifi(); 288 SetupTestCerts(); 289 SetupPolicy(); 290 base::RunLoop().RunUntilIdle(); 291 292 StartCertLoader(); 293 base::RunLoop().RunUntilIdle(); 294 295 // Verify that the resolver positively matched the pattern in the policy with 296 // the test client cert and configured the network. 297 std::string pkcs11_id; 298 GetClientCertProperties(&pkcs11_id); 299 EXPECT_EQ(test_cert_id_, pkcs11_id); 300 } 301 302 TEST_F(ClientCertResolverTest, ResolveAfterPolicyApplication) { 303 SetupTestCerts(); 304 StartCertLoader(); 305 SetupNetworkHandlers(); 306 SetupWifi(); 307 base::RunLoop().RunUntilIdle(); 308 309 // Policy application will trigger the ClientCertResolver. 310 SetupPolicy(); 311 base::RunLoop().RunUntilIdle(); 312 313 // Verify that the resolver positively matched the pattern in the policy with 314 // the test client cert and configured the network. 315 std::string pkcs11_id; 316 GetClientCertProperties(&pkcs11_id); 317 EXPECT_EQ(test_cert_id_, pkcs11_id); 318 } 319 320 } // namespace chromeos 321