summaryrefslogtreecommitdiffstats
path: root/chromeos
diff options
context:
space:
mode:
authorpneubeck@chromium.org <pneubeck@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-06 17:15:48 +0000
committerpneubeck@chromium.org <pneubeck@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-06 17:15:48 +0000
commit18e8d54f5e70ed8576fdb97aaed5de00ad663e72 (patch)
treef3b3710eadd94552bf4ef30471bd2a9aaa3366da /chromeos
parentd8f1fa0dbe1507b1330c19315ddcfb7c6ef68e70 (diff)
downloadchromium_src-18e8d54f5e70ed8576fdb97aaed5de00ad663e72.zip
chromium_src-18e8d54f5e70ed8576fdb97aaed5de00ad663e72.tar.gz
chromium_src-18e8d54f5e70ed8576fdb97aaed5de00ad663e72.tar.bz2
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
Diffstat (limited to 'chromeos')
-rw-r--r--chromeos/cert_loader.cc23
-rw-r--r--chromeos/cert_loader.h10
-rw-r--r--chromeos/chromeos.gyp4
-rw-r--r--chromeos/dbus/shill_service_client_stub.cc23
-rw-r--r--chromeos/network/network_cert_migrator.cc259
-rw-r--r--chromeos/network/network_cert_migrator.h50
-rw-r--r--chromeos/network/network_cert_migrator_unittest.cc264
-rw-r--r--chromeos/network/network_handler.cc6
-rw-r--r--chromeos/network/network_handler.h2
-rw-r--r--chromeos/network/network_state.cc33
-rw-r--r--chromeos/network/network_state.h7
11 files changed, 670 insertions, 11 deletions
diff --git a/chromeos/cert_loader.cc b/chromeos/cert_loader.cc
index 5d76711..799815d 100644
--- a/chromeos/cert_loader.cc
+++ b/chromeos/cert_loader.cc
@@ -59,6 +59,7 @@ void CallOpenPersistentNSSDB() {
} // namespace
static CertLoader* g_cert_loader = NULL;
+
// static
void CertLoader::Initialize() {
CHECK(!g_cert_loader);
@@ -108,6 +109,11 @@ void CertLoader::SetCryptoTaskRunner(
MaybeRequestCertificates();
}
+void CertLoader::SetSlowTaskRunnerForTest(
+ const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
+ slow_task_runner_for_test_ = task_runner;
+}
+
CertLoader::~CertLoader() {
net::CertDatabase::GetInstance()->RemoveObserver(this);
if (LoginState::IsInitialized())
@@ -330,13 +336,16 @@ void CertLoader::StartLoadCertificates() {
net::CertificateList* cert_list = new net::CertificateList;
certificates_update_running_ = true;
certificates_update_required_ = false;
- base::WorkerPool::GetTaskRunner(true /* task_is_slow */)->
- PostTaskAndReply(
- FROM_HERE,
- base::Bind(LoadNSSCertificates, cert_list),
- base::Bind(&CertLoader::UpdateCertificates,
- update_certificates_factory_.GetWeakPtr(),
- base::Owned(cert_list)));
+
+ base::TaskRunner* task_runner = slow_task_runner_for_test_.get();
+ if (!task_runner)
+ task_runner = base::WorkerPool::GetTaskRunner(true /* task is slow */);
+ task_runner->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(LoadNSSCertificates, cert_list),
+ base::Bind(&CertLoader::UpdateCertificates,
+ update_certificates_factory_.GetWeakPtr(),
+ base::Owned(cert_list)));
}
void CertLoader::UpdateCertificates(net::CertificateList* cert_list) {
diff --git a/chromeos/cert_loader.h b/chromeos/cert_loader.h
index 69e3191..ec2d7ce 100644
--- a/chromeos/cert_loader.h
+++ b/chromeos/cert_loader.h
@@ -66,12 +66,17 @@ class CHROMEOS_EXPORT CertLoader : public net::CertDatabase::Observer,
static bool IsInitialized();
// |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
// this is set.
void SetCryptoTaskRunner(
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 RemoveObserver(CertLoader::Observer* observer);
@@ -167,6 +172,9 @@ class CHROMEOS_EXPORT CertLoader : public net::CertDatabase::Observer,
// TaskRunner for crypto calls.
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
// initialization.
base::WeakPtrFactory<CertLoader> initialize_token_factory_;
diff --git a/chromeos/chromeos.gyp b/chromeos/chromeos.gyp
index 6ae7624..32691f1 100644
--- a/chromeos/chromeos.gyp
+++ b/chromeos/chromeos.gyp
@@ -228,6 +228,8 @@
'network/managed_network_configuration_handler.h',
'network/managed_state.cc',
'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.h',
'network/network_change_notifier_factory_chromeos.cc',
@@ -447,6 +449,7 @@
'../crypto/crypto.gyp:crypto',
'../dbus/dbus.gyp:dbus_test_support',
'../net/net.gyp:net',
+ '../net/net.gyp:net_test_support',
'../testing/gmock.gyp:gmock',
'../testing/gtest.gyp:gtest',
'../url/url.gyp:url_lib',
@@ -494,6 +497,7 @@
'network/cros_network_functions_unittest.cc',
'network/geolocation_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_configuration_handler_unittest.cc',
'network/network_connection_handler_unittest.cc',
diff --git a/chromeos/dbus/shill_service_client_stub.cc b/chromeos/dbus/shill_service_client_stub.cc
index 197e19b..f46d2d5 100644
--- a/chromeos/dbus/shill_service_client_stub.cc
+++ b/chromeos/dbus/shill_service_client_stub.cc
@@ -8,6 +8,7 @@
#include "base/command_line.h"
#include "base/message_loop/message_loop.h"
#include "base/stl_util.h"
+#include "base/strings/string_util.h"
#include "base/values.h"
#include "chromeos/chromeos_switches.h"
#include "chromeos/dbus/dbus_thread_manager.h"
@@ -356,12 +357,30 @@ bool ShillServiceClientStub::SetServiceProperty(const std::string& service_path,
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(
FROM_HERE,
base::Bind(&ShillServiceClientStub::NotifyObserversPropertyChanged,
weak_ptr_factory_.GetWeakPtr(),
- dbus::ObjectPath(service_path), property));
+ dbus::ObjectPath(service_path), changed_property));
return true;
}
diff --git a/chromeos/network/network_cert_migrator.cc b/chromeos/network/network_cert_migrator.cc
new file mode 100644
index 0000000..baca3c0
--- /dev/null
+++ b/chromeos/network/network_cert_migrator.cc
@@ -0,0 +1,259 @@
+// 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
diff --git a/chromeos/network/network_cert_migrator.h b/chromeos/network/network_cert_migrator.h
new file mode 100644
index 0000000..05b69e6
--- /dev/null
+++ b/chromeos/network/network_cert_migrator.h
@@ -0,0 +1,50 @@
+// 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_
diff --git a/chromeos/network/network_cert_migrator_unittest.cc b/chromeos/network/network_cert_migrator_unittest.cc
new file mode 100644
index 0000000..ee2dcdf
--- /dev/null
+++ b/chromeos/network/network_cert_migrator_unittest.cc
@@ -0,0 +1,264 @@
+// 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
diff --git a/chromeos/network/network_handler.cc b/chromeos/network/network_handler.cc
index fc6896b..ae272fa 100644
--- a/chromeos/network/network_handler.cc
+++ b/chromeos/network/network_handler.cc
@@ -4,9 +4,11 @@
#include "chromeos/network/network_handler.h"
+#include "base/threading/worker_pool.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/network/geolocation_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_connection_handler.h"
#include "chromeos/network/network_device_handler.h"
@@ -29,6 +31,8 @@ NetworkHandler::NetworkHandler() {
network_state_handler_.reset(new NetworkStateHandler());
network_device_handler_.reset(new NetworkDeviceHandler());
network_profile_handler_.reset(new NetworkProfileHandler());
+ if (CertLoader::IsInitialized())
+ network_cert_migrator_.reset(new NetworkCertMigrator());
network_configuration_handler_.reset(new NetworkConfigurationHandler());
managed_network_configuration_handler_.reset(
new ManagedNetworkConfigurationHandler());
@@ -44,6 +48,8 @@ NetworkHandler::~NetworkHandler() {
void NetworkHandler::Init() {
network_state_handler_->InitShillPropertyHandler();
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());
managed_network_configuration_handler_->Init(
network_state_handler_.get(),
diff --git a/chromeos/network/network_handler.h b/chromeos/network/network_handler.h
index 9cc2d46..a791f9e 100644
--- a/chromeos/network/network_handler.h
+++ b/chromeos/network/network_handler.h
@@ -13,6 +13,7 @@ namespace chromeos {
class GeolocationHandler;
class ManagedNetworkConfigurationHandler;
+class NetworkCertMigrator;
class NetworkConfigurationHandler;
class NetworkConnectionHandler;
class NetworkDeviceHandler;
@@ -59,6 +60,7 @@ class CHROMEOS_EXPORT NetworkHandler {
scoped_ptr<NetworkStateHandler> network_state_handler_;
scoped_ptr<NetworkDeviceHandler> network_device_handler_;
scoped_ptr<NetworkProfileHandler> network_profile_handler_;
+ scoped_ptr<NetworkCertMigrator> network_cert_migrator_;
scoped_ptr<NetworkConfigurationHandler> network_configuration_handler_;
scoped_ptr<ManagedNetworkConfigurationHandler>
managed_network_configuration_handler_;
diff --git a/chromeos/network/network_state.cc b/chromeos/network/network_state.cc
index ca0b7b6..f0da62d 100644
--- a/chromeos/network/network_state.cc
+++ b/chromeos/network/network_state.cc
@@ -68,6 +68,33 @@ chromeos::NetworkUIData* CreateUIDataFromValue(
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 chromeos {
@@ -82,7 +109,8 @@ NetworkState::NetworkState(const std::string& path)
signal_strength_(0),
connectable_(false),
activate_over_non_cellular_networks_(false),
- cellular_out_of_credits_(false) {
+ cellular_out_of_credits_(false),
+ has_ca_cert_nss_(false) {
}
NetworkState::~NetworkState() {
@@ -191,6 +219,9 @@ bool NetworkState::PropertyChanged(const std::string& key,
bool NetworkState::InitialPropertiesReceived(
const base::DictionaryValue& 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;
}
diff --git a/chromeos/network/network_state.h b/chromeos/network/network_state.h
index 5263d00..f177794 100644
--- a/chromeos/network/network_state.h
+++ b/chromeos/network/network_state.h
@@ -74,6 +74,9 @@ class CHROMEOS_EXPORT NetworkState : public ManagedState {
const std::string& post_method() const { return post_method_; }
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.
bool IsConnectedState() const;
bool IsConnectingState() const;
@@ -154,6 +157,10 @@ class CHROMEOS_EXPORT NetworkState : public ManagedState {
std::string post_method_;
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);
};