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/cros/cryptohome_library.h"
6
7#include "base/command_line.h"
8#include "base/hash_tables.h"
9#include "base/message_loop.h"
10#include "chrome/browser/chromeos/cros/cros_library.h"
11#include "chrome/common/chrome_switches.h"
12#include "content/browser/browser_thread.h"
13
14namespace chromeos {
15
16// This class handles the interaction with the ChromeOS cryptohome library APIs.
17class CryptohomeLibraryImpl : public CryptohomeLibrary {
18 public:
19  CryptohomeLibraryImpl() {
20    if (CrosLibrary::Get()->EnsureLoaded())
21      Init();
22  }
23  virtual ~CryptohomeLibraryImpl() {}
24
25  bool CheckKey(const std::string& user_email, const std::string& passhash) {
26    return chromeos::CryptohomeCheckKey(user_email.c_str(), passhash.c_str());
27  }
28
29  bool AsyncCheckKey(const std::string& user_email,
30                     const std::string& passhash,
31                     Delegate* d) {
32    return CacheCallback(
33        chromeos::CryptohomeAsyncCheckKey(user_email.c_str(), passhash.c_str()),
34        d,
35        "Couldn't initiate async check of user's key.");
36  }
37
38  bool MigrateKey(const std::string& user_email,
39                  const std::string& old_hash,
40                  const std::string& new_hash) {
41    return chromeos::CryptohomeMigrateKey(user_email.c_str(),
42                                          old_hash.c_str(),
43                                          new_hash.c_str());
44  }
45
46  bool AsyncMigrateKey(const std::string& user_email,
47                       const std::string& old_hash,
48                       const std::string& new_hash,
49                       Delegate* d) {
50    return CacheCallback(
51        chromeos::CryptohomeAsyncMigrateKey(user_email.c_str(),
52                                            old_hash.c_str(),
53                                            new_hash.c_str()),
54        d,
55        "Couldn't initiate aync migration of user's key");
56  }
57
58  bool Mount(const std::string& user_email,
59             const std::string& passhash,
60             int* error_code) {
61    return chromeos::CryptohomeMountAllowFail(user_email.c_str(),
62                                              passhash.c_str(),
63                                              error_code);
64  }
65
66  bool AsyncMount(const std::string& user_email,
67                  const std::string& passhash,
68                  const bool create_if_missing,
69                  Delegate* d) {
70    return CacheCallback(
71        chromeos::CryptohomeAsyncMountSafe(user_email.c_str(),
72                                           passhash.c_str(),
73                                           create_if_missing,
74                                           false,
75                                           NULL),
76        d,
77        "Couldn't initiate async mount of cryptohome.");
78  }
79
80  bool MountForBwsi(int* error_code) {
81    return chromeos::CryptohomeMountGuest(error_code);
82  }
83
84  bool AsyncMountForBwsi(Delegate* d) {
85    return CacheCallback(chromeos::CryptohomeAsyncMountGuest(),
86                         d,
87                         "Couldn't initiate async mount of cryptohome.");
88  }
89
90  bool Unmount() {
91    return chromeos::CryptohomeUnmount();
92  }
93
94  bool Remove(const std::string& user_email) {
95    return chromeos::CryptohomeRemove(user_email.c_str());
96  }
97
98  bool AsyncRemove(const std::string& user_email, Delegate* d) {
99    return CacheCallback(
100        chromeos::CryptohomeAsyncRemove(user_email.c_str()),
101        d,
102        "Couldn't initiate async removal of cryptohome.");
103  }
104
105  bool IsMounted() {
106    return chromeos::CryptohomeIsMounted();
107  }
108
109  CryptohomeBlob GetSystemSalt() {
110    CryptohomeBlob system_salt;
111    char* salt_buf;
112    int salt_len;
113    bool result = chromeos::CryptohomeGetSystemSaltSafe(&salt_buf, &salt_len);
114    if (result) {
115      system_salt.resize(salt_len);
116      if ((int)system_salt.size() == salt_len) {
117        memcpy(&system_salt[0], static_cast<const void*>(salt_buf),
118               salt_len);
119      } else {
120        system_salt.clear();
121      }
122    }
123    return system_salt;
124  }
125
126  bool AsyncDoAutomaticFreeDiskSpaceControl(Delegate* d) {
127    return CacheCallback(
128        chromeos::CryptohomeAsyncDoAutomaticFreeDiskSpaceControl(),
129        d,
130        "Couldn't do automatic free disk space control.");
131  }
132
133  bool TpmIsReady() {
134    return chromeos::CryptohomeTpmIsReady();
135  }
136
137  bool TpmIsEnabled() {
138    return chromeos::CryptohomeTpmIsEnabled();
139  }
140
141  bool TpmIsOwned() {
142    return chromeos::CryptohomeTpmIsOwned();
143  }
144
145  bool TpmIsBeingOwned() {
146    return chromeos::CryptohomeTpmIsBeingOwned();
147  }
148
149  bool TpmGetPassword(std::string* password) {
150    char *password_buf;
151    bool result = chromeos::CryptohomeTpmGetPasswordSafe(&password_buf);
152    *password = password_buf;
153    chromeos::CryptohomeFreeString(password_buf);
154    return result;
155  }
156
157  void TpmCanAttemptOwnership() {
158    chromeos::CryptohomeTpmCanAttemptOwnership();
159  }
160
161  void TpmClearStoredPassword() {
162    chromeos::CryptohomeTpmClearStoredPassword();
163  }
164
165  bool InstallAttributesGet(const std::string& name, std::string* value) {
166    char* local_value;
167    bool done =
168        chromeos::CryptohomeInstallAttributesGet(name.c_str(), &local_value);
169    if (done) {
170      *value = local_value;
171      chromeos::CryptohomeFreeString(local_value);
172    }
173    return done;
174  }
175
176  bool InstallAttributesSet(const std::string& name, const std::string& value) {
177    return chromeos::CryptohomeInstallAttributesSet(name.c_str(),
178                                                    value.c_str());
179  }
180
181  int InstallAttributesCount() {
182    return chromeos::CryptohomeInstallAttributesCount();
183  }
184
185  bool InstallAttributesFinalize() {
186    return chromeos::CryptohomeInstallAttributesFinalize();
187  }
188
189  bool InstallAttributesIsReady() {
190    return chromeos::CryptohomeInstallAttributesIsReady();
191  }
192
193  bool InstallAttributesIsSecure() {
194    return chromeos::CryptohomeInstallAttributesIsSecure();
195  }
196
197  bool InstallAttributesIsInvalid() {
198    return chromeos::CryptohomeInstallAttributesIsInvalid();
199  }
200
201  bool InstallAttributesIsFirstInstall() {
202    return chromeos::CryptohomeInstallAttributesIsFirstInstall();
203  }
204
205  void Pkcs11GetTpmTokenInfo(std::string* label, std::string* user_pin) {
206    chromeos::CryptohomePkcs11GetTpmTokenInfo(label, user_pin);
207  }
208
209  bool Pkcs11IsTpmTokenReady() {
210    return chromeos::CryptohomePkcs11IsTpmTokenReady();
211  }
212
213 private:
214  static void Handler(const chromeos::CryptohomeAsyncCallStatus& event,
215                      void* cryptohome_library) {
216    CryptohomeLibraryImpl* library =
217        reinterpret_cast<CryptohomeLibraryImpl*>(cryptohome_library);
218    library->Dispatch(event);
219  }
220
221  void Init() {
222    cryptohome_connection_ = chromeos::CryptohomeMonitorSession(&Handler, this);
223  }
224
225  void Dispatch(const chromeos::CryptohomeAsyncCallStatus& event) {
226    const CallbackMap::iterator callback = callback_map_.find(event.async_id);
227    if (callback == callback_map_.end()) {
228      LOG(ERROR) << "Received signal for unknown async_id " << event.async_id;
229      return;
230    }
231    if (callback->second)
232      callback->second->OnComplete(event.return_status, event.return_code);
233    callback_map_.erase(callback);
234  }
235
236  bool CacheCallback(int async_id, Delegate* d, const char* error) {
237    if (async_id == 0) {
238      LOG(ERROR) << error;
239      return false;
240    }
241    VLOG(1) << "Adding handler for " << async_id;
242    callback_map_[async_id] = d;
243    return true;
244  }
245
246  typedef base::hash_map<int, Delegate*> CallbackMap;
247  mutable CallbackMap callback_map_;
248
249  void* cryptohome_connection_;
250
251  DISALLOW_COPY_AND_ASSIGN(CryptohomeLibraryImpl);
252};
253
254class CryptohomeLibraryStubImpl : public CryptohomeLibrary {
255 public:
256  CryptohomeLibraryStubImpl()
257    : locked_(false) {}
258  virtual ~CryptohomeLibraryStubImpl() {}
259
260  bool CheckKey(const std::string& user_email, const std::string& passhash) {
261    return true;
262  }
263
264  bool AsyncCheckKey(const std::string& user_email,
265                     const std::string& passhash,
266                     Delegate* callback) {
267    BrowserThread::PostTask(
268        BrowserThread::UI, FROM_HERE,
269        NewRunnableFunction(&DoStubCallback, callback));
270    return true;
271  }
272
273  bool MigrateKey(const std::string& user_email,
274                  const std::string& old_hash,
275                  const std::string& new_hash) {
276    return true;
277  }
278
279  bool AsyncMigrateKey(const std::string& user_email,
280                       const std::string& old_hash,
281                       const std::string& new_hash,
282                       Delegate* callback) {
283    BrowserThread::PostTask(
284        BrowserThread::UI, FROM_HERE,
285        NewRunnableFunction(&DoStubCallback, callback));
286    return true;
287  }
288
289  bool Mount(const std::string& user_email,
290             const std::string& passhash,
291             int* error_code) {
292    // For testing password change.
293    if (user_email ==
294        CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
295            switches::kLoginUserWithNewPassword)) {
296      *error_code = kCryptohomeMountErrorKeyFailure;
297      return false;
298    }
299
300    return true;
301  }
302
303  bool AsyncMount(const std::string& user_email,
304                  const std::string& passhash,
305                  const bool create_if_missing,
306                  Delegate* callback) {
307    BrowserThread::PostTask(
308        BrowserThread::UI, FROM_HERE,
309        NewRunnableFunction(&DoStubCallback, callback));
310    return true;
311  }
312
313  bool MountForBwsi(int* error_code) {
314    return true;
315  }
316
317  bool AsyncMountForBwsi(Delegate* callback) {
318    BrowserThread::PostTask(
319        BrowserThread::UI, FROM_HERE,
320        NewRunnableFunction(&DoStubCallback, callback));
321    return true;
322  }
323
324  bool Unmount() {
325    return true;
326  }
327
328  bool Remove(const std::string& user_email) {
329    return true;
330  }
331
332  bool AsyncRemove(const std::string& user_email, Delegate* callback) {
333    BrowserThread::PostTask(
334        BrowserThread::UI, FROM_HERE,
335        NewRunnableFunction(&DoStubCallback, callback));
336    return true;
337  }
338
339  bool IsMounted() {
340    return true;
341  }
342
343  CryptohomeBlob GetSystemSalt() {
344    CryptohomeBlob salt = CryptohomeBlob();
345    salt.push_back(0);
346    salt.push_back(0);
347    return salt;
348  }
349
350  bool AsyncDoAutomaticFreeDiskSpaceControl(Delegate* callback) {
351    BrowserThread::PostTask(
352        BrowserThread::UI, FROM_HERE,
353        NewRunnableFunction(&DoStubCallback, callback));
354    return true;
355  }
356
357  // Tpm begin ready after 20-th call.
358  bool TpmIsReady() {
359    static int counter = 0;
360    return ++counter > 20;
361  }
362
363  bool TpmIsEnabled() {
364    return true;
365  }
366
367  bool TpmIsOwned() {
368    return true;
369  }
370
371  bool TpmIsBeingOwned() {
372    return true;
373  }
374
375  bool TpmGetPassword(std::string* password) {
376    *password = "Stub-TPM-password";
377    return true;
378  }
379
380  void TpmCanAttemptOwnership() {}
381
382  void TpmClearStoredPassword() {}
383
384  bool InstallAttributesGet(const std::string& name, std::string* value) {
385    if (install_attrs_.find(name) != install_attrs_.end()) {
386      *value = install_attrs_[name];
387      return true;
388    }
389    return false;
390  }
391
392  bool InstallAttributesSet(const std::string& name, const std::string& value) {
393    install_attrs_[name] = value;
394    return true;
395  }
396
397  int InstallAttributesCount() {
398    return install_attrs_.size();
399  }
400
401  bool InstallAttributesFinalize() {
402    locked_ = true;
403    return true;
404  }
405
406  bool InstallAttributesIsReady() {
407    return true;
408  }
409
410  bool InstallAttributesIsSecure() {
411    return false;
412  }
413
414  bool InstallAttributesIsInvalid() {
415    return false;
416  }
417
418  bool InstallAttributesIsFirstInstall() {
419    return !locked_;
420  }
421
422  void Pkcs11GetTpmTokenInfo(std::string* label,
423                             std::string* user_pin) {
424    *label = "Stub TPM Token";
425    *user_pin = "012345";
426  }
427
428  bool Pkcs11IsTpmTokenReady() { return true; }
429
430 private:
431  static void DoStubCallback(Delegate* callback) {
432    if (callback)
433      callback->OnComplete(true, kCryptohomeMountErrorNone);
434  }
435
436  std::map<std::string, std::string> install_attrs_;
437  bool locked_;
438  DISALLOW_COPY_AND_ASSIGN(CryptohomeLibraryStubImpl);
439};
440
441CryptohomeLibrary::CryptohomeLibrary() {}
442CryptohomeLibrary::~CryptohomeLibrary() {}
443
444// static
445CryptohomeLibrary* CryptohomeLibrary::GetImpl(bool stub) {
446  if (stub)
447    return new CryptohomeLibraryStubImpl();
448  else
449    return new CryptohomeLibraryImpl();
450}
451
452} // namespace chromeos
453