blob: 888a3be7bdde7280242125d334a00e7bdaeef3ab [file] [log] [blame]
// Copyright (c) 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 "chrome/browser/net/nss_context.h"
#include <utility>
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "base/supports_user_data.h"
#include "chrome/browser/profiles/profile_io_data.h"
#include "content/public/browser/browser_thread.h"
#include "crypto/nss_util_internal.h"
#include "net/cert/nss_cert_database_chromeos.h"
namespace {
void* kDatabaseManagerKey = &kDatabaseManagerKey;
class NSSCertDatabaseChromeOSManager : public base::SupportsUserData::Data {
public:
typedef base::Callback<void(net::NSSCertDatabaseChromeOS*)>
GetNSSCertDatabaseCallback;
explicit NSSCertDatabaseChromeOSManager(const std::string& username_hash)
: username_hash_(username_hash), weak_ptr_factory_(this) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
crypto::ScopedPK11Slot private_slot(crypto::GetPrivateSlotForChromeOSUser(
username_hash,
base::Bind(&NSSCertDatabaseChromeOSManager::DidGetPrivateSlot,
weak_ptr_factory_.GetWeakPtr())));
if (private_slot)
DidGetPrivateSlot(std::move(private_slot));
}
~NSSCertDatabaseChromeOSManager() override {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
}
net::NSSCertDatabaseChromeOS* GetNSSCertDatabase(
const GetNSSCertDatabaseCallback& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (nss_cert_database_)
return nss_cert_database_.get();
ready_callback_list_.push_back(callback);
return NULL;
}
private:
typedef std::vector<GetNSSCertDatabaseCallback> ReadyCallbackList;
void DidGetPrivateSlot(crypto::ScopedPK11Slot private_slot) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
nss_cert_database_.reset(new net::NSSCertDatabaseChromeOS(
crypto::GetPublicSlotForChromeOSUser(username_hash_),
std::move(private_slot)));
ReadyCallbackList callback_list;
callback_list.swap(ready_callback_list_);
for (ReadyCallbackList::iterator i = callback_list.begin();
i != callback_list.end();
++i) {
(*i).Run(nss_cert_database_.get());
}
}
std::string username_hash_;
std::unique_ptr<net::NSSCertDatabaseChromeOS> nss_cert_database_;
ReadyCallbackList ready_callback_list_;
base::WeakPtrFactory<NSSCertDatabaseChromeOSManager> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(NSSCertDatabaseChromeOSManager);
};
std::string GetUsername(content::ResourceContext* context) {
return ProfileIOData::FromResourceContext(context)->username_hash();
}
net::NSSCertDatabaseChromeOS* GetNSSCertDatabaseChromeOS(
content::ResourceContext* context,
const NSSCertDatabaseChromeOSManager::GetNSSCertDatabaseCallback&
callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
NSSCertDatabaseChromeOSManager* manager =
static_cast<NSSCertDatabaseChromeOSManager*>(
context->GetUserData(kDatabaseManagerKey));
if (!manager) {
manager = new NSSCertDatabaseChromeOSManager(GetUsername(context));
context->SetUserData(kDatabaseManagerKey, base::WrapUnique(manager));
}
return manager->GetNSSCertDatabase(callback);
}
void CallWithNSSCertDatabase(
const base::Callback<void(net::NSSCertDatabase*)>& callback,
net::NSSCertDatabaseChromeOS* db) {
callback.Run(db);
}
void SetSystemSlot(crypto::ScopedPK11Slot system_slot,
net::NSSCertDatabaseChromeOS* db) {
db->SetSystemSlot(std::move(system_slot));
}
void SetSystemSlotOfDBForResourceContext(content::ResourceContext* context,
crypto::ScopedPK11Slot system_slot) {
base::Callback<void(net::NSSCertDatabaseChromeOS*)> callback =
base::Bind(&SetSystemSlot, base::Passed(&system_slot));
net::NSSCertDatabaseChromeOS* db =
GetNSSCertDatabaseChromeOS(context, callback);
if (db)
callback.Run(db);
}
} // namespace
net::NSSCertDatabase* GetNSSCertDatabaseForResourceContext(
content::ResourceContext* context,
const base::Callback<void(net::NSSCertDatabase*)>& callback) {
return GetNSSCertDatabaseChromeOS(
context, base::Bind(&CallWithNSSCertDatabase, callback));
}
void EnableNSSSystemKeySlotForResourceContext(
content::ResourceContext* context) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
base::Callback<void(crypto::ScopedPK11Slot)> callback =
base::Bind(&SetSystemSlotOfDBForResourceContext, context);
crypto::ScopedPK11Slot system_slot = crypto::GetSystemNSSKeySlot(callback);
if (system_slot)
callback.Run(std::move(system_slot));
}