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#include "chrome/browser/chromeos/login/owner_manager_unittest.h"
7
8#include <string>
9
10#include "base/file_path.h"
11#include "base/file_util.h"
12#include "base/logging.h"
13#include "base/memory/scoped_temp_dir.h"
14#include "crypto/nss_util.h"
15#include "crypto/rsa_private_key.h"
16#include "chrome/browser/chromeos/login/mock_owner_key_utils.h"
17#include "content/browser/browser_thread.h"
18#include "testing/gmock/include/gmock/gmock.h"
19#include "testing/gtest/include/gtest/gtest.h"
20
21using ::crypto::RSAPrivateKey;
22using ::testing::DoAll;
23using ::testing::Eq;
24using ::testing::Invoke;
25using ::testing::Return;
26using ::testing::SetArgumentPointee;
27using ::testing::_;
28
29namespace chromeos {
30
31class OwnerManagerTest : public ::testing::Test {
32 public:
33  OwnerManagerTest()
34      : message_loop_(MessageLoop::TYPE_UI),
35        ui_thread_(BrowserThread::UI, &message_loop_),
36        file_thread_(BrowserThread::FILE),
37        mock_(new MockKeyUtils),
38        injector_(mock_) /* injector_ takes ownership of mock_ */ {
39  }
40  virtual ~OwnerManagerTest() {}
41
42  virtual void SetUp() {
43    crypto::OpenPersistentNSSDB();  // TODO(cmasone): use test DB instead
44    fake_private_key_.reset(RSAPrivateKey::Create(256));
45    ASSERT_TRUE(fake_private_key_->ExportPublicKey(&fake_public_key_));
46
47    // Mimic ownership.
48    ASSERT_TRUE(tmpdir_.CreateUniqueTempDir());
49    ASSERT_TRUE(file_util::CreateTemporaryFileInDir(tmpdir_.path(), &tmpfile_));
50
51    file_thread_.Start();
52    OwnerKeyUtils::set_factory(&injector_);
53  }
54
55  virtual void TearDown() {
56    OwnerKeyUtils::set_factory(NULL);
57  }
58
59  void StartUnowned() {
60    file_util::Delete(tmpfile_, false);
61  }
62
63  void InjectKeys(OwnerManager* manager) {
64    manager->public_key_ = fake_public_key_;
65    manager->private_key_.reset(fake_private_key_.release());
66  }
67
68  ScopedTempDir tmpdir_;
69  FilePath tmpfile_;
70
71  MessageLoop message_loop_;
72  BrowserThread ui_thread_;
73  BrowserThread file_thread_;
74
75  std::vector<uint8> fake_public_key_;
76  scoped_ptr<RSAPrivateKey> fake_private_key_;
77
78  MockKeyUtils* mock_;
79  MockInjector injector_;
80
81};
82
83TEST_F(OwnerManagerTest, UpdateOwnerKey) {
84  scoped_refptr<OwnerManager> manager(new OwnerManager);
85
86  MockKeyUpdateUser delegate;
87  BrowserThread::PostTask(
88      BrowserThread::FILE, FROM_HERE,
89      NewRunnableMethod(manager.get(),
90                        &OwnerManager::UpdateOwnerKey,
91                        BrowserThread::UI,
92                        std::vector<uint8>(),
93                        &delegate));
94  message_loop_.Run();
95}
96
97TEST_F(OwnerManagerTest, LoadOwnerKeyFail) {
98  StartUnowned();
99  MockKeyLoadObserver loader;
100  scoped_refptr<OwnerManager> manager(new OwnerManager);
101
102  EXPECT_CALL(*mock_, GetOwnerKeyFilePath())
103      .WillRepeatedly(Return(tmpfile_));
104  EXPECT_CALL(*mock_, ImportPublicKey(tmpfile_, _))
105      .WillOnce(Return(false))
106      .RetiresOnSaturation();
107
108  BrowserThread::PostTask(
109      BrowserThread::FILE, FROM_HERE,
110      NewRunnableMethod(manager.get(),
111                        &OwnerManager::LoadOwnerKey));
112  message_loop_.Run();
113}
114
115TEST_F(OwnerManagerTest, AlreadyLoadedOwnerKey) {
116  MockKeyLoadObserver loader;
117  loader.ExpectKeyFetchSuccess(true);
118  scoped_refptr<OwnerManager> manager(new OwnerManager);
119
120  EXPECT_CALL(*mock_, GetOwnerKeyFilePath())
121      .WillRepeatedly(Return(tmpfile_));
122
123  InjectKeys(manager.get());
124
125  BrowserThread::PostTask(
126      BrowserThread::FILE, FROM_HERE,
127      NewRunnableMethod(manager.get(),
128                        &OwnerManager::LoadOwnerKey));
129
130  message_loop_.Run();
131}
132
133TEST_F(OwnerManagerTest, LoadOwnerKey) {
134  MockKeyLoadObserver loader;
135  loader.ExpectKeyFetchSuccess(true);
136  scoped_refptr<OwnerManager> manager(new OwnerManager);
137
138  EXPECT_CALL(*mock_, GetOwnerKeyFilePath())
139      .WillRepeatedly(Return(tmpfile_));
140  EXPECT_CALL(*mock_, ImportPublicKey(tmpfile_, _))
141      .WillOnce(DoAll(SetArgumentPointee<1>(fake_public_key_),
142                      Return(true)))
143      .RetiresOnSaturation();
144
145  BrowserThread::PostTask(
146      BrowserThread::FILE, FROM_HERE,
147      NewRunnableMethod(manager.get(),
148                        &OwnerManager::LoadOwnerKey));
149
150  message_loop_.Run();
151}
152
153TEST_F(OwnerManagerTest, GetKeyFailDuringVerify) {
154  StartUnowned();
155  MockKeyLoadObserver loader;
156  loader.ExpectKeyFetchSuccess(false);
157  scoped_refptr<OwnerManager> manager(new OwnerManager);
158
159  EXPECT_CALL(*mock_, GetOwnerKeyFilePath())
160      .WillRepeatedly(Return(tmpfile_));
161  EXPECT_CALL(*mock_, ImportPublicKey(tmpfile_, _))
162      .WillOnce(Return(false))
163      .RetiresOnSaturation();
164
165  MockKeyUser delegate(OwnerManager::KEY_UNAVAILABLE);
166
167  BrowserThread::PostTask(
168      BrowserThread::FILE, FROM_HERE,
169      NewRunnableMethod(manager.get(),
170                        &OwnerManager::Verify,
171                        BrowserThread::UI,
172                        std::string(),
173                        std::vector<uint8>(),
174                        &delegate));
175  message_loop_.Run();
176}
177
178TEST_F(OwnerManagerTest, AlreadyHaveKeysVerify) {
179  scoped_refptr<OwnerManager> manager(new OwnerManager);
180
181  std::string data;
182  std::vector<uint8> sig(0, 2);
183
184  EXPECT_CALL(*mock_, GetOwnerKeyFilePath())
185      .WillRepeatedly(Return(tmpfile_));
186  EXPECT_CALL(*mock_, Verify(Eq(data), Eq(sig), Eq(fake_public_key_)))
187      .WillOnce(Return(true))
188      .RetiresOnSaturation();
189
190  InjectKeys(manager.get());
191  MockKeyUser delegate(OwnerManager::SUCCESS);
192
193  BrowserThread::PostTask(
194      BrowserThread::FILE, FROM_HERE,
195      NewRunnableMethod(manager.get(),
196                        &OwnerManager::Verify,
197                        BrowserThread::UI,
198                        data,
199                        sig,
200                        &delegate));
201  message_loop_.Run();
202}
203
204TEST_F(OwnerManagerTest, GetKeyAndVerify) {
205  MockKeyLoadObserver loader;
206  loader.ExpectKeyFetchSuccess(true);
207  loader.SetQuitOnKeyFetch(false);
208  scoped_refptr<OwnerManager> manager(new OwnerManager);
209
210  std::string data;
211  std::vector<uint8> sig(0, 2);
212
213  EXPECT_CALL(*mock_, GetOwnerKeyFilePath())
214      .WillRepeatedly(Return(tmpfile_));
215  EXPECT_CALL(*mock_, ImportPublicKey(tmpfile_, _))
216      .WillOnce(DoAll(SetArgumentPointee<1>(fake_public_key_),
217                      Return(true)))
218      .RetiresOnSaturation();
219  EXPECT_CALL(*mock_, Verify(Eq(data), Eq(sig), Eq(fake_public_key_)))
220      .WillOnce(Return(true))
221      .RetiresOnSaturation();
222
223  MockKeyUser delegate(OwnerManager::SUCCESS);
224
225  BrowserThread::PostTask(
226      BrowserThread::FILE, FROM_HERE,
227      NewRunnableMethod(manager.get(),
228                        &OwnerManager::Verify,
229                        BrowserThread::UI,
230                        data,
231                        sig,
232                        &delegate));
233  message_loop_.Run();
234}
235
236TEST_F(OwnerManagerTest, AlreadyHaveKeysSign) {
237  scoped_refptr<OwnerManager> manager(new OwnerManager);
238
239  std::string data;
240  std::vector<uint8> sig(0, 2);
241
242  EXPECT_CALL(*mock_, GetOwnerKeyFilePath())
243      .WillRepeatedly(Return(tmpfile_));
244  EXPECT_CALL(*mock_, Sign(Eq(data), _, Eq(fake_private_key_.get())))
245      .WillOnce(DoAll(SetArgumentPointee<1>(sig),
246                      Return(true)))
247      .RetiresOnSaturation();
248
249  InjectKeys(manager.get());
250  MockSigner delegate(OwnerManager::SUCCESS, sig);
251
252  BrowserThread::PostTask(
253      BrowserThread::FILE, FROM_HERE,
254      NewRunnableMethod(manager.get(),
255                        &OwnerManager::Sign,
256                        BrowserThread::UI,
257                        data,
258                        &delegate));
259  message_loop_.Run();
260}
261
262}  // namespace chromeos
263