Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1750)

Unified Diff: net/cert/nss_cert_database_chromeos.cc

Issue 18121007: *WIP* Store NSS slots per profile. Move keygen to chrome. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: more refactoring Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/cert/nss_cert_database_chromeos.h ('k') | net/cert/nss_profile_filter_chromeos.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/cert/nss_cert_database_chromeos.cc
diff --git a/net/cert/nss_cert_database_chromeos.cc b/net/cert/nss_cert_database_chromeos.cc
new file mode 100644
index 0000000000000000000000000000000000000000..0fde443face81aa0eefe7c7ce80554f31145b440
--- /dev/null
+++ b/net/cert/nss_cert_database_chromeos.cc
@@ -0,0 +1,304 @@
+// 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 "net/cert/nss_cert_database_chromeos.h"
+
+#include <cert.h>
+#include <pk11pub.h>
+
+#include <map>
+
+#include "base/bind.h"
+#include "base/lazy_instance.h"
+#include "base/stl_util.h"
+#include "base/threading/non_thread_safe.h"
+#include "crypto/nss_util.h"
+#include "crypto/nss_util_internal.h"
+#include "net/base/crypto_module.h"
+#include "net/cert/x509_certificate.h"
+//#include "net/cert/x509_util_nss.h"
+
+namespace net {
+
+namespace {
+
+scoped_refptr<const X509Certificate> FindCertInSlot(const X509Certificate* cert,
+ PK11SlotInfo* slot) {
+ CERTCertificate* slot_cert_handle = PK11_FindCertFromDERCert(
+ slot, cert->os_cert_handle(), NULL);
+ if (slot_cert_handle) {
+ scoped_refptr<X509Certificate> slot_cert(
+ X509Certificate::CreateFromHandle(slot_cert_handle,
+ X509Certificate::OSCertHandles()));
+ CERT_DestroyCertificate(slot_cert_handle);
+ return slot_cert;
+ }
+ return NULL;
+}
+
+} // namespace
+
+class NSSCertDatabaseChromeOS::Manager : public base::NonThreadSafe {
+ public:
+ ~Manager() {
+ STLDeleteValues(&user_db_map_);
+ }
+
+ // XXX remove this? Or keep it but with a ready callback?
+ /*NSSCertDatabase* GetPrimaryDB() {
+ LOG(WARNING)
+ << "Using primary NSSCertDatabase. Consider using GetForUser instead.";
+ return primary_db_;
+ }*/
+
+ NSSCertDatabase* GetForUser(
+ const std::string& username_hash,
+ const base::Callback<void(NSSCertDatabase*)>& callback) {
+ DCHECK(CalledOnValidThread());
+ UserDBMap::iterator it = user_db_map_.find(username_hash);
+ if (it != user_db_map_.end()) {
+ // DB already exists for this user.
+ if (it->second->ready_)
+ return it->second;
+ it->second->OnReady(callback);
+ return NULL;
+ }
+
+ crypto::ScopedPK11Slot public_slot(
+ crypto::GetPublicSlotForChromeOSUser(username_hash));
+ if (!public_slot) {
+ NOTREACHED();
+ // Invalid user, or someone called us before InitializeNSSForChromeOSUser
+ // got called for the user.
+ // XXX we don't really have a way to return error.. maybe run the callback
+ // with NULL also?
+ //callback.Run(NULL);
+ return NULL;
+ }
+
+ NSSCertDatabaseChromeOS* db = NULL;
+ if (primary_db_owner_) {
+ crypto::ScopedPK11Slot primary_public_slot(primary_db_->GetPublicSlot());
+ if (public_slot.get() == primary_public_slot.get()) {
+ DVLOG(1) << "Got username for primary: " << username_hash;
+ // We now know what username corrosponds to the primary user. Put the
+ // primary_db_ into the user_db_map_, which will now own it.
+ db = primary_db_owner_.release();
+ }
+ }
+
+ if (!db) {
+ // Create DB for new user.
+ DVLOG(1) << "Create DB for: " << username_hash;
+ db = new NSSCertDatabaseChromeOS(public_slot.Pass());
+ crypto::ScopedPK11Slot private_slot(crypto::GetPrivateSlotForChromeOSUser(
+ username_hash,
+ base::Bind(&NSSCertDatabaseChromeOS::SetPrivateSlot,
+ base::Unretained(db))));
+ if (private_slot)
+ db->SetPrivateSlot(private_slot.Pass());
+ }
+
+ user_db_map_[username_hash] = db;
+ if (db->ready_)
+ return db;
+ db->OnReady(callback);
+ return NULL;
+ }
+ private:
+ friend struct base::DefaultLazyInstanceTraits<Manager>;
+
+ Manager()
+ : primary_db_(new NSSCertDatabaseChromeOS(
+ crypto::ScopedPK11Slot(crypto::GetPublicNSSKeySlot()))) {
+ primary_db_owner_.reset(primary_db_);
+ if (crypto::IsTPMTokenReady(base::Bind(&Manager::SetPrimaryPrivateSlot,
+ base::Unretained(this))))
+ SetPrimaryPrivateSlot();
+ }
+
+ void SetPrimaryPrivateSlot() {
+ DCHECK(CalledOnValidThread());
+ primary_db_->SetPrivateSlot(
+ crypto::ScopedPK11Slot(crypto::GetPrivateNSSKeySlot()));
+ }
+
+ // XXX do we still need primary db stuff?
+ NSSCertDatabaseChromeOS* primary_db_;
+ // Holds ownership of |primary_db_| until it has been inserted into the
+ // |user_db_map_|.
+ scoped_ptr<NSSCertDatabaseChromeOS> primary_db_owner_;
+ typedef std::map<std::string, NSSCertDatabaseChromeOS*> UserDBMap;
+ UserDBMap user_db_map_;
+};
+
+namespace {
+base::LazyInstance<NSSCertDatabaseChromeOS::Manager>::Leaky
+ g_nss_cert_database_chromeos_manager = LAZY_INSTANCE_INITIALIZER;
+} // namespace
+
+// static
+NSSCertDatabase* NSSCertDatabaseChromeOS::GetForUser(
+ const std::string& username_hash,
+ const base::Callback<void(NSSCertDatabase*)>& callback) {
+ return g_nss_cert_database_chromeos_manager.Get().GetForUser(username_hash,
+ callback);
+}
+
+NSSCertDatabaseChromeOS::NSSCertDatabaseChromeOS(
+ crypto::ScopedPK11Slot public_slot)
+ : ready_(false), public_slot_(public_slot.Pass()) {
+ DVLOG(1) << __func__ << " pub:" << PK11_GetModuleID(public_slot_.get()) << ":"
+ << PK11_GetSlotID(public_slot_.get());
+ NSSCertDatabase::GetInstanceNoWarn()->AddSource(this);
+}
+
+NSSCertDatabaseChromeOS::~NSSCertDatabaseChromeOS() {}
+
+void NSSCertDatabaseChromeOS::ListCerts(CertificateList* certs) {
+ if (!ready_) {
+ LOG(WARNING) << __func__ << " called before initialization complete";
+ certs->clear();
+ return;
+ }
+ NSSCertDatabase::ListCerts(certs);
+
+ size_t pre_size = certs->size();
+ certs->erase(
+ std::remove_if(certs->begin(), certs->end(),
+ NSSProfileFilterChromeOS::Predicate(profile_filter_)),
+ certs->end());
+ DVLOG(1) << "filtered " << pre_size - certs->size() << " of " << pre_size
+ << " certs";
+}
+
+crypto::ScopedPK11Slot NSSCertDatabaseChromeOS::GetPublicSlot() const {
+ return crypto::ScopedPK11Slot(
+ public_slot_ ? PK11_ReferenceSlot(public_slot_.get()) : NULL);
+}
+
+crypto::ScopedPK11Slot NSSCertDatabaseChromeOS::GetPrivateSlot() const {
+ return crypto::ScopedPK11Slot(
+ private_slot_ ? PK11_ReferenceSlot(private_slot_.get()) : NULL);
+}
+
+void NSSCertDatabaseChromeOS::ListModules(CryptoModuleList* modules,
+ bool need_rw) const {
+ if (!ready_) {
+ LOG(WARNING) << __func__ << " called before initialization complete";
+ modules->clear();
+ return;
+ }
+ NSSCertDatabase::ListModules(modules, need_rw);
+
+ size_t pre_size = modules->size();
+ modules->erase(
+ std::remove_if(modules->begin(), modules->end(),
+ NSSProfileFilterChromeOS::Predicate(profile_filter_)),
+ modules->end());
+ DVLOG(1) << "filtered " << pre_size - modules->size() << " of " << pre_size
+ << " modules";
+}
+
+NSSCertDatabase::TrustBits NSSCertDatabaseChromeOS::GetCertTrust(
+ const X509Certificate* cert,
+ CertType type) const {
+ return NSSCertDatabase::GetCertTrust(ResolveCert(cert, false), type);
+}
+
+bool NSSCertDatabaseChromeOS::IsUntrusted(const X509Certificate* cert) const {
+ return NSSCertDatabase::IsUntrusted(ResolveCert(cert, false));
+}
+
+#if 0
+bool NSSCertDatabaseChromeOS::SetCertTrust(const X509Certificate* cert,
+ CertType type,
+ TrustBits trust_bits) {
+ // XXX handle case of cert not existing in any of this profile's rw slots
+ if (!FindCertInSlot(cert, public_slot_.get())) {
+ // Copy cert to our slot so we can set trust . . .
+ // XXX this doesn't actually help.
+ SECStatus srv = PK11_ImportCert(
+ public_slot_.get(),
+ cert->os_cert_handle(),
+ CK_INVALID_HANDLE,
+ x509_util::GetUniqueNicknameForSlot(cert->GetDefaultNickname(type),
+ &cert->os_cert_handle()->derSubject,
+ public_slot_.get()).c_str(),
+ PR_FALSE /* includeTrust (unused) */);
+ if (srv != SECSuccess) {
+ LOG(ERROR) << "copying cert to our slot failed with error "
+ << PORT_GetError();
+ return false;
+ }
+ DVLOG(1) << "copied cert to our slot";
+ }
+ //
+ // XXX this doesn't work: if cert is in multiple rw slots nss will just set
+ // the trust on the "first" one - we could return false instead of setting
+ // trust in wrong slot? (but how do we know which slot nss would have felt
+ // like setting the trust in? is it always the lowest numbered slotid?)
+ return NSSCertDatabase::SetCertTrust(
+ ResolveCert(cert, true), type, trust_bits);
+}
+#endif
+
+void NSSCertDatabaseChromeOS::SetPrivateSlot(
+ crypto::ScopedPK11Slot private_slot) {
+ DCHECK(!ready_);
+ if (!private_slot)
+ LOG(WARNING) << "initializing with NULL private_slot.";
+ private_slot_ = private_slot.Pass();
+ profile_filter_.Init(GetPublicSlot(), GetPrivateSlot());
+ ready_ = true;
+
+ ReadyCallbackList callback_list;
+ callback_list.swap(ready_callback_list_);
+ for (ReadyCallbackList::iterator i = callback_list.begin();
+ i != callback_list.end();
+ ++i) {
+ (*i).Run(this);
+ }
+}
+
+void NSSCertDatabaseChromeOS::OnReady(
+ const base::Callback<void(NSSCertDatabase*)>& callback) {
+ DCHECK(!ready_);
+ ready_callback_list_.push_back(callback);
+}
+
+scoped_refptr<const X509Certificate> NSSCertDatabaseChromeOS::ResolveCert(
+ const X509Certificate* cert, bool need_rw) const {
+ // If we have a copy in our slot, use that.
+ scoped_refptr<const X509Certificate> pub_slot_cert(
+ FindCertInSlot(cert, public_slot_.get()));
+ if (pub_slot_cert) {
+ DVLOG(1) << "found pub slot cert";
+ return pub_slot_cert;
+ }
+
+ CryptoModuleList module_list;
+ ListModules(&module_list, need_rw);
+ for (CryptoModuleList::iterator i = module_list.begin();
+ i != module_list.end();
+ ++i) {
+ if ((*i)->os_module_handle() == public_slot_.get())
+ continue; // We already checked this slot above.
+ scoped_refptr<const X509Certificate> slot_cert(
+ FindCertInSlot(cert, (*i)->os_module_handle()));
+ if (slot_cert) {
+ DVLOG(1) << "found cert in other slot: "
+ << PK11_GetModuleID((*i)->os_module_handle()) << ":"
+ << PK11_GetSlotID((*i)->os_module_handle());
+ return slot_cert;
+ }
+ }
+
+ // Otherwise, use whatever NSS decides as the default.
+ // XXX should we return NULL here? NOTREACHED?
+ LOG(WARNING) << "using default slot cert";
+ return cert;
+}
+
+} // namespace net
« no previous file with comments | « net/cert/nss_cert_database_chromeos.h ('k') | net/cert/nss_profile_filter_chromeos.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698