Home | History | Annotate | Download | only in ui
      1 // Copyright (c) 2011 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 "chrome/browser/ui/crypto_module_password_dialog.h"
      6 
      7 #include <pk11pub.h>
      8 
      9 #include "base/logging.h"
     10 #include "content/browser/browser_thread.h"
     11 #include "net/base/crypto_module.h"
     12 #include "net/base/x509_certificate.h"
     13 
     14 #if defined(OS_CHROMEOS)
     15 #include "crypto/nss_util.h"
     16 #endif
     17 
     18 namespace {
     19 
     20 bool ShouldShowDialog(const net::CryptoModule* module) {
     21   // The wincx arg is unused since we don't call PK11_SetIsLoggedInFunc.
     22   return (PK11_NeedLogin(module->os_module_handle()) &&
     23           !PK11_IsLoggedIn(module->os_module_handle(), NULL /* wincx */));
     24 }
     25 
     26 // Basically an asynchronous implementation of NSS's PK11_DoPassword.
     27 // Note: This currently handles only the simple case.  See the TODOs in
     28 // GotPassword for what is yet unimplemented.
     29 class SlotUnlocker {
     30  public:
     31   SlotUnlocker(const net::CryptoModuleList& modules,
     32                browser::CryptoModulePasswordReason reason,
     33                const std::string& host,
     34                Callback0::Type* callback);
     35 
     36   void Start();
     37 
     38  private:
     39   void GotPassword(const char* password);
     40   void Done();
     41 
     42   size_t current_;
     43   net::CryptoModuleList modules_;
     44   browser::CryptoModulePasswordReason reason_;
     45   std::string host_;
     46   Callback0::Type* callback_;
     47   PRBool retry_;
     48 };
     49 
     50 SlotUnlocker::SlotUnlocker(const net::CryptoModuleList& modules,
     51                            browser::CryptoModulePasswordReason reason,
     52                            const std::string& host,
     53                            Callback0::Type* callback)
     54     : current_(0),
     55       modules_(modules),
     56       reason_(reason),
     57       host_(host),
     58       callback_(callback),
     59       retry_(PR_FALSE) {
     60   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     61 }
     62 
     63 void SlotUnlocker::Start() {
     64   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     65 
     66   for (; current_ < modules_.size(); ++current_) {
     67     if (ShouldShowDialog(modules_[current_].get())) {
     68 #if defined(OS_CHROMEOS)
     69       if (crypto::IsTPMTokenReady()) {
     70         std::string token_name;
     71         std::string user_pin;
     72         crypto::GetTPMTokenInfo(&token_name, &user_pin);
     73         if (modules_[current_]->GetTokenName() == token_name) {
     74           // The user PIN is a well known secret on this machine, and
     75           // the user didn't set it, so we need to fetch the value and
     76           // supply it for them here.
     77           GotPassword(user_pin.c_str());
     78           return;
     79         }
     80       }
     81 #endif
     82       ShowCryptoModulePasswordDialog(
     83           modules_[current_]->GetTokenName(),
     84           retry_,
     85           reason_,
     86           host_,
     87           NewCallback(this, &SlotUnlocker::GotPassword));
     88       return;
     89     }
     90   }
     91   Done();
     92 }
     93 
     94 void SlotUnlocker::GotPassword(const char* password) {
     95   // TODO(mattm): PK11_DoPassword has something about PK11_Global.verifyPass.
     96   // Do we need it?
     97   // http://mxr.mozilla.org/mozilla/source/security/nss/lib/pk11wrap/pk11auth.c#577
     98 
     99   if (!password) {
    100     // User cancelled entering password.  Oh well.
    101     ++current_;
    102     Start();
    103     return;
    104   }
    105 
    106   // TODO(mattm): handle protectedAuthPath
    107   SECStatus rv = PK11_CheckUserPassword(modules_[current_]->os_module_handle(),
    108                                         password);
    109   if (rv == SECWouldBlock) {
    110     // Incorrect password.  Try again.
    111     retry_ = PR_TRUE;
    112     Start();
    113     return;
    114   }
    115 
    116   // TODO(mattm): PK11_DoPassword calls nssTrustDomain_UpdateCachedTokenCerts on
    117   // non-friendly slots.  How important is that?
    118 
    119   // Correct password (SECSuccess) or too many attempts/other failure
    120   // (SECFailure).  Either way we're done with this slot.
    121   ++current_;
    122   Start();
    123 }
    124 
    125 void SlotUnlocker::Done() {
    126   DCHECK_EQ(current_, modules_.size());
    127   callback_->Run();
    128   delete this;
    129 }
    130 
    131 }  // namespace
    132 
    133 namespace browser {
    134 
    135 void UnlockSlotsIfNecessary(const net::CryptoModuleList& modules,
    136                             browser::CryptoModulePasswordReason reason,
    137                             const std::string& host,
    138                             Callback0::Type* callback) {
    139   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    140   for (size_t i = 0; i < modules.size(); ++i) {
    141     if (ShouldShowDialog(modules[i].get())) {
    142       (new SlotUnlocker(modules, reason, host, callback))->Start();
    143       return;
    144     }
    145   }
    146   callback->Run();
    147 }
    148 
    149 void UnlockCertSlotIfNecessary(net::X509Certificate* cert,
    150                                browser::CryptoModulePasswordReason reason,
    151                                const std::string& host,
    152                                Callback0::Type* callback) {
    153   net::CryptoModuleList modules;
    154   modules.push_back(net::CryptoModule::CreateFromHandle(
    155       cert->os_cert_handle()->slot));
    156   UnlockSlotsIfNecessary(modules, reason, host, callback);
    157 }
    158 
    159 }  // namespace browser
    160