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/chromeos/login/owner_manager.h"
6
7#include <string>
8#include <vector>
9
10#include "base/file_path.h"
11#include "base/file_util.h"
12#include "chrome/browser/browser_process.h"
13#include "chrome/browser/chromeos/boot_times_loader.h"
14#include "chrome/browser/chromeos/login/signed_settings_temp_storage.h"
15#include "content/browser/browser_thread.h"
16#include "content/common/notification_service.h"
17#include "content/common/notification_type.h"
18
19namespace chromeos {
20
21OwnerManager::OwnerManager()
22    : private_key_(NULL),
23      public_key_(0),
24      utils_(OwnerKeyUtils::Create()) {
25}
26
27OwnerManager::~OwnerManager() {}
28
29void OwnerManager::UpdateOwnerKey(const BrowserThread::ID thread_id,
30                                  const std::vector<uint8>& key,
31                                  KeyUpdateDelegate* d) {
32  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
33
34  public_key_ = key;
35
36  BrowserThread::PostTask(
37      thread_id, FROM_HERE,
38      NewRunnableMethod(this, &OwnerManager::CallKeyUpdateDelegate, d));
39}
40
41void OwnerManager::LoadOwnerKey() {
42  BootTimesLoader::Get()->AddLoginTimeMarker("LoadOwnerKeyStart", false);
43  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
44  VLOG(1) << "Loading owner key";
45  NotificationType result = NotificationType::OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED;
46
47  // If |public_key_| isn't empty, we already have the key, so don't
48  // try to import again.
49  if (public_key_.empty() &&
50      !utils_->ImportPublicKey(utils_->GetOwnerKeyFilePath(), &public_key_)) {
51    result = NotificationType::OWNER_KEY_FETCH_ATTEMPT_FAILED;
52  }
53
54  // Whether we loaded the public key or not, send a notification indicating
55  // that we're done with this attempt.
56  BrowserThread::PostTask(
57      BrowserThread::UI, FROM_HERE,
58      NewRunnableMethod(this,
59                        &OwnerManager::SendNotification,
60                        result,
61                        NotificationService::NoDetails()));
62}
63
64bool OwnerManager::EnsurePublicKey() {
65  if (public_key_.empty())
66    LoadOwnerKey();
67
68  return !public_key_.empty();
69}
70
71bool OwnerManager::EnsurePrivateKey() {
72  if (!EnsurePublicKey())
73    return false;
74
75  if (!private_key_.get())
76    private_key_.reset(utils_->FindPrivateKey(public_key_));
77
78  return private_key_.get() != NULL;
79}
80
81void OwnerManager::Sign(const BrowserThread::ID thread_id,
82                        const std::string& data,
83                        Delegate* d) {
84  BootTimesLoader::Get()->AddLoginTimeMarker("SignStart", false);
85  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
86
87  // If it's not the case that we can get both keys...
88  if (!(EnsurePublicKey() && EnsurePrivateKey())) {
89    BrowserThread::PostTask(
90        thread_id, FROM_HERE,
91        NewRunnableMethod(this,
92                          &OwnerManager::CallDelegate,
93                          d, KEY_UNAVAILABLE, std::vector<uint8>()));
94    BootTimesLoader::Get()->AddLoginTimeMarker("SignEnd", false);
95    return;
96  }
97
98  VLOG(1) << "Starting signing attempt";
99  KeyOpCode return_code = SUCCESS;
100  std::vector<uint8> signature;
101  if (!utils_->Sign(data, &signature, private_key_.get())) {
102    return_code = OPERATION_FAILED;
103  }
104
105  BrowserThread::PostTask(
106      thread_id, FROM_HERE,
107      NewRunnableMethod(this,
108                        &OwnerManager::CallDelegate,
109                        d, return_code, signature));
110  BootTimesLoader::Get()->AddLoginTimeMarker("SignEnd", false);
111}
112
113void OwnerManager::Verify(const BrowserThread::ID thread_id,
114                          const std::string& data,
115                          const std::vector<uint8>& signature,
116                          Delegate* d) {
117  BootTimesLoader::Get()->AddLoginTimeMarker("VerifyStart", false);
118  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
119
120  if (!EnsurePublicKey()) {
121    BrowserThread::PostTask(
122        thread_id, FROM_HERE,
123        NewRunnableMethod(this,
124                          &OwnerManager::CallDelegate,
125                          d, KEY_UNAVAILABLE, std::vector<uint8>()));
126    BootTimesLoader::Get()->AddLoginTimeMarker("VerifyEnd", false);
127    return;
128  }
129
130  VLOG(1) << "Starting verify attempt";
131  KeyOpCode return_code = SUCCESS;
132  if (!utils_->Verify(data, signature, public_key_)) {
133    return_code = OPERATION_FAILED;
134  }
135  BrowserThread::PostTask(
136      thread_id, FROM_HERE,
137      NewRunnableMethod(this,
138                        &OwnerManager::CallDelegate,
139                        d, return_code, std::vector<uint8>()));
140  BootTimesLoader::Get()->AddLoginTimeMarker("VerifyEnd", false);
141}
142
143void OwnerManager::SendNotification(NotificationType type,
144                                    const NotificationDetails& details) {
145  NotificationService::current()->Notify(
146      type,
147      NotificationService::AllSources(),
148      details);
149}
150
151}  // namespace chromeos
152