summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui/crypto_module_password_dialog_nss.cc
blob: d0b1357dc2c5379033ecbd48e4c91f56555fc6fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// Copyright (c) 2011 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/ui/crypto_module_password_dialog.h"

#include <pk11pub.h>

#include "base/logging.h"
#include "chrome/browser/browser_thread.h"
#include "net/base/crypto_module.h"
#include "net/base/x509_certificate.h"

namespace {

// Basically an asynchronous implementation of NSS's PK11_DoPassword.
// Note: This currently handles only the simple case.  See the TODOs in
// GotPassword for what is yet unimplemented.
class SlotUnlocker {
 public:
  SlotUnlocker(net::CryptoModule* module,
               browser::CryptoModulePasswordReason reason,
               const std::string& host,
               Callback0::Type* callback);

  void Start();

 private:
  void GotPassword(const char* password);
  void Done();

  scoped_refptr<net::CryptoModule> module_;
  browser::CryptoModulePasswordReason reason_;
  std::string host_;
  Callback0::Type* callback_;
  PRBool retry_;
};

SlotUnlocker::SlotUnlocker(net::CryptoModule* module,
                           browser::CryptoModulePasswordReason reason,
                           const std::string& host,
                           Callback0::Type* callback)
    : module_(module),
      reason_(reason),
      host_(host),
      callback_(callback),
      retry_(PR_FALSE) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}

void SlotUnlocker::Start() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  ShowCryptoModulePasswordDialog(
      module_->GetTokenName(),
      retry_,
      reason_,
      host_,
      NewCallback(this, &SlotUnlocker::GotPassword));
}

void SlotUnlocker::GotPassword(const char* password) {
  // TODO(mattm): PK11_DoPassword has something about PK11_Global.verifyPass.
  // Do we need it?
  // http://mxr.mozilla.org/mozilla/source/security/nss/lib/pk11wrap/pk11auth.c#577

  if (!password) {
    // User cancelled entering password.  Oh well.
    Done();
    return;
  }

  // TODO(mattm): handle protectedAuthPath
  SECStatus rv = PK11_CheckUserPassword(module_->os_module_handle(),
                                        password);
  if (rv == SECWouldBlock) {
    // Incorrect password.  Try again.
    retry_ = PR_TRUE;
    Start();
    return;
  }

  // TODO(mattm): PK11_DoPassword calls nssTrustDomain_UpdateCachedTokenCerts on
  // non-friendly slots.  How important is that?

  // Correct password (SECSuccess) or too many attempts/other failure
  // (SECFailure).  Either way we're done.
  Done();
}

void SlotUnlocker::Done() {
  callback_->Run();
  delete this;
}

}  // namespace

namespace browser {

void UnlockSlotIfNecessary(net::CryptoModule* module,
                           browser::CryptoModulePasswordReason reason,
                           const std::string& host,
                           Callback0::Type* callback) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  // The wincx arg is unused since we don't call PK11_SetIsLoggedInFunc.
  if (PK11_NeedLogin(module->os_module_handle()) &&
      !PK11_IsLoggedIn(module->os_module_handle(), NULL /* wincx */)) {
    (new SlotUnlocker(module, reason, host, callback))->Start();
  } else {
    callback->Run();
  }
}

void UnlockCertSlotIfNecessary(net::X509Certificate* cert,
                               browser::CryptoModulePasswordReason reason,
                               const std::string& host,
                               Callback0::Type* callback) {
  scoped_refptr<net::CryptoModule> module(net::CryptoModule::CreateFromHandle(
      cert->os_cert_handle()->slot));
  UnlockSlotIfNecessary(module.get(), reason, host, callback);
}

}  // namespace browser