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