Home | History | Annotate | Download | only in crypto
      1 // Copyright (c) 2012 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 
      5 #include "crypto/nss_util.h"
      6 #include "crypto/nss_util_internal.h"
      7 
      8 #include <nss.h>
      9 #include <pk11pub.h>
     10 #include <plarena.h>
     11 #include <prerror.h>
     12 #include <prinit.h>
     13 #include <prtime.h>
     14 #include <secmod.h>
     15 
     16 #if defined(OS_OPENBSD)
     17 #include <sys/mount.h>
     18 #include <sys/param.h>
     19 #endif
     20 
     21 #include <map>
     22 #include <vector>
     23 
     24 #include "base/base_paths.h"
     25 #include "base/bind.h"
     26 #include "base/cpu.h"
     27 #include "base/debug/alias.h"
     28 #include "base/debug/stack_trace.h"
     29 #include "base/environment.h"
     30 #include "base/file_util.h"
     31 #include "base/files/file_path.h"
     32 #include "base/lazy_instance.h"
     33 #include "base/logging.h"
     34 #include "base/memory/scoped_ptr.h"
     35 #include "base/message_loop/message_loop.h"
     36 #include "base/metrics/histogram.h"
     37 #include "base/native_library.h"
     38 #include "base/path_service.h"
     39 #include "base/stl_util.h"
     40 #include "base/strings/stringprintf.h"
     41 #include "base/threading/thread_checker.h"
     42 #include "base/threading/thread_restrictions.h"
     43 #include "base/threading/worker_pool.h"
     44 #include "build/build_config.h"
     45 
     46 // USE_NSS means we use NSS for everything crypto-related.  If USE_NSS is not
     47 // defined, such as on Mac and Windows, we use NSS for SSL only -- we don't
     48 // use NSS for crypto or certificate verification, and we don't use the NSS
     49 // certificate and key databases.
     50 #if defined(USE_NSS)
     51 #include "base/synchronization/lock.h"
     52 #include "crypto/nss_crypto_module_delegate.h"
     53 #endif  // defined(USE_NSS)
     54 
     55 namespace crypto {
     56 
     57 namespace {
     58 
     59 #if defined(OS_CHROMEOS)
     60 const char kNSSDatabaseName[] = "Real NSS database";
     61 
     62 // Constants for loading the Chrome OS TPM-backed PKCS #11 library.
     63 const char kChapsModuleName[] = "Chaps";
     64 const char kChapsPath[] = "libchaps.so";
     65 
     66 // Fake certificate authority database used for testing.
     67 static const base::FilePath::CharType kReadOnlyCertDB[] =
     68     FILE_PATH_LITERAL("/etc/fake_root_ca/nssdb");
     69 #endif  // defined(OS_CHROMEOS)
     70 
     71 std::string GetNSSErrorMessage() {
     72   std::string result;
     73   if (PR_GetErrorTextLength()) {
     74     scoped_ptr<char[]> error_text(new char[PR_GetErrorTextLength() + 1]);
     75     PRInt32 copied = PR_GetErrorText(error_text.get());
     76     result = std::string(error_text.get(), copied);
     77   } else {
     78     result = base::StringPrintf("NSS error code: %d", PR_GetError());
     79   }
     80   return result;
     81 }
     82 
     83 #if defined(USE_NSS)
     84 base::FilePath GetDefaultConfigDirectory() {
     85   base::FilePath dir;
     86   PathService::Get(base::DIR_HOME, &dir);
     87   if (dir.empty()) {
     88     LOG(ERROR) << "Failed to get home directory.";
     89     return dir;
     90   }
     91   dir = dir.AppendASCII(".pki").AppendASCII("nssdb");
     92   if (!base::CreateDirectory(dir)) {
     93     LOG(ERROR) << "Failed to create " << dir.value() << " directory.";
     94     dir.clear();
     95   }
     96   DVLOG(2) << "DefaultConfigDirectory: " << dir.value();
     97   return dir;
     98 }
     99 
    100 // On non-Chrome OS platforms, return the default config directory. On Chrome OS
    101 // test images, return a read-only directory with fake root CA certs (which are
    102 // used by the local Google Accounts server mock we use when testing our login
    103 // code). On Chrome OS non-test images (where the read-only directory doesn't
    104 // exist), return an empty path.
    105 base::FilePath GetInitialConfigDirectory() {
    106 #if defined(OS_CHROMEOS)
    107   base::FilePath database_dir = base::FilePath(kReadOnlyCertDB);
    108   if (!base::PathExists(database_dir))
    109     database_dir.clear();
    110   return database_dir;
    111 #else
    112   return GetDefaultConfigDirectory();
    113 #endif  // defined(OS_CHROMEOS)
    114 }
    115 
    116 // This callback for NSS forwards all requests to a caller-specified
    117 // CryptoModuleBlockingPasswordDelegate object.
    118 char* PKCS11PasswordFunc(PK11SlotInfo* slot, PRBool retry, void* arg) {
    119   crypto::CryptoModuleBlockingPasswordDelegate* delegate =
    120       reinterpret_cast<crypto::CryptoModuleBlockingPasswordDelegate*>(arg);
    121   if (delegate) {
    122     bool cancelled = false;
    123     std::string password = delegate->RequestPassword(PK11_GetTokenName(slot),
    124                                                      retry != PR_FALSE,
    125                                                      &cancelled);
    126     if (cancelled)
    127       return NULL;
    128     char* result = PORT_Strdup(password.c_str());
    129     password.replace(0, password.size(), password.size(), 0);
    130     return result;
    131   }
    132   DLOG(ERROR) << "PK11 password requested with NULL arg";
    133   return NULL;
    134 }
    135 
    136 // NSS creates a local cache of the sqlite database if it detects that the
    137 // filesystem the database is on is much slower than the local disk.  The
    138 // detection doesn't work with the latest versions of sqlite, such as 3.6.22
    139 // (NSS bug https://bugzilla.mozilla.org/show_bug.cgi?id=578561).  So we set
    140 // the NSS environment variable NSS_SDB_USE_CACHE to "yes" to override NSS's
    141 // detection when database_dir is on NFS.  See http://crbug.com/48585.
    142 //
    143 // TODO(wtc): port this function to other USE_NSS platforms.  It is defined
    144 // only for OS_LINUX and OS_OPENBSD simply because the statfs structure
    145 // is OS-specific.
    146 //
    147 // Because this function sets an environment variable it must be run before we
    148 // go multi-threaded.
    149 void UseLocalCacheOfNSSDatabaseIfNFS(const base::FilePath& database_dir) {
    150   bool db_on_nfs = false;
    151 #if defined(OS_LINUX)
    152   base::FileSystemType fs_type = base::FILE_SYSTEM_UNKNOWN;
    153   if (base::GetFileSystemType(database_dir, &fs_type))
    154     db_on_nfs = (fs_type == base::FILE_SYSTEM_NFS);
    155 #elif defined(OS_OPENBSD)
    156   struct statfs buf;
    157   if (statfs(database_dir.value().c_str(), &buf) == 0)
    158     db_on_nfs = (strcmp(buf.f_fstypename, MOUNT_NFS) == 0);
    159 #else
    160   NOTIMPLEMENTED();
    161 #endif
    162 
    163   if (db_on_nfs) {
    164     scoped_ptr<base::Environment> env(base::Environment::Create());
    165     static const char kUseCacheEnvVar[] = "NSS_SDB_USE_CACHE";
    166     if (!env->HasVar(kUseCacheEnvVar))
    167       env->SetVar(kUseCacheEnvVar, "yes");
    168   }
    169 }
    170 
    171 #endif  // defined(USE_NSS)
    172 
    173 // A singleton to initialize/deinitialize NSPR.
    174 // Separate from the NSS singleton because we initialize NSPR on the UI thread.
    175 // Now that we're leaking the singleton, we could merge back with the NSS
    176 // singleton.
    177 class NSPRInitSingleton {
    178  private:
    179   friend struct base::DefaultLazyInstanceTraits<NSPRInitSingleton>;
    180 
    181   NSPRInitSingleton() {
    182     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
    183   }
    184 
    185   // NOTE(willchan): We don't actually execute this code since we leak NSS to
    186   // prevent non-joinable threads from using NSS after it's already been shut
    187   // down.
    188   ~NSPRInitSingleton() {
    189     PL_ArenaFinish();
    190     PRStatus prstatus = PR_Cleanup();
    191     if (prstatus != PR_SUCCESS)
    192       LOG(ERROR) << "PR_Cleanup failed; was NSPR initialized on wrong thread?";
    193   }
    194 };
    195 
    196 base::LazyInstance<NSPRInitSingleton>::Leaky
    197     g_nspr_singleton = LAZY_INSTANCE_INITIALIZER;
    198 
    199 // This is a LazyInstance so that it will be deleted automatically when the
    200 // unittest exits.  NSSInitSingleton is a LeakySingleton, so it would not be
    201 // deleted if it were a regular member.
    202 base::LazyInstance<base::ScopedTempDir> g_test_nss_db_dir =
    203     LAZY_INSTANCE_INITIALIZER;
    204 
    205 // Force a crash with error info on NSS_NoDB_Init failure.
    206 void CrashOnNSSInitFailure() {
    207   int nss_error = PR_GetError();
    208   int os_error = PR_GetOSError();
    209   base::debug::Alias(&nss_error);
    210   base::debug::Alias(&os_error);
    211   LOG(ERROR) << "Error initializing NSS without a persistent database: "
    212              << GetNSSErrorMessage();
    213   LOG(FATAL) << "nss_error=" << nss_error << ", os_error=" << os_error;
    214 }
    215 
    216 #if defined(OS_CHROMEOS)
    217 class ChromeOSUserData {
    218  public:
    219   ChromeOSUserData(ScopedPK11Slot public_slot, bool is_primary_user)
    220       : public_slot_(public_slot.Pass()),
    221         is_primary_user_(is_primary_user) {}
    222   ~ChromeOSUserData() {
    223     if (public_slot_ && !is_primary_user_) {
    224       SECStatus status = SECMOD_CloseUserDB(public_slot_.get());
    225       if (status != SECSuccess)
    226         PLOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError();
    227     }
    228   }
    229 
    230   ScopedPK11Slot GetPublicSlot() {
    231     return ScopedPK11Slot(
    232         public_slot_ ? PK11_ReferenceSlot(public_slot_.get()) : NULL);
    233   }
    234 
    235   ScopedPK11Slot GetPrivateSlot(
    236       const base::Callback<void(ScopedPK11Slot)>& callback) {
    237     if (private_slot_)
    238       return ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get()));
    239     if (!callback.is_null())
    240       tpm_ready_callback_list_.push_back(callback);
    241     return ScopedPK11Slot();
    242   }
    243 
    244   void SetPrivateSlot(ScopedPK11Slot private_slot) {
    245     DCHECK(!private_slot_);
    246     private_slot_ = private_slot.Pass();
    247 
    248     SlotReadyCallbackList callback_list;
    249     callback_list.swap(tpm_ready_callback_list_);
    250     for (SlotReadyCallbackList::iterator i = callback_list.begin();
    251          i != callback_list.end();
    252          ++i) {
    253       (*i).Run(ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get())));
    254     }
    255   }
    256 
    257  private:
    258   ScopedPK11Slot public_slot_;
    259   ScopedPK11Slot private_slot_;
    260   bool is_primary_user_;
    261 
    262   typedef std::vector<base::Callback<void(ScopedPK11Slot)> >
    263       SlotReadyCallbackList;
    264   SlotReadyCallbackList tpm_ready_callback_list_;
    265 };
    266 #endif  // defined(OS_CHROMEOS)
    267 
    268 class NSSInitSingleton {
    269  public:
    270 #if defined(OS_CHROMEOS)
    271   // Used with PostTaskAndReply to pass handles to worker thread and back.
    272   struct TPMModuleAndSlot {
    273     explicit TPMModuleAndSlot(SECMODModule* init_chaps_module)
    274         : chaps_module(init_chaps_module), tpm_slot(NULL) {}
    275     SECMODModule* chaps_module;
    276     PK11SlotInfo* tpm_slot;
    277   };
    278 
    279   void OpenPersistentNSSDB() {
    280     DCHECK(thread_checker_.CalledOnValidThread());
    281 
    282     if (!chromeos_user_logged_in_) {
    283       // GetDefaultConfigDirectory causes us to do blocking IO on UI thread.
    284       // Temporarily allow it until we fix http://crbug.com/70119
    285       base::ThreadRestrictions::ScopedAllowIO allow_io;
    286       chromeos_user_logged_in_ = true;
    287 
    288       // This creates another DB slot in NSS that is read/write, unlike
    289       // the fake root CA cert DB and the "default" crypto key
    290       // provider, which are still read-only (because we initialized
    291       // NSS before we had a cryptohome mounted).
    292       software_slot_ = OpenUserDB(GetDefaultConfigDirectory(),
    293                                   kNSSDatabaseName);
    294     }
    295   }
    296 
    297   PK11SlotInfo* OpenPersistentNSSDBForPath(const base::FilePath& path) {
    298     DCHECK(thread_checker_.CalledOnValidThread());
    299     // NSS is allowed to do IO on the current thread since dispatching
    300     // to a dedicated thread would still have the affect of blocking
    301     // the current thread, due to NSS's internal locking requirements
    302     base::ThreadRestrictions::ScopedAllowIO allow_io;
    303 
    304     base::FilePath nssdb_path = path.AppendASCII(".pki").AppendASCII("nssdb");
    305     if (!base::CreateDirectory(nssdb_path)) {
    306       LOG(ERROR) << "Failed to create " << nssdb_path.value() << " directory.";
    307       return NULL;
    308     }
    309     return OpenUserDB(nssdb_path, kNSSDatabaseName);
    310   }
    311 
    312   void EnableTPMTokenForNSS() {
    313     DCHECK(thread_checker_.CalledOnValidThread());
    314 
    315     // If this gets set, then we'll use the TPM for certs with
    316     // private keys, otherwise we'll fall back to the software
    317     // implementation.
    318     tpm_token_enabled_for_nss_ = true;
    319   }
    320 
    321   bool IsTPMTokenEnabledForNSS() {
    322     DCHECK(thread_checker_.CalledOnValidThread());
    323     return tpm_token_enabled_for_nss_;
    324   }
    325 
    326   void InitializeTPMToken(int token_slot_id,
    327                           const base::Callback<void(bool)>& callback) {
    328     DCHECK(thread_checker_.CalledOnValidThread());
    329     // Should not be called while there is already an initialization in
    330     // progress.
    331     DCHECK(!initializing_tpm_token_);
    332     // If EnableTPMTokenForNSS hasn't been called, return false.
    333     if (!tpm_token_enabled_for_nss_) {
    334       base::MessageLoop::current()->PostTask(FROM_HERE,
    335                                              base::Bind(callback, false));
    336       return;
    337     }
    338 
    339     // If everything is already initialized, then return true.
    340     // Note that only |tpm_slot_| is checked, since |chaps_module_| could be
    341     // NULL in tests while |tpm_slot_| has been set to the test DB.
    342     if (tpm_slot_) {
    343       base::MessageLoop::current()->PostTask(FROM_HERE,
    344                                              base::Bind(callback, true));
    345       return;
    346     }
    347 
    348     // Note that a reference is not taken to chaps_module_. This is safe since
    349     // NSSInitSingleton is Leaky, so the reference it holds is never released.
    350     scoped_ptr<TPMModuleAndSlot> tpm_args(new TPMModuleAndSlot(chaps_module_));
    351     TPMModuleAndSlot* tpm_args_ptr = tpm_args.get();
    352     if (base::WorkerPool::PostTaskAndReply(
    353             FROM_HERE,
    354             base::Bind(&NSSInitSingleton::InitializeTPMTokenOnWorkerThread,
    355                        token_slot_id,
    356                        tpm_args_ptr),
    357             base::Bind(&NSSInitSingleton::OnInitializedTPMToken,
    358                        base::Unretained(this),  // NSSInitSingleton is leaky
    359                        callback,
    360                        base::Passed(&tpm_args)),
    361             true /* task_is_slow */
    362             )) {
    363       initializing_tpm_token_ = true;
    364     } else {
    365       base::MessageLoop::current()->PostTask(FROM_HERE,
    366                                              base::Bind(callback, false));
    367     }
    368   }
    369 
    370   static void InitializeTPMTokenOnWorkerThread(CK_SLOT_ID token_slot_id,
    371                                                TPMModuleAndSlot* tpm_args) {
    372     // This tries to load the Chaps module so NSS can talk to the hardware
    373     // TPM.
    374     if (!tpm_args->chaps_module) {
    375       DVLOG(3) << "Loading chaps...";
    376       tpm_args->chaps_module = LoadModule(
    377           kChapsModuleName,
    378           kChapsPath,
    379           // For more details on these parameters, see:
    380           // https://developer.mozilla.org/en/PKCS11_Module_Specs
    381           // slotFlags=[PublicCerts] -- Certificates and public keys can be
    382           //   read from this slot without requiring a call to C_Login.
    383           // askpw=only -- Only authenticate to the token when necessary.
    384           "NSS=\"slotParams=(0={slotFlags=[PublicCerts] askpw=only})\"");
    385     }
    386     if (tpm_args->chaps_module) {
    387       tpm_args->tpm_slot =
    388           GetTPMSlotForIdOnWorkerThread(tpm_args->chaps_module, token_slot_id);
    389     }
    390   }
    391 
    392   void OnInitializedTPMToken(const base::Callback<void(bool)>& callback,
    393                              scoped_ptr<TPMModuleAndSlot> tpm_args) {
    394     DCHECK(thread_checker_.CalledOnValidThread());
    395     DVLOG(2) << "Loaded chaps: " << !!tpm_args->chaps_module
    396              << ", got tpm slot: " << !!tpm_args->tpm_slot;
    397 
    398     chaps_module_ = tpm_args->chaps_module;
    399     tpm_slot_ = tpm_args->tpm_slot;
    400     if (!chaps_module_ && test_slot_) {
    401       // chromeos_unittests try to test the TPM initialization process. If we
    402       // have a test DB open, pretend that it is the TPM slot.
    403       tpm_slot_ = PK11_ReferenceSlot(test_slot_);
    404     }
    405     initializing_tpm_token_ = false;
    406 
    407     if (tpm_slot_) {
    408       TPMReadyCallbackList callback_list;
    409       callback_list.swap(tpm_ready_callback_list_);
    410       for (TPMReadyCallbackList::iterator i = callback_list.begin();
    411            i != callback_list.end();
    412            ++i) {
    413         (*i).Run();
    414       }
    415     }
    416 
    417     callback.Run(!!tpm_slot_);
    418   }
    419 
    420   bool IsTPMTokenReady(const base::Closure& callback) {
    421     if (!callback.is_null()) {
    422       // Cannot DCHECK in the general case yet, but since the callback is
    423       // a new addition to the API, DCHECK to make sure at least the new uses
    424       // don't regress.
    425       DCHECK(thread_checker_.CalledOnValidThread());
    426     } else if (!thread_checker_.CalledOnValidThread()) {
    427       // TODO(mattm): Change to DCHECK when callers have been fixed.
    428       DVLOG(1) << "Called on wrong thread.\n"
    429                << base::debug::StackTrace().ToString();
    430     }
    431 
    432     if (tpm_slot_ != NULL)
    433       return true;
    434 
    435     if (!callback.is_null())
    436       tpm_ready_callback_list_.push_back(callback);
    437 
    438     return false;
    439   }
    440 
    441   // Note that CK_SLOT_ID is an unsigned long, but cryptohome gives us the slot
    442   // id as an int. This should be safe since this is only used with chaps, which
    443   // we also control.
    444   static PK11SlotInfo* GetTPMSlotForIdOnWorkerThread(SECMODModule* chaps_module,
    445                                                      CK_SLOT_ID slot_id) {
    446     DCHECK(chaps_module);
    447 
    448     DVLOG(3) << "Poking chaps module.";
    449     SECStatus rv = SECMOD_UpdateSlotList(chaps_module);
    450     if (rv != SECSuccess)
    451       PLOG(ERROR) << "SECMOD_UpdateSlotList failed: " << PORT_GetError();
    452 
    453     PK11SlotInfo* slot = SECMOD_LookupSlot(chaps_module->moduleID, slot_id);
    454     if (!slot)
    455       LOG(ERROR) << "TPM slot " << slot_id << " not found.";
    456     return slot;
    457   }
    458 
    459   bool InitializeNSSForChromeOSUser(
    460       const std::string& email,
    461       const std::string& username_hash,
    462       bool is_primary_user,
    463       const base::FilePath& path) {
    464     DCHECK(thread_checker_.CalledOnValidThread());
    465     if (chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()) {
    466       // This user already exists in our mapping.
    467       DVLOG(2) << username_hash << " already initialized.";
    468       return false;
    469     }
    470     ScopedPK11Slot public_slot;
    471     if (is_primary_user) {
    472       DVLOG(2) << "Primary user, using GetPublicNSSKeySlot()";
    473       public_slot.reset(GetPublicNSSKeySlot());
    474     } else {
    475       DVLOG(2) << "Opening NSS DB " << path.value();
    476       public_slot.reset(OpenPersistentNSSDBForPath(path));
    477     }
    478     chromeos_user_map_[username_hash] =
    479         new ChromeOSUserData(public_slot.Pass(), is_primary_user);
    480     return true;
    481   }
    482 
    483   void InitializeTPMForChromeOSUser(const std::string& username_hash,
    484                                     CK_SLOT_ID slot_id) {
    485     DCHECK(thread_checker_.CalledOnValidThread());
    486     DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
    487 
    488     if (!chaps_module_)
    489       return;
    490 
    491     // Note that a reference is not taken to chaps_module_. This is safe since
    492     // NSSInitSingleton is Leaky, so the reference it holds is never released.
    493     scoped_ptr<TPMModuleAndSlot> tpm_args(new TPMModuleAndSlot(chaps_module_));
    494     TPMModuleAndSlot* tpm_args_ptr = tpm_args.get();
    495     base::WorkerPool::PostTaskAndReply(
    496         FROM_HERE,
    497         base::Bind(&NSSInitSingleton::InitializeTPMTokenOnWorkerThread,
    498                    slot_id,
    499                    tpm_args_ptr),
    500         base::Bind(&NSSInitSingleton::OnInitializedTPMForChromeOSUser,
    501                    base::Unretained(this),  // NSSInitSingleton is leaky
    502                    username_hash,
    503                    base::Passed(&tpm_args)),
    504         true /* task_is_slow */
    505         );
    506   }
    507 
    508   void OnInitializedTPMForChromeOSUser(const std::string& username_hash,
    509                                        scoped_ptr<TPMModuleAndSlot> tpm_args) {
    510     DCHECK(thread_checker_.CalledOnValidThread());
    511     DVLOG(2) << "Got tpm slot for " << username_hash << " "
    512              << !!tpm_args->tpm_slot;
    513     chromeos_user_map_[username_hash]->SetPrivateSlot(
    514         ScopedPK11Slot(tpm_args->tpm_slot));
    515   }
    516 
    517   void InitializePrivateSoftwareSlotForChromeOSUser(
    518       const std::string& username_hash) {
    519     DCHECK(thread_checker_.CalledOnValidThread());
    520     VLOG(1) << "using software private slot for " << username_hash;
    521     DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
    522     chromeos_user_map_[username_hash]->SetPrivateSlot(
    523         chromeos_user_map_[username_hash]->GetPublicSlot());
    524   }
    525 
    526   ScopedPK11Slot GetPublicSlotForChromeOSUser(
    527       const std::string& username_hash) {
    528     DCHECK(thread_checker_.CalledOnValidThread());
    529 
    530     if (username_hash.empty()) {
    531       DVLOG(2) << "empty username_hash";
    532       return ScopedPK11Slot();
    533     }
    534 
    535     if (test_slot_) {
    536       DVLOG(2) << "returning test_slot_ for " << username_hash;
    537       return ScopedPK11Slot(PK11_ReferenceSlot(test_slot_));
    538     }
    539 
    540     if (chromeos_user_map_.find(username_hash) == chromeos_user_map_.end()) {
    541       LOG(ERROR) << username_hash << " not initialized.";
    542       return ScopedPK11Slot();
    543     }
    544     return chromeos_user_map_[username_hash]->GetPublicSlot();
    545   }
    546 
    547   ScopedPK11Slot GetPrivateSlotForChromeOSUser(
    548       const std::string& username_hash,
    549       const base::Callback<void(ScopedPK11Slot)>& callback) {
    550     DCHECK(thread_checker_.CalledOnValidThread());
    551 
    552     if (username_hash.empty()) {
    553       DVLOG(2) << "empty username_hash";
    554       if (!callback.is_null()) {
    555         base::MessageLoop::current()->PostTask(
    556             FROM_HERE, base::Bind(callback, base::Passed(ScopedPK11Slot())));
    557       }
    558       return ScopedPK11Slot();
    559     }
    560 
    561     DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
    562 
    563     if (test_slot_) {
    564       DVLOG(2) << "returning test_slot_ for " << username_hash;
    565       return ScopedPK11Slot(PK11_ReferenceSlot(test_slot_));
    566     }
    567 
    568     return chromeos_user_map_[username_hash]->GetPrivateSlot(callback);
    569   }
    570 
    571   void CloseTestChromeOSUser(const std::string& username_hash) {
    572     DCHECK(thread_checker_.CalledOnValidThread());
    573     ChromeOSUserMap::iterator i = chromeos_user_map_.find(username_hash);
    574     DCHECK(i != chromeos_user_map_.end());
    575     delete i->second;
    576     chromeos_user_map_.erase(i);
    577   }
    578 #endif  // defined(OS_CHROMEOS)
    579 
    580 
    581   bool OpenTestNSSDB() {
    582     DCHECK(thread_checker_.CalledOnValidThread());
    583     // NSS is allowed to do IO on the current thread since dispatching
    584     // to a dedicated thread would still have the affect of blocking
    585     // the current thread, due to NSS's internal locking requirements
    586     base::ThreadRestrictions::ScopedAllowIO allow_io;
    587 
    588     if (test_slot_)
    589       return true;
    590     if (!g_test_nss_db_dir.Get().CreateUniqueTempDir())
    591       return false;
    592     test_slot_ = OpenUserDB(g_test_nss_db_dir.Get().path(), kTestTPMTokenName);
    593     return !!test_slot_;
    594   }
    595 
    596   void CloseTestNSSDB() {
    597     DCHECK(thread_checker_.CalledOnValidThread());
    598     // NSS is allowed to do IO on the current thread since dispatching
    599     // to a dedicated thread would still have the affect of blocking
    600     // the current thread, due to NSS's internal locking requirements
    601     base::ThreadRestrictions::ScopedAllowIO allow_io;
    602 
    603     if (!test_slot_)
    604       return;
    605     SECStatus status = SECMOD_CloseUserDB(test_slot_);
    606     if (status != SECSuccess)
    607       PLOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError();
    608     PK11_FreeSlot(test_slot_);
    609     test_slot_ = NULL;
    610     ignore_result(g_test_nss_db_dir.Get().Delete());
    611   }
    612 
    613   PK11SlotInfo* GetPublicNSSKeySlot() {
    614     // TODO(mattm): Change to DCHECK when callers have been fixed.
    615     if (!thread_checker_.CalledOnValidThread()) {
    616       DVLOG(1) << "Called on wrong thread.\n"
    617                << base::debug::StackTrace().ToString();
    618     }
    619 
    620     if (test_slot_)
    621       return PK11_ReferenceSlot(test_slot_);
    622     if (software_slot_)
    623       return PK11_ReferenceSlot(software_slot_);
    624     return PK11_GetInternalKeySlot();
    625   }
    626 
    627   PK11SlotInfo* GetPrivateNSSKeySlot() {
    628     // TODO(mattm): Change to DCHECK when callers have been fixed.
    629     if (!thread_checker_.CalledOnValidThread()) {
    630       DVLOG(1) << "Called on wrong thread.\n"
    631                << base::debug::StackTrace().ToString();
    632     }
    633 
    634     if (test_slot_)
    635       return PK11_ReferenceSlot(test_slot_);
    636 
    637 #if defined(OS_CHROMEOS)
    638     if (tpm_token_enabled_for_nss_) {
    639       if (IsTPMTokenReady(base::Closure())) {
    640         return PK11_ReferenceSlot(tpm_slot_);
    641       } else {
    642         // If we were supposed to get the hardware token, but were
    643         // unable to, return NULL rather than fall back to sofware.
    644         return NULL;
    645       }
    646     }
    647 #endif
    648     // If we weren't supposed to enable the TPM for NSS, then return
    649     // the software slot.
    650     if (software_slot_)
    651       return PK11_ReferenceSlot(software_slot_);
    652     return PK11_GetInternalKeySlot();
    653   }
    654 
    655 #if defined(USE_NSS)
    656   base::Lock* write_lock() {
    657     return &write_lock_;
    658   }
    659 #endif  // defined(USE_NSS)
    660 
    661   // This method is used to force NSS to be initialized without a DB.
    662   // Call this method before NSSInitSingleton() is constructed.
    663   static void ForceNoDBInit() {
    664     force_nodb_init_ = true;
    665   }
    666 
    667  private:
    668   friend struct base::DefaultLazyInstanceTraits<NSSInitSingleton>;
    669 
    670   NSSInitSingleton()
    671       : tpm_token_enabled_for_nss_(false),
    672         initializing_tpm_token_(false),
    673         chaps_module_(NULL),
    674         software_slot_(NULL),
    675         test_slot_(NULL),
    676         tpm_slot_(NULL),
    677         root_(NULL),
    678         chromeos_user_logged_in_(false) {
    679     base::TimeTicks start_time = base::TimeTicks::Now();
    680 
    681     // It's safe to construct on any thread, since LazyInstance will prevent any
    682     // other threads from accessing until the constructor is done.
    683     thread_checker_.DetachFromThread();
    684 
    685     DisableAESNIIfNeeded();
    686 
    687     EnsureNSPRInit();
    688 
    689     // We *must* have NSS >= 3.14.3.
    690     COMPILE_ASSERT(
    691         (NSS_VMAJOR == 3 && NSS_VMINOR == 14 && NSS_VPATCH >= 3) ||
    692         (NSS_VMAJOR == 3 && NSS_VMINOR > 14) ||
    693         (NSS_VMAJOR > 3),
    694         nss_version_check_failed);
    695     // Also check the run-time NSS version.
    696     // NSS_VersionCheck is a >= check, not strict equality.
    697     if (!NSS_VersionCheck("3.14.3")) {
    698       LOG(FATAL) << "NSS_VersionCheck(\"3.14.3\") failed. NSS >= 3.14.3 is "
    699                     "required. Please upgrade to the latest NSS, and if you "
    700                     "still get this error, contact your distribution "
    701                     "maintainer.";
    702     }
    703 
    704     SECStatus status = SECFailure;
    705     bool nodb_init = force_nodb_init_;
    706 
    707 #if !defined(USE_NSS)
    708     // Use the system certificate store, so initialize NSS without database.
    709     nodb_init = true;
    710 #endif
    711 
    712     if (nodb_init) {
    713       status = NSS_NoDB_Init(NULL);
    714       if (status != SECSuccess) {
    715         CrashOnNSSInitFailure();
    716         return;
    717       }
    718 #if defined(OS_IOS)
    719       root_ = InitDefaultRootCerts();
    720 #endif  // defined(OS_IOS)
    721     } else {
    722 #if defined(USE_NSS)
    723       base::FilePath database_dir = GetInitialConfigDirectory();
    724       if (!database_dir.empty()) {
    725         // This duplicates the work which should have been done in
    726         // EarlySetupForNSSInit. However, this function is idempotent so
    727         // there's no harm done.
    728         UseLocalCacheOfNSSDatabaseIfNFS(database_dir);
    729 
    730         // Initialize with a persistent database (likely, ~/.pki/nssdb).
    731         // Use "sql:" which can be shared by multiple processes safely.
    732         std::string nss_config_dir =
    733             base::StringPrintf("sql:%s", database_dir.value().c_str());
    734 #if defined(OS_CHROMEOS)
    735         status = NSS_Init(nss_config_dir.c_str());
    736 #else
    737         status = NSS_InitReadWrite(nss_config_dir.c_str());
    738 #endif
    739         if (status != SECSuccess) {
    740           LOG(ERROR) << "Error initializing NSS with a persistent "
    741                         "database (" << nss_config_dir
    742                      << "): " << GetNSSErrorMessage();
    743         }
    744       }
    745       if (status != SECSuccess) {
    746         VLOG(1) << "Initializing NSS without a persistent database.";
    747         status = NSS_NoDB_Init(NULL);
    748         if (status != SECSuccess) {
    749           CrashOnNSSInitFailure();
    750           return;
    751         }
    752       }
    753 
    754       PK11_SetPasswordFunc(PKCS11PasswordFunc);
    755 
    756       // If we haven't initialized the password for the NSS databases,
    757       // initialize an empty-string password so that we don't need to
    758       // log in.
    759       PK11SlotInfo* slot = PK11_GetInternalKeySlot();
    760       if (slot) {
    761         // PK11_InitPin may write to the keyDB, but no other thread can use NSS
    762         // yet, so we don't need to lock.
    763         if (PK11_NeedUserInit(slot))
    764           PK11_InitPin(slot, NULL, NULL);
    765         PK11_FreeSlot(slot);
    766       }
    767 
    768       root_ = InitDefaultRootCerts();
    769 #endif  // defined(USE_NSS)
    770     }
    771 
    772     // Disable MD5 certificate signatures. (They are disabled by default in
    773     // NSS 3.14.)
    774     NSS_SetAlgorithmPolicy(SEC_OID_MD5, 0, NSS_USE_ALG_IN_CERT_SIGNATURE);
    775     NSS_SetAlgorithmPolicy(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION,
    776                            0, NSS_USE_ALG_IN_CERT_SIGNATURE);
    777 
    778     // The UMA bit is conditionally set for this histogram in
    779     // chrome/common/startup_metric_utils.cc .
    780     HISTOGRAM_CUSTOM_TIMES("Startup.SlowStartupNSSInit",
    781                            base::TimeTicks::Now() - start_time,
    782                            base::TimeDelta::FromMilliseconds(10),
    783                            base::TimeDelta::FromHours(1),
    784                            50);
    785   }
    786 
    787   // NOTE(willchan): We don't actually execute this code since we leak NSS to
    788   // prevent non-joinable threads from using NSS after it's already been shut
    789   // down.
    790   ~NSSInitSingleton() {
    791 #if defined(OS_CHROMEOS)
    792     STLDeleteValues(&chromeos_user_map_);
    793 #endif
    794     if (tpm_slot_) {
    795       PK11_FreeSlot(tpm_slot_);
    796       tpm_slot_ = NULL;
    797     }
    798     if (software_slot_) {
    799       SECMOD_CloseUserDB(software_slot_);
    800       PK11_FreeSlot(software_slot_);
    801       software_slot_ = NULL;
    802     }
    803     CloseTestNSSDB();
    804     if (root_) {
    805       SECMOD_UnloadUserModule(root_);
    806       SECMOD_DestroyModule(root_);
    807       root_ = NULL;
    808     }
    809     if (chaps_module_) {
    810       SECMOD_UnloadUserModule(chaps_module_);
    811       SECMOD_DestroyModule(chaps_module_);
    812       chaps_module_ = NULL;
    813     }
    814 
    815     SECStatus status = NSS_Shutdown();
    816     if (status != SECSuccess) {
    817       // We VLOG(1) because this failure is relatively harmless (leaking, but
    818       // we're shutting down anyway).
    819       VLOG(1) << "NSS_Shutdown failed; see http://crbug.com/4609";
    820     }
    821   }
    822 
    823 #if defined(USE_NSS) || defined(OS_IOS)
    824   // Load nss's built-in root certs.
    825   SECMODModule* InitDefaultRootCerts() {
    826     SECMODModule* root = LoadModule("Root Certs", "libnssckbi.so", NULL);
    827     if (root)
    828       return root;
    829 
    830     // Aw, snap.  Can't find/load root cert shared library.
    831     // This will make it hard to talk to anybody via https.
    832     // TODO(mattm): Re-add the NOTREACHED here when crbug.com/310972 is fixed.
    833     return NULL;
    834   }
    835 
    836   // Load the given module for this NSS session.
    837   static SECMODModule* LoadModule(const char* name,
    838                                   const char* library_path,
    839                                   const char* params) {
    840     std::string modparams = base::StringPrintf(
    841         "name=\"%s\" library=\"%s\" %s",
    842         name, library_path, params ? params : "");
    843 
    844     // Shouldn't need to const_cast here, but SECMOD doesn't properly
    845     // declare input string arguments as const.  Bug
    846     // https://bugzilla.mozilla.org/show_bug.cgi?id=642546 was filed
    847     // on NSS codebase to address this.
    848     SECMODModule* module = SECMOD_LoadUserModule(
    849         const_cast<char*>(modparams.c_str()), NULL, PR_FALSE);
    850     if (!module) {
    851       LOG(ERROR) << "Error loading " << name << " module into NSS: "
    852                  << GetNSSErrorMessage();
    853       return NULL;
    854     }
    855     if (!module->loaded) {
    856       LOG(ERROR) << "After loading " << name << ", loaded==false: "
    857                  << GetNSSErrorMessage();
    858       SECMOD_DestroyModule(module);
    859       return NULL;
    860     }
    861     return module;
    862   }
    863 #endif
    864 
    865   static PK11SlotInfo* OpenUserDB(const base::FilePath& path,
    866                                   const char* description) {
    867     const std::string modspec =
    868         base::StringPrintf("configDir='sql:%s' tokenDescription='%s'",
    869                            path.value().c_str(), description);
    870     PK11SlotInfo* db_slot = SECMOD_OpenUserDB(modspec.c_str());
    871     if (db_slot) {
    872       if (PK11_NeedUserInit(db_slot))
    873         PK11_InitPin(db_slot, NULL, NULL);
    874     }
    875     else {
    876       LOG(ERROR) << "Error opening persistent database (" << modspec
    877                  << "): " << GetNSSErrorMessage();
    878     }
    879     return db_slot;
    880   }
    881 
    882   static void DisableAESNIIfNeeded() {
    883     if (NSS_VersionCheck("3.15") && !NSS_VersionCheck("3.15.4")) {
    884       // Some versions of NSS have a bug that causes AVX instructions to be
    885       // used without testing whether XSAVE is enabled by the operating system.
    886       // In order to work around this, we disable AES-NI in NSS when we find
    887       // that |has_avx()| is false (which includes the XSAVE test). See
    888       // https://bugzilla.mozilla.org/show_bug.cgi?id=940794
    889       base::CPU cpu;
    890 
    891       if (cpu.has_avx_hardware() && !cpu.has_avx()) {
    892         base::Environment::Create()->SetVar("NSS_DISABLE_HW_AES", "1");
    893       }
    894     }
    895   }
    896 
    897   // If this is set to true NSS is forced to be initialized without a DB.
    898   static bool force_nodb_init_;
    899 
    900   bool tpm_token_enabled_for_nss_;
    901   bool initializing_tpm_token_;
    902   typedef std::vector<base::Closure> TPMReadyCallbackList;
    903   TPMReadyCallbackList tpm_ready_callback_list_;
    904   SECMODModule* chaps_module_;
    905   PK11SlotInfo* software_slot_;
    906   PK11SlotInfo* test_slot_;
    907   PK11SlotInfo* tpm_slot_;
    908   SECMODModule* root_;
    909   bool chromeos_user_logged_in_;
    910 #if defined(OS_CHROMEOS)
    911   typedef std::map<std::string, ChromeOSUserData*> ChromeOSUserMap;
    912   ChromeOSUserMap chromeos_user_map_;
    913 #endif
    914 #if defined(USE_NSS)
    915   // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011
    916   // is fixed, we will no longer need the lock.
    917   base::Lock write_lock_;
    918 #endif  // defined(USE_NSS)
    919 
    920   base::ThreadChecker thread_checker_;
    921 };
    922 
    923 // static
    924 bool NSSInitSingleton::force_nodb_init_ = false;
    925 
    926 base::LazyInstance<NSSInitSingleton>::Leaky
    927     g_nss_singleton = LAZY_INSTANCE_INITIALIZER;
    928 }  // namespace
    929 
    930 const char kTestTPMTokenName[] = "Test DB";
    931 
    932 #if defined(USE_NSS)
    933 void EarlySetupForNSSInit() {
    934   base::FilePath database_dir = GetInitialConfigDirectory();
    935   if (!database_dir.empty())
    936     UseLocalCacheOfNSSDatabaseIfNFS(database_dir);
    937 }
    938 #endif
    939 
    940 void EnsureNSPRInit() {
    941   g_nspr_singleton.Get();
    942 }
    943 
    944 void InitNSSSafely() {
    945   // We might fork, but we haven't loaded any security modules.
    946   DisableNSSForkCheck();
    947   // If we're sandboxed, we shouldn't be able to open user security modules,
    948   // but it's more correct to tell NSS to not even try.
    949   // Loading user security modules would have security implications.
    950   ForceNSSNoDBInit();
    951   // Initialize NSS.
    952   EnsureNSSInit();
    953 }
    954 
    955 void EnsureNSSInit() {
    956   // Initializing SSL causes us to do blocking IO.
    957   // Temporarily allow it until we fix
    958   //   http://code.google.com/p/chromium/issues/detail?id=59847
    959   base::ThreadRestrictions::ScopedAllowIO allow_io;
    960   g_nss_singleton.Get();
    961 }
    962 
    963 void ForceNSSNoDBInit() {
    964   NSSInitSingleton::ForceNoDBInit();
    965 }
    966 
    967 void DisableNSSForkCheck() {
    968   scoped_ptr<base::Environment> env(base::Environment::Create());
    969   env->SetVar("NSS_STRICT_NOFORK", "DISABLED");
    970 }
    971 
    972 void LoadNSSLibraries() {
    973   // Some NSS libraries are linked dynamically so load them here.
    974 #if defined(USE_NSS)
    975   // Try to search for multiple directories to load the libraries.
    976   std::vector<base::FilePath> paths;
    977 
    978   // Use relative path to Search PATH for the library files.
    979   paths.push_back(base::FilePath());
    980 
    981   // For Debian derivatives NSS libraries are located here.
    982   paths.push_back(base::FilePath("/usr/lib/nss"));
    983 
    984   // Ubuntu 11.10 (Oneiric) and Debian Wheezy place the libraries here.
    985 #if defined(ARCH_CPU_X86_64)
    986   paths.push_back(base::FilePath("/usr/lib/x86_64-linux-gnu/nss"));
    987 #elif defined(ARCH_CPU_X86)
    988   paths.push_back(base::FilePath("/usr/lib/i386-linux-gnu/nss"));
    989 #elif defined(ARCH_CPU_ARMEL)
    990 #if defined(__ARM_PCS_VFP)
    991   paths.push_back(base::FilePath("/usr/lib/arm-linux-gnueabihf/nss"));
    992 #else
    993   paths.push_back(base::FilePath("/usr/lib/arm-linux-gnueabi/nss"));
    994 #endif  // defined(__ARM_PCS_VFP)
    995 #elif defined(ARCH_CPU_MIPSEL)
    996   paths.push_back(base::FilePath("/usr/lib/mipsel-linux-gnu/nss"));
    997 #endif  // defined(ARCH_CPU_X86_64)
    998 
    999   // A list of library files to load.
   1000   std::vector<std::string> libs;
   1001   libs.push_back("libsoftokn3.so");
   1002   libs.push_back("libfreebl3.so");
   1003 
   1004   // For each combination of library file and path, check for existence and
   1005   // then load.
   1006   size_t loaded = 0;
   1007   for (size_t i = 0; i < libs.size(); ++i) {
   1008     for (size_t j = 0; j < paths.size(); ++j) {
   1009       base::FilePath path = paths[j].Append(libs[i]);
   1010       base::NativeLibrary lib = base::LoadNativeLibrary(path, NULL);
   1011       if (lib) {
   1012         ++loaded;
   1013         break;
   1014       }
   1015     }
   1016   }
   1017 
   1018   if (loaded == libs.size()) {
   1019     VLOG(3) << "NSS libraries loaded.";
   1020   } else {
   1021     LOG(ERROR) << "Failed to load NSS libraries.";
   1022   }
   1023 #endif  // defined(USE_NSS)
   1024 }
   1025 
   1026 bool CheckNSSVersion(const char* version) {
   1027   return !!NSS_VersionCheck(version);
   1028 }
   1029 
   1030 #if defined(USE_NSS)
   1031 ScopedTestNSSDB::ScopedTestNSSDB()
   1032   : is_open_(g_nss_singleton.Get().OpenTestNSSDB()) {
   1033 }
   1034 
   1035 ScopedTestNSSDB::~ScopedTestNSSDB() {
   1036   // Don't close when NSS is < 3.15.1, because it would require an additional
   1037   // sleep for 1 second after closing the database, due to
   1038   // http://bugzil.la/875601.
   1039   if (NSS_VersionCheck("3.15.1")) {
   1040     g_nss_singleton.Get().CloseTestNSSDB();
   1041   }
   1042 }
   1043 
   1044 base::Lock* GetNSSWriteLock() {
   1045   return g_nss_singleton.Get().write_lock();
   1046 }
   1047 
   1048 AutoNSSWriteLock::AutoNSSWriteLock() : lock_(GetNSSWriteLock()) {
   1049   // May be NULL if the lock is not needed in our version of NSS.
   1050   if (lock_)
   1051     lock_->Acquire();
   1052 }
   1053 
   1054 AutoNSSWriteLock::~AutoNSSWriteLock() {
   1055   if (lock_) {
   1056     lock_->AssertAcquired();
   1057     lock_->Release();
   1058   }
   1059 }
   1060 
   1061 AutoSECMODListReadLock::AutoSECMODListReadLock()
   1062       : lock_(SECMOD_GetDefaultModuleListLock()) {
   1063     SECMOD_GetReadLock(lock_);
   1064   }
   1065 
   1066 AutoSECMODListReadLock::~AutoSECMODListReadLock() {
   1067   SECMOD_ReleaseReadLock(lock_);
   1068 }
   1069 
   1070 #endif  // defined(USE_NSS)
   1071 
   1072 #if defined(OS_CHROMEOS)
   1073 void OpenPersistentNSSDB() {
   1074   g_nss_singleton.Get().OpenPersistentNSSDB();
   1075 }
   1076 
   1077 void EnableTPMTokenForNSS() {
   1078   g_nss_singleton.Get().EnableTPMTokenForNSS();
   1079 }
   1080 
   1081 bool IsTPMTokenEnabledForNSS() {
   1082   return g_nss_singleton.Get().IsTPMTokenEnabledForNSS();
   1083 }
   1084 
   1085 bool IsTPMTokenReady(const base::Closure& callback) {
   1086   return g_nss_singleton.Get().IsTPMTokenReady(callback);
   1087 }
   1088 
   1089 void InitializeTPMToken(int token_slot_id,
   1090                         const base::Callback<void(bool)>& callback) {
   1091   g_nss_singleton.Get().InitializeTPMToken(token_slot_id, callback);
   1092 }
   1093 
   1094 ScopedTestNSSChromeOSUser::ScopedTestNSSChromeOSUser(
   1095     const std::string& username_hash)
   1096     : username_hash_(username_hash), constructed_successfully_(false) {
   1097   if (!temp_dir_.CreateUniqueTempDir())
   1098     return;
   1099   constructed_successfully_ =
   1100       InitializeNSSForChromeOSUser(username_hash,
   1101                                    username_hash,
   1102                                    false /* is_primary_user */,
   1103                                    temp_dir_.path());
   1104 }
   1105 
   1106 ScopedTestNSSChromeOSUser::~ScopedTestNSSChromeOSUser() {
   1107   if (constructed_successfully_)
   1108     g_nss_singleton.Get().CloseTestChromeOSUser(username_hash_);
   1109 }
   1110 
   1111 void ScopedTestNSSChromeOSUser::FinishInit() {
   1112   InitializePrivateSoftwareSlotForChromeOSUser(username_hash_);
   1113 }
   1114 
   1115 bool InitializeNSSForChromeOSUser(
   1116     const std::string& email,
   1117     const std::string& username_hash,
   1118     bool is_primary_user,
   1119     const base::FilePath& path) {
   1120   return g_nss_singleton.Get().InitializeNSSForChromeOSUser(
   1121       email, username_hash, is_primary_user, path);
   1122 }
   1123 void InitializeTPMForChromeOSUser(
   1124     const std::string& username_hash,
   1125     CK_SLOT_ID slot_id) {
   1126   g_nss_singleton.Get().InitializeTPMForChromeOSUser(username_hash, slot_id);
   1127 }
   1128 void InitializePrivateSoftwareSlotForChromeOSUser(
   1129     const std::string& username_hash) {
   1130   g_nss_singleton.Get().InitializePrivateSoftwareSlotForChromeOSUser(
   1131       username_hash);
   1132 }
   1133 ScopedPK11Slot GetPublicSlotForChromeOSUser(const std::string& username_hash) {
   1134   return g_nss_singleton.Get().GetPublicSlotForChromeOSUser(username_hash);
   1135 }
   1136 ScopedPK11Slot GetPrivateSlotForChromeOSUser(
   1137     const std::string& username_hash,
   1138     const base::Callback<void(ScopedPK11Slot)>& callback) {
   1139   return g_nss_singleton.Get().GetPrivateSlotForChromeOSUser(username_hash,
   1140                                                              callback);
   1141 }
   1142 #endif  // defined(OS_CHROMEOS)
   1143 
   1144 base::Time PRTimeToBaseTime(PRTime prtime) {
   1145   return base::Time::FromInternalValue(
   1146       prtime + base::Time::UnixEpoch().ToInternalValue());
   1147 }
   1148 
   1149 PRTime BaseTimeToPRTime(base::Time time) {
   1150   return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue();
   1151 }
   1152 
   1153 PK11SlotInfo* GetPublicNSSKeySlot() {
   1154   return g_nss_singleton.Get().GetPublicNSSKeySlot();
   1155 }
   1156 
   1157 PK11SlotInfo* GetPrivateNSSKeySlot() {
   1158   return g_nss_singleton.Get().GetPrivateNSSKeySlot();
   1159 }
   1160 
   1161 }  // namespace crypto
   1162