Commit 18e8d54f authored by pneubeck@chromium.org's avatar pneubeck@chromium.org

Add migration from CaCert NSS nicknames to PEM.

BUG=263044

Review URL: https://chromiumcodereview.appspot.com/20087002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@215914 0039d316-1c4b-4281-b951-d872f2087c98
parent d8f1fa0d
...@@ -59,6 +59,7 @@ void CallOpenPersistentNSSDB() { ...@@ -59,6 +59,7 @@ void CallOpenPersistentNSSDB() {
} // namespace } // namespace
static CertLoader* g_cert_loader = NULL; static CertLoader* g_cert_loader = NULL;
// static // static
void CertLoader::Initialize() { void CertLoader::Initialize() {
CHECK(!g_cert_loader); CHECK(!g_cert_loader);
...@@ -108,6 +109,11 @@ void CertLoader::SetCryptoTaskRunner( ...@@ -108,6 +109,11 @@ void CertLoader::SetCryptoTaskRunner(
MaybeRequestCertificates(); MaybeRequestCertificates();
} }
void CertLoader::SetSlowTaskRunnerForTest(
const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
slow_task_runner_for_test_ = task_runner;
}
CertLoader::~CertLoader() { CertLoader::~CertLoader() {
net::CertDatabase::GetInstance()->RemoveObserver(this); net::CertDatabase::GetInstance()->RemoveObserver(this);
if (LoginState::IsInitialized()) if (LoginState::IsInitialized())
...@@ -330,13 +336,16 @@ void CertLoader::StartLoadCertificates() { ...@@ -330,13 +336,16 @@ void CertLoader::StartLoadCertificates() {
net::CertificateList* cert_list = new net::CertificateList; net::CertificateList* cert_list = new net::CertificateList;
certificates_update_running_ = true; certificates_update_running_ = true;
certificates_update_required_ = false; certificates_update_required_ = false;
base::WorkerPool::GetTaskRunner(true /* task_is_slow */)->
PostTaskAndReply( base::TaskRunner* task_runner = slow_task_runner_for_test_.get();
FROM_HERE, if (!task_runner)
base::Bind(LoadNSSCertificates, cert_list), task_runner = base::WorkerPool::GetTaskRunner(true /* task is slow */);
base::Bind(&CertLoader::UpdateCertificates, task_runner->PostTaskAndReply(
update_certificates_factory_.GetWeakPtr(), FROM_HERE,
base::Owned(cert_list))); base::Bind(LoadNSSCertificates, cert_list),
base::Bind(&CertLoader::UpdateCertificates,
update_certificates_factory_.GetWeakPtr(),
base::Owned(cert_list)));
} }
void CertLoader::UpdateCertificates(net::CertificateList* cert_list) { void CertLoader::UpdateCertificates(net::CertificateList* cert_list) {
......
...@@ -66,12 +66,17 @@ class CHROMEOS_EXPORT CertLoader : public net::CertDatabase::Observer, ...@@ -66,12 +66,17 @@ class CHROMEOS_EXPORT CertLoader : public net::CertDatabase::Observer,
static bool IsInitialized(); static bool IsInitialized();
// |crypto_task_runner| is the task runner that any synchronous crypto calls // |crypto_task_runner| is the task runner that any synchronous crypto calls
// should be made from. e.g. in Chrome this is the IO thread. Must be called // should be made from, e.g. in Chrome this is the IO thread. Must be called
// after the thread is started. Certificate loading will not happen unless // after the thread is started. Certificate loading will not happen unless
// this is set. // this is set.
void SetCryptoTaskRunner( void SetCryptoTaskRunner(
const scoped_refptr<base::SequencedTaskRunner>& crypto_task_runner); const scoped_refptr<base::SequencedTaskRunner>& crypto_task_runner);
// Sets the task runner that any slow calls will be made from, e.g. calls
// to the NSS database. If not set, uses base::WorkerPool.
void SetSlowTaskRunnerForTest(
const scoped_refptr<base::SequencedTaskRunner>& task_runner);
void AddObserver(CertLoader::Observer* observer); void AddObserver(CertLoader::Observer* observer);
void RemoveObserver(CertLoader::Observer* observer); void RemoveObserver(CertLoader::Observer* observer);
...@@ -167,6 +172,9 @@ class CHROMEOS_EXPORT CertLoader : public net::CertDatabase::Observer, ...@@ -167,6 +172,9 @@ class CHROMEOS_EXPORT CertLoader : public net::CertDatabase::Observer,
// TaskRunner for crypto calls. // TaskRunner for crypto calls.
scoped_refptr<base::SequencedTaskRunner> crypto_task_runner_; scoped_refptr<base::SequencedTaskRunner> crypto_task_runner_;
// TaskRunner for other slow tasks. May be set in tests.
scoped_refptr<base::TaskRunner> slow_task_runner_for_test_;
// This factory should be used only for callbacks during TPMToken // This factory should be used only for callbacks during TPMToken
// initialization. // initialization.
base::WeakPtrFactory<CertLoader> initialize_token_factory_; base::WeakPtrFactory<CertLoader> initialize_token_factory_;
......
...@@ -228,6 +228,8 @@ ...@@ -228,6 +228,8 @@
'network/managed_network_configuration_handler.h', 'network/managed_network_configuration_handler.h',
'network/managed_state.cc', 'network/managed_state.cc',
'network/managed_state.h', 'network/managed_state.h',
'network/network_cert_migrator.cc',
'network/network_cert_migrator.h',
'network/network_change_notifier_chromeos.cc', 'network/network_change_notifier_chromeos.cc',
'network/network_change_notifier_chromeos.h', 'network/network_change_notifier_chromeos.h',
'network/network_change_notifier_factory_chromeos.cc', 'network/network_change_notifier_factory_chromeos.cc',
...@@ -447,6 +449,7 @@ ...@@ -447,6 +449,7 @@
'../crypto/crypto.gyp:crypto', '../crypto/crypto.gyp:crypto',
'../dbus/dbus.gyp:dbus_test_support', '../dbus/dbus.gyp:dbus_test_support',
'../net/net.gyp:net', '../net/net.gyp:net',
'../net/net.gyp:net_test_support',
'../testing/gmock.gyp:gmock', '../testing/gmock.gyp:gmock',
'../testing/gtest.gyp:gtest', '../testing/gtest.gyp:gtest',
'../url/url.gyp:url_lib', '../url/url.gyp:url_lib',
...@@ -494,6 +497,7 @@ ...@@ -494,6 +497,7 @@
'network/cros_network_functions_unittest.cc', 'network/cros_network_functions_unittest.cc',
'network/geolocation_handler_unittest.cc', 'network/geolocation_handler_unittest.cc',
'network/managed_network_configuration_handler_unittest.cc', 'network/managed_network_configuration_handler_unittest.cc',
'network/network_cert_migrator_unittest.cc',
'network/network_change_notifier_chromeos_unittest.cc', 'network/network_change_notifier_chromeos_unittest.cc',
'network/network_configuration_handler_unittest.cc', 'network/network_configuration_handler_unittest.cc',
'network/network_connection_handler_unittest.cc', 'network/network_connection_handler_unittest.cc',
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/command_line.h" #include "base/command_line.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/values.h" #include "base/values.h"
#include "chromeos/chromeos_switches.h" #include "chromeos/chromeos_switches.h"
#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/dbus_thread_manager.h"
...@@ -356,12 +357,30 @@ bool ShillServiceClientStub::SetServiceProperty(const std::string& service_path, ...@@ -356,12 +357,30 @@ bool ShillServiceClientStub::SetServiceProperty(const std::string& service_path,
MoveServiceToIndex(service_path, 0, true); MoveServiceToIndex(service_path, 0, true);
} }
} }
dict->SetWithoutPathExpansion(property, value.DeepCopy()); base::DictionaryValue new_properties;
std::string changed_property;
bool case_sensitive = true;
if (StartsWithASCII(property, "Provider.", case_sensitive) ||
StartsWithASCII(property, "OpenVPN.", case_sensitive) ||
StartsWithASCII(property, "L2TPIPsec.", case_sensitive)) {
// These properties are only nested within the Provider dictionary if read
// from Shill.
base::DictionaryValue* provider = new base::DictionaryValue;
provider->SetWithoutPathExpansion(property, value.DeepCopy());
new_properties.SetWithoutPathExpansion(flimflam::kProviderProperty,
provider);
changed_property = flimflam::kProviderProperty;
} else {
new_properties.SetWithoutPathExpansion(property, value.DeepCopy());
changed_property = property;
}
dict->MergeDictionary(&new_properties);
base::MessageLoop::current()->PostTask( base::MessageLoop::current()->PostTask(
FROM_HERE, FROM_HERE,
base::Bind(&ShillServiceClientStub::NotifyObserversPropertyChanged, base::Bind(&ShillServiceClientStub::NotifyObserversPropertyChanged,
weak_ptr_factory_.GetWeakPtr(), weak_ptr_factory_.GetWeakPtr(),
dbus::ObjectPath(service_path), property)); dbus::ObjectPath(service_path), changed_property));
return true; return true;
} }
......
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/network/network_cert_migrator.h"
#include <cert.h>
#include <string>
#include "base/location.h"
#include "base/metrics/histogram.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/shill_service_client.h"
#include "chromeos/network/network_handler_callbacks.h"
#include "chromeos/network/network_state.h"
#include "chromeos/network/network_state_handler.h"
#include "dbus/object_path.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
namespace chromeos {
namespace {
enum UMANetworkType {
UMA_NETWORK_TYPE_EAP,
UMA_NETWORK_TYPE_OPENVPN,
UMA_NETWORK_TYPE_IPSEC,
UMA_NETWORK_TYPE_SIZE,
};
// Copied from x509_certificate_model_nss.cc
std::string GetNickname(const net::X509Certificate& cert) {
if (!cert.os_cert_handle()->nickname)
return std::string();
std::string name = cert.os_cert_handle()->nickname;
// Hack copied from mozilla: Cut off text before first :, which seems to
// just be the token name.
size_t colon_pos = name.find(':');
if (colon_pos != std::string::npos)
name = name.substr(colon_pos + 1);
return name;
}
} // namespace
// Checks which of the given |networks| has one of the deprecated
// CaCertNssProperties set. If such a network already has a CaCertPEM property,
// then the NssProperty is cleared. Otherwise, the NssProperty is compared with
// the nickname of each certificate of |certs|. If a match is found, then the
// CaCertPemProperty is set and the NssProperty is cleared. Otherwise, the
// network is not modified.
class NetworkCertMigrator::MigrationTask
: public base::RefCounted<MigrationTask> {
public:
MigrationTask(const net::CertificateList& certs,
const base::WeakPtr<NetworkCertMigrator>& cert_migrator)
: certs_(certs),
cert_migrator_(cert_migrator) {
}
void Run(const NetworkStateHandler::NetworkStateList& networks) {
// Request properties for each network that has a CaCertNssProperty set
// according to the NetworkStateHandler.
for (NetworkStateHandler::NetworkStateList::const_iterator it =
networks.begin(); it != networks.end(); ++it) {
if (!(*it)->HasCACertNSS())
continue;
const std::string& service_path = (*it)->path();
DBusThreadManager::Get()->GetShillServiceClient()->GetProperties(
dbus::ObjectPath(service_path),
base::Bind(&network_handler::GetPropertiesCallback,
base::Bind(&MigrationTask::MigrateNetwork, this),
network_handler::ErrorCallback(),
service_path));
}
}
void MigrateNetwork(const std::string& service_path,
const base::DictionaryValue& properties) {
if (!cert_migrator_) {
VLOG(2) << "NetworkCertMigrator already destroyed. Aborting migration.";
return;
}
std::string nss_key, pem_key, nickname;
const base::ListValue* pem_property = NULL;
UMANetworkType uma_type = UMA_NETWORK_TYPE_SIZE;
GetNssAndPemProperties(
properties, &nss_key, &pem_key, &pem_property, &nickname, &uma_type);
if (nickname.empty())
return; // Didn't find any nickname.
VLOG(2) << "Found NSS nickname to migrate. Property: " << nss_key
<< ", network: " << service_path;
UMA_HISTOGRAM_ENUMERATION(
"Network.MigrationNssToPem", uma_type, UMA_NETWORK_TYPE_SIZE);
if (pem_property && !pem_property->empty()) {
VLOG(2) << "PEM already exists, clearing NSS property.";
ClearNssProperty(service_path, nss_key);
return;
}
scoped_refptr<net::X509Certificate> cert =
FindCertificateWithNickname(nickname);
if (!cert) {
VLOG(2) << "No matching cert found.";
return;
}
std::string pem_encoded;
if (!net::X509Certificate::GetPEMEncoded(cert->os_cert_handle(),
&pem_encoded)) {
LOG(ERROR) << "PEM encoding failed.";
return;
}
SetNssAndPemProperties(service_path, nss_key, pem_key, pem_encoded);
}
void GetNssAndPemProperties(const base::DictionaryValue& shill_properties,
std::string* nss_key,
std::string* pem_key,
const base::ListValue** pem_property,
std::string* nickname,
UMANetworkType* uma_type) {
struct NssPem {
const char* read_prefix;
const char* nss_key;
const char* pem_key;
UMANetworkType uma_type;
} const kNssPemMap[] = {
{ NULL, flimflam::kEapCaCertNssProperty, shill::kEapCaCertPemProperty,
UMA_NETWORK_TYPE_EAP },
{ flimflam::kProviderProperty, flimflam::kL2tpIpsecCaCertNssProperty,
shill::kL2tpIpsecCaCertPemProperty, UMA_NETWORK_TYPE_IPSEC },
{ flimflam::kProviderProperty, flimflam::kOpenVPNCaCertNSSProperty,
shill::kOpenVPNCaCertPemProperty, UMA_NETWORK_TYPE_OPENVPN },
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kNssPemMap); ++i) {
const base::DictionaryValue* dict = &shill_properties;
if (kNssPemMap[i].read_prefix) {
shill_properties.GetDictionaryWithoutPathExpansion(
kNssPemMap[i].read_prefix, &dict);
if (!dict)
continue;
}
dict->GetStringWithoutPathExpansion(kNssPemMap[i].nss_key, nickname);
if (!nickname->empty()) {
*nss_key = kNssPemMap[i].nss_key;
*pem_key = kNssPemMap[i].pem_key;
*uma_type = kNssPemMap[i].uma_type;
dict->GetListWithoutPathExpansion(kNssPemMap[i].pem_key, pem_property);
return;
}
}
}
void ClearNssProperty(const std::string& service_path,
const std::string& nss_key) {
DBusThreadManager::Get()->GetShillServiceClient()
->SetProperty(dbus::ObjectPath(service_path),
nss_key,
base::StringValue(std::string()),
base::Bind(&base::DoNothing),
base::Bind(&network_handler::ShillErrorCallbackFunction,
"MigrationTask.SetProperty failed",
service_path,
network_handler::ErrorCallback()));
cert_migrator_->network_state_handler_
->RequestUpdateForNetwork(service_path);
}
scoped_refptr<net::X509Certificate> FindCertificateWithNickname(
const std::string& nickname) {
for (net::CertificateList::iterator it = certs_.begin(); it != certs_.end();
++it) {
if (nickname == GetNickname(**it))
return *it;
}
return NULL;
}
void SetNssAndPemProperties(const std::string& service_path,
const std::string& nss_key,
const std::string& pem_key,
const std::string& pem_encoded_cert) {
base::DictionaryValue new_properties;
new_properties.SetStringWithoutPathExpansion(nss_key, std::string());
scoped_ptr<base::ListValue> ca_cert_pems(new base::ListValue);
ca_cert_pems->AppendString(pem_encoded_cert);
new_properties.SetWithoutPathExpansion(pem_key, ca_cert_pems.release());
DBusThreadManager::Get()->GetShillServiceClient()
->SetProperties(dbus::ObjectPath(service_path),
new_properties,
base::Bind(&base::DoNothing),
base::Bind(&network_handler::ShillErrorCallbackFunction,
"MigrationTask.SetProperties failed",
service_path,
network_handler::ErrorCallback()));
cert_migrator_->network_state_handler_
->RequestUpdateForNetwork(service_path);
}
private:
friend class base::RefCounted<MigrationTask>;
virtual ~MigrationTask() {
}
net::CertificateList certs_;
base::WeakPtr<NetworkCertMigrator> cert_migrator_;
};
NetworkCertMigrator::NetworkCertMigrator()
: network_state_handler_(NULL),
weak_ptr_factory_(this) {
}
NetworkCertMigrator::~NetworkCertMigrator() {
network_state_handler_->RemoveObserver(this, FROM_HERE);
if (CertLoader::IsInitialized())
CertLoader::Get()->RemoveObserver(this);
}
void NetworkCertMigrator::Init(NetworkStateHandler* network_state_handler) {
DCHECK(network_state_handler);
network_state_handler_ = network_state_handler;
network_state_handler_->AddObserver(this, FROM_HERE);
DCHECK(CertLoader::IsInitialized());
CertLoader::Get()->AddObserver(this);
}
void NetworkCertMigrator::NetworkListChanged() {
if (!CertLoader::Get()->certificates_loaded()) {
VLOG(2) << "Certs not loaded yet.";
return;
}
// Run the migration process from deprecated CaCertNssProperties to CaCertPem.
VLOG(2) << "Start NSS nickname to PEM migration.";
scoped_refptr<MigrationTask> helper(new MigrationTask(
CertLoader::Get()->cert_list(), weak_ptr_factory_.GetWeakPtr()));
NetworkStateHandler::NetworkStateList networks;
network_state_handler_->GetNetworkList(&networks);
helper->Run(networks);
}
void NetworkCertMigrator::OnCertificatesLoaded(
const net::CertificateList& cert_list,
bool initial_load) {
// Maybe there are networks referring to certs (by NSS nickname) that were not
// loaded before but are now.
NetworkListChanged();
}
} // namespace chromeos
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMEOS_NETWORK_NETWORK_CERT_MIGRATOR_H_
#define CHROMEOS_NETWORK_NETWORK_CERT_MIGRATOR_H_
#include "base/basictypes.h"
#include "base/memory/weak_ptr.h"
#include "chromeos/cert_loader.h"
#include "chromeos/chromeos_export.h"
#include "chromeos/network/network_state_handler_observer.h"
namespace chromeos {
class NetworkStateHandler;
// Migrates network configurations from deprecated CaCertNSS properties to
// CaCertPEM.
class CHROMEOS_EXPORT NetworkCertMigrator : public NetworkStateHandlerObserver,
public CertLoader::Observer {
public:
virtual ~NetworkCertMigrator();
private:
friend class NetworkHandler;
friend class NetworkCertMigratorTest;
class MigrationTask;
NetworkCertMigrator();
void Init(NetworkStateHandler* network_state_handler);
// NetworkStateHandlerObserver overrides
virtual void NetworkListChanged() OVERRIDE;
// CertLoader::Observer overrides
virtual void OnCertificatesLoaded(const net::CertificateList& cert_list,
bool initial_load) OVERRIDE;
// Unowned associated NetworkStateHandler* (global or test instance).
NetworkStateHandler* network_state_handler_;
base::WeakPtrFactory<NetworkCertMigrator> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(NetworkCertMigrator);
};
} // namespace chromeos
#endif // CHROMEOS_NETWORK_NETWORK_CERT_MIGRATOR_H_
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/network/network_cert_migrator.h"
#include <cert.h>
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/run_loop.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/shill_service_client.h"
#include "chromeos/login/login_state.h"
#include "chromeos/network/network_state_handler.h"
#include "crypto/nss_util.h"
#include "net/base/crypto_module.h"
#include "net/base/net_errors.h"
#include "net/base/test_data_directory.h"
#include "net/cert/nss_cert_database.h"
#include "net/cert/x509_certificate.h"
#include "net/test/cert_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
namespace chromeos {
namespace {
const char* kWifiStub = "wifi_stub";
const char* kVPNStub = "vpn_stub";
const char* kNSSNickname = "nss_nickname";
const char* kFakePEM = "pem";
} // namespace
class NetworkCertMigratorTest : public testing::Test {
public:
NetworkCertMigratorTest() {}
virtual ~NetworkCertMigratorTest() {}
virtual void SetUp() OVERRIDE {
ASSERT_TRUE(test_nssdb_.is_open());
slot_ = net::NSSCertDatabase::GetInstance()->GetPublicModule();
ASSERT_TRUE(slot_->os_module_handle());
LoginState::Initialize();
DBusThreadManager::InitializeWithStub();
service_test_ =
DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
message_loop_.RunUntilIdle();
service_test_->ClearServices();
message_loop_.RunUntilIdle();
CertLoader::Initialize();
CertLoader::Get()->SetSlowTaskRunnerForTest(
message_loop_.message_loop_proxy());
CertLoader::Get()->SetCryptoTaskRunner(message_loop_.message_loop_proxy());
}
virtual void TearDown() OVERRIDE {
network_cert_migrator_.reset();
network_state_handler_.reset();
CertLoader::Shutdown();
DBusThreadManager::Shutdown();
LoginState::Shutdown();
CleanupTestCert();
}
protected:
void SetupTestCACert() {
scoped_refptr<net::X509Certificate> cert_wo_nickname =
net::CreateCertificateListFromFile(net::GetTestCertsDirectory(),
"eku-test-root.pem",
net::X509Certificate::FORMAT_AUTO)
.back();
net::X509Certificate::GetPEMEncoded(cert_wo_nickname->os_cert_handle(),
&test_ca_cert_pem_);
std::string der_encoded;
net::X509Certificate::GetDEREncoded(cert_wo_nickname->os_cert_handle(),
&der_encoded);
cert_wo_nickname = NULL;
test_ca_cert_ = net::X509Certificate::CreateFromBytesWithNickname(
der_encoded.data(), der_encoded.size(), kNSSNickname);
net::NSSCertDatabase* cert_database = net::NSSCertDatabase::GetInstance();
net::CertificateList cert_list;
cert_list.push_back(test_ca_cert_);
net::NSSCertDatabase::ImportCertFailureList failures;
EXPECT_TRUE(cert_database->ImportCACerts(
cert_list, net::NSSCertDatabase::TRUST_DEFAULT, &failures));
ASSERT_TRUE(failures.empty()) << net::ErrorToString(failures[0].net_error);
}
void SetupNetworkHandlers() {
network_state_handler_.reset(NetworkStateHandler::InitializeForTest());
network_cert_migrator_.reset(new NetworkCertMigrator);
network_cert_migrator_->Init(network_state_handler_.get());
}
void SetupWifiWithNss() {
const bool add_to_visible = true;
const bool add_to_watchlist = true;
service_test_->AddService(kWifiStub,
kWifiStub,
flimflam::kTypeWifi,
flimflam::kStateOnline,
add_to_visible,
add_to_watchlist);
service_test_->SetServiceProperty(kWifiStub,
flimflam::kEapCaCertNssProperty,
base::StringValue(kNSSNickname));
}
void GetEapCACertProperties(std::string* nss_nickname, std::string* ca_pem) {
nss_nickname->clear();
ca_pem->clear();
const base::DictionaryValue* properties =
service_test_->GetServiceProperties(kWifiStub);
properties->GetStringWithoutPathExpansion(flimflam::kEapCaCertNssProperty,
nss_nickname);
const base::ListValue* ca_pems = NULL;
properties->GetListWithoutPathExpansion(shill::kEapCaCertPemProperty,
&ca_pems);
if (ca_pems && !ca_pems->empty())
ca_pems->GetString(0, ca_pem);
}
void SetupVpnWithNss(bool open_vpn) {
const bool add_to_visible = true;
const bool add_to_watchlist = true;
service_test_->AddService(kVPNStub,
kVPNStub,
flimflam::kTypeVPN,
flimflam::kStateIdle,
add_to_visible,
add_to_watchlist);
base::DictionaryValue provider;
const char* nss_property = open_vpn ? flimflam::kOpenVPNCaCertNSSProperty
: flimflam::kL2tpIpsecCaCertNssProperty;
provider.SetStringWithoutPathExpansion(nss_property, kNSSNickname);
service_test_->SetServiceProperty(
kVPNStub, flimflam::kProviderProperty, provider);
}
void GetVpnCACertProperties(bool open_vpn,
std::string* nss_nickname,
std::string* ca_pem) {
nss_nickname->clear();
ca_pem->clear();
const base::DictionaryValue* properties =
service_test_->GetServiceProperties(kVPNStub);
const base::DictionaryValue* provider = NULL;
properties->GetDictionaryWithoutPathExpansion(flimflam::kProviderProperty,
&provider);
if (!provider)
return;
const char* nss_property = open_vpn ? flimflam::kOpenVPNCaCertNSSProperty
: flimflam::kL2tpIpsecCaCertNssProperty;
provider->GetStringWithoutPathExpansion(nss_property, nss_nickname);
const base::ListValue* ca_pems = NULL;
const char* pem_property = open_vpn ? shill::kOpenVPNCaCertPemProperty
: shill::kL2tpIpsecCaCertPemProperty;
provider->GetListWithoutPathExpansion(pem_property, &ca_pems);
if (ca_pems && !ca_pems->empty())
ca_pems->GetString(0, ca_pem);
}
ShillServiceClient::TestInterface* service_test_;
scoped_refptr<net::X509Certificate> test_ca_cert_;
std::string test_ca_cert_pem_;
base::MessageLoop message_loop_;
private:
void CleanupTestCert() {
ASSERT_TRUE(net::NSSCertDatabase::GetInstance()->DeleteCertAndKey(
test_ca_cert_.get()));
}
scoped_ptr<NetworkStateHandler> network_state_handler_;
scoped_ptr<NetworkCertMigrator> network_cert_migrator_;
scoped_refptr<net::CryptoModule> slot_;
crypto::ScopedTestNSSDB test_nssdb_;
DISALLOW_COPY_AND_ASSIGN(NetworkCertMigratorTest);
};
TEST_F(NetworkCertMigratorTest, MigrateNssOnInitialization) {
// Add a new network for migration before the handlers are initialized.
SetupWifiWithNss();
SetupTestCACert();
SetupNetworkHandlers();
message_loop_.RunUntilIdle();
std::string nss_nickname, ca_pem;
GetEapCACertProperties(&nss_nickname, &ca_pem);
EXPECT_TRUE(nss_nickname.empty());
EXPECT_EQ(test_ca_cert_pem_, ca_pem);
}
TEST_F(NetworkCertMigratorTest, MigrateNssOnNetworkAppearance) {
SetupTestCACert();
SetupNetworkHandlers();
message_loop_.RunUntilIdle();
// Add a new network for migration after the handlers are initialized.
SetupWifiWithNss();
message_loop_.RunUntilIdle();
std::string nss_nickname, ca_pem;
GetEapCACertProperties(&nss_nickname, &ca_pem);
EXPECT_TRUE(nss_nickname.empty());
EXPECT_EQ(test_ca_cert_pem_, ca_pem);
}
TEST_F(NetworkCertMigratorTest, DoNotMigrateNssIfPemSet) {
// Add a new network with an already set PEM property.
SetupWifiWithNss();
base::ListValue ca_pems;
ca_pems.AppendString(kFakePEM);
service_test_->SetServiceProperty(
kWifiStub, shill::kEapCaCertPemProperty, ca_pems);
SetupTestCACert();
SetupNetworkHandlers();
message_loop_.RunUntilIdle();
std::string nss_nickname, ca_pem;
GetEapCACertProperties(&nss_nickname, &ca_pem);
EXPECT_TRUE(nss_nickname.empty());
EXPECT_EQ(kFakePEM, ca_pem);
}
TEST_F(NetworkCertMigratorTest, MigrateOpenVpn) {
// Add a new network for migration before the handlers are initialized.
SetupVpnWithNss(true /* OpenVPN */);
SetupTestCACert();
SetupNetworkHandlers();
message_loop_.RunUntilIdle();
std::string nss_nickname, ca_pem;
GetVpnCACertProperties(true /* OpenVPN */, &nss_nickname, &ca_pem);
EXPECT_TRUE(nss_nickname.empty());
EXPECT_EQ(test_ca_cert_pem_, ca_pem);
}
TEST_F(NetworkCertMigratorTest, MigrateIpsecVpn) {
// Add a new network for migration before the handlers are initialized.
SetupVpnWithNss(false /* not OpenVPN */);
SetupTestCACert();
SetupNetworkHandlers();
message_loop_.RunUntilIdle();
std::string nss_nickname, ca_pem;
GetVpnCACertProperties(false /* not OpenVPN */, &nss_nickname, &ca_pem);
EXPECT_TRUE(nss_nickname.empty());
EXPECT_EQ(test_ca_cert_pem_, ca_pem);
}
} // namespace chromeos
...@@ -4,9 +4,11 @@ ...@@ -4,9 +4,11 @@
#include "chromeos/network/network_handler.h" #include "chromeos/network/network_handler.h"
#include "base/threading/worker_pool.h"
#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/network/geolocation_handler.h" #include "chromeos/network/geolocation_handler.h"
#include "chromeos/network/managed_network_configuration_handler.h" #include "chromeos/network/managed_network_configuration_handler.h"
#include "chromeos/network/network_cert_migrator.h"
#include "chromeos/network/network_configuration_handler.h" #include "chromeos/network/network_configuration_handler.h"
#include "chromeos/network/network_connection_handler.h" #include "chromeos/network/network_connection_handler.h"
#include "chromeos/network/network_device_handler.h" #include "chromeos/network/network_device_handler.h"
...@@ -29,6 +31,8 @@ NetworkHandler::NetworkHandler() { ...@@ -29,6 +31,8 @@ NetworkHandler::NetworkHandler() {
network_state_handler_.reset(new NetworkStateHandler()); network_state_handler_.reset(new NetworkStateHandler());
network_device_handler_.reset(new NetworkDeviceHandler()); network_device_handler_.reset(new NetworkDeviceHandler());
network_profile_handler_.reset(new NetworkProfileHandler()); network_profile_handler_.reset(new NetworkProfileHandler());
if (CertLoader::IsInitialized())
network_cert_migrator_.reset(new NetworkCertMigrator());
network_configuration_handler_.reset(new NetworkConfigurationHandler()); network_configuration_handler_.reset(new NetworkConfigurationHandler());
managed_network_configuration_handler_.reset( managed_network_configuration_handler_.reset(
new ManagedNetworkConfigurationHandler()); new ManagedNetworkConfigurationHandler());
...@@ -44,6 +48,8 @@ NetworkHandler::~NetworkHandler() { ...@@ -44,6 +48,8 @@ NetworkHandler::~NetworkHandler() {
void NetworkHandler::Init() { void NetworkHandler::Init() {
network_state_handler_->InitShillPropertyHandler(); network_state_handler_->InitShillPropertyHandler();
network_profile_handler_->Init(network_state_handler_.get()); network_profile_handler_->Init(network_state_handler_.get());
if (network_cert_migrator_)
network_cert_migrator_->Init(network_state_handler_.get());
network_configuration_handler_->Init(network_state_handler_.get()); network_configuration_handler_->Init(network_state_handler_.get());
managed_network_configuration_handler_->Init( managed_network_configuration_handler_->Init(
network_state_handler_.get(), network_state_handler_.get(),
......
...@@ -13,6 +13,7 @@ namespace chromeos { ...@@ -13,6 +13,7 @@ namespace chromeos {
class GeolocationHandler; class GeolocationHandler;
class ManagedNetworkConfigurationHandler; class ManagedNetworkConfigurationHandler;
class NetworkCertMigrator;
class NetworkConfigurationHandler; class NetworkConfigurationHandler;
class NetworkConnectionHandler; class NetworkConnectionHandler;
class NetworkDeviceHandler; class NetworkDeviceHandler;
...@@ -59,6 +60,7 @@ class CHROMEOS_EXPORT NetworkHandler { ...@@ -59,6 +60,7 @@ class CHROMEOS_EXPORT NetworkHandler {
scoped_ptr<NetworkStateHandler> network_state_handler_; scoped_ptr<NetworkStateHandler> network_state_handler_;
scoped_ptr<NetworkDeviceHandler> network_device_handler_; scoped_ptr<NetworkDeviceHandler> network_device_handler_;
scoped_ptr<NetworkProfileHandler> network_profile_handler_; scoped_ptr<NetworkProfileHandler> network_profile_handler_;
scoped_ptr<NetworkCertMigrator> network_cert_migrator_;
scoped_ptr<NetworkConfigurationHandler> network_configuration_handler_; scoped_ptr<NetworkConfigurationHandler> network_configuration_handler_;
scoped_ptr<ManagedNetworkConfigurationHandler> scoped_ptr<ManagedNetworkConfigurationHandler>
managed_network_configuration_handler_; managed_network_configuration_handler_;
......
...@@ -68,6 +68,33 @@ chromeos::NetworkUIData* CreateUIDataFromValue( ...@@ -68,6 +68,33 @@ chromeos::NetworkUIData* CreateUIDataFromValue(
return new chromeos::NetworkUIData(*ui_data_dict); return new chromeos::NetworkUIData(*ui_data_dict);
} }
bool IsCaCertNssSet(const base::DictionaryValue& properties) {
std::string ca_cert_nss;
if (properties.GetStringWithoutPathExpansion(flimflam::kEapCaCertNssProperty,
&ca_cert_nss) &&
!ca_cert_nss.empty()) {
return true;
}
const base::DictionaryValue* provider = NULL;
properties.GetDictionaryWithoutPathExpansion(flimflam::kProviderProperty,
&provider);
if (!provider)
return false;
if (provider->GetStringWithoutPathExpansion(
flimflam::kL2tpIpsecCaCertNssProperty, &ca_cert_nss) &&
!ca_cert_nss.empty()) {
return true;
}
if (provider->GetStringWithoutPathExpansion(
flimflam::kOpenVPNCaCertNSSProperty, &ca_cert_nss) &&
!ca_cert_nss.empty()) {
return true;
}
return false;
}
} // namespace } // namespace
namespace chromeos { namespace chromeos {
...@@ -82,7 +109,8 @@ NetworkState::NetworkState(const std::string& path) ...@@ -82,7 +109,8 @@ NetworkState::NetworkState(const std::string& path)
signal_strength_(0), signal_strength_(0),
connectable_(false), connectable_(false),
activate_over_non_cellular_networks_(false), activate_over_non_cellular_networks_(false),
cellular_out_of_credits_(false) { cellular_out_of_credits_(false),
has_ca_cert_nss_(false) {
} }
NetworkState::~NetworkState() { NetworkState::~NetworkState() {
...@@ -191,6 +219,9 @@ bool NetworkState::PropertyChanged(const std::string& key, ...@@ -191,6 +219,9 @@ bool NetworkState::PropertyChanged(const std::string& key,
bool NetworkState::InitialPropertiesReceived( bool NetworkState::InitialPropertiesReceived(
const base::DictionaryValue& properties) { const base::DictionaryValue& properties) {
bool changed = UpdateName(properties); bool changed = UpdateName(properties);
bool had_ca_cert_nss = has_ca_cert_nss_;
has_ca_cert_nss_ = IsCaCertNssSet(properties);
changed |= had_ca_cert_nss != has_ca_cert_nss_;
return changed; return changed;
} }
......
...@@ -74,6 +74,9 @@ class CHROMEOS_EXPORT NetworkState : public ManagedState { ...@@ -74,6 +74,9 @@ class CHROMEOS_EXPORT NetworkState : public ManagedState {
const std::string& post_method() const { return post_method_; } const std::string& post_method() const { return post_method_; }
const std::string& post_data() const { return post_data_; } const std::string& post_data() const { return post_data_; }
// Whether this network has a CACertNSS nickname set.
bool HasCACertNSS() const { return has_ca_cert_nss_; }
// Returns true if |connection_state_| is a connected/connecting state. // Returns true if |connection_state_| is a connected/connecting state.
bool IsConnectedState() const; bool IsConnectedState() const;
bool IsConnectingState() const; bool IsConnectingState() const;
...@@ -154,6 +157,10 @@ class CHROMEOS_EXPORT NetworkState : public ManagedState { ...@@ -154,6 +157,10 @@ class CHROMEOS_EXPORT NetworkState : public ManagedState {
std::string post_method_; std::string post_method_;
std::string post_data_; std::string post_data_;
// Whether a deprecated CaCertNSS property of this network is set. Required
// for migration to PEM.
bool has_ca_cert_nss_;
DISALLOW_COPY_AND_ASSIGN(NetworkState); DISALLOW_COPY_AND_ASSIGN(NetworkState);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment