15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/ui/crypto_module_delegate_nss.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/basictypes.h"
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/bind.h"
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/net/nss_context.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using content::BrowserThread;
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ChromeNSSCryptoModuleDelegate::ChromeNSSCryptoModuleDelegate(
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    chrome::CryptoModulePasswordReason reason,
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const net::HostPortPair& server)
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : reason_(reason),
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      server_(server),
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      event_(false, false),
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      cancelled_(false) {}
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ChromeNSSCryptoModuleDelegate::~ChromeNSSCryptoModuleDelegate() {}
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ChromeNSSCryptoModuleDelegate::InitializeSlot(
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    content::ResourceContext* context,
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::Closure& initialization_complete_callback) {
27e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(!slot_);
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::Callback<void(crypto::ScopedPK11Slot)> get_slot_callback;
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!initialization_complete_callback.is_null())
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    get_slot_callback = base::Bind(&ChromeNSSCryptoModuleDelegate::DidGetSlot,
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   // Caller is responsible for keeping |this|
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   // alive until the callback is run.
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   base::Unretained(this),
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   initialization_complete_callback);
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  slot_ = GetPrivateNSSKeySlotForResourceContext(context, get_slot_callback);
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return slot_.get() != NULL;
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// TODO(mattm): allow choosing which slot to generate and store the key.
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)crypto::ScopedPK11Slot ChromeNSSCryptoModuleDelegate::RequestSlot() {
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return slot_.Pass();
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string ChromeNSSCryptoModuleDelegate::RequestPassword(
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& slot_name,
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool retry,
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool* cancelled) {
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!event_.IsSignaled());
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  event_.Reset();
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (BrowserThread::PostTask(
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          BrowserThread::UI,
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          FROM_HERE,
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::Bind(&ChromeNSSCryptoModuleDelegate::ShowDialog,
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     // This method blocks on |event_| until the task completes,
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     // so there's no need to ref-count.
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     base::Unretained(this),
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     slot_name,
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     retry))) {
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    event_.Wait();
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  *cancelled = cancelled_;
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return password_;
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChromeNSSCryptoModuleDelegate::ShowDialog(const std::string& slot_name,
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               bool retry) {
70e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ShowCryptoModulePasswordDialog(
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      slot_name,
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      retry,
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      reason_,
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      server_.host(),
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL,  // TODO(mattm): Supply parent window.
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&ChromeNSSCryptoModuleDelegate::GotPassword,
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 // RequestPassword is blocked on |event_| until GotPassword is
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 // called, so there's no need to ref-count.
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Unretained(this)));
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChromeNSSCryptoModuleDelegate::GotPassword(const std::string& password) {
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!password.empty())
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    password_ = password;
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    cancelled_ = true;
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  event_.Signal();
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChromeNSSCryptoModuleDelegate::DidGetSlot(const base::Closure& callback,
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               crypto::ScopedPK11Slot slot) {
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(!slot_);
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  slot_ = slot.Pass();
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  callback.Run();
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)crypto::CryptoModuleBlockingPasswordDelegate*
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)CreateCryptoModuleBlockingPasswordDelegate(
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    chrome::CryptoModulePasswordReason reason,
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const net::HostPortPair& server) {
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Returns a ChromeNSSCryptoModuleDelegate without calling InitializeSlot.
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Since it is only being used as a CreateCryptoModuleBlockingDialogDelegate,
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // initializing the slot handle is unnecessary.
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return new ChromeNSSCryptoModuleDelegate(reason, server);
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
107