fake_cryptohome_client.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1// Copyright 2013 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 "chromeos/dbus/fake_cryptohome_client.h"
6
7#include "base/bind.h"
8#include "base/files/file_util.h"
9#include "base/location.h"
10#include "base/message_loop/message_loop.h"
11#include "base/path_service.h"
12#include "base/threading/thread_restrictions.h"
13#include "chromeos/chromeos_paths.h"
14#include "chromeos/dbus/cryptohome/key.pb.h"
15#include "chromeos/dbus/cryptohome/rpc.pb.h"
16#include "third_party/cros_system_api/dbus/service_constants.h"
17#include "third_party/protobuf/src/google/protobuf/io/coded_stream.h"
18#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream.h"
19#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.h"
20
21namespace chromeos {
22
23FakeCryptohomeClient::FakeCryptohomeClient()
24    : service_is_available_(true),
25      async_call_id_(1),
26      tpm_is_ready_counter_(0),
27      unmount_result_(true),
28      system_salt_(GetStubSystemSalt()),
29      weak_ptr_factory_(this) {
30  base::FilePath cache_path;
31  locked_ = PathService::Get(chromeos::FILE_INSTALL_ATTRIBUTES, &cache_path) &&
32            base::PathExists(cache_path);
33}
34
35FakeCryptohomeClient::~FakeCryptohomeClient() {}
36
37void FakeCryptohomeClient::Init(dbus::Bus* bus) {
38}
39
40void FakeCryptohomeClient::SetAsyncCallStatusHandlers(
41    const AsyncCallStatusHandler& handler,
42    const AsyncCallStatusWithDataHandler& data_handler) {
43  async_call_status_handler_ = handler;
44  async_call_status_data_handler_ = data_handler;
45}
46
47void FakeCryptohomeClient::ResetAsyncCallStatusHandlers() {
48  async_call_status_handler_.Reset();
49  async_call_status_data_handler_.Reset();
50}
51
52void FakeCryptohomeClient::WaitForServiceToBeAvailable(
53    const WaitForServiceToBeAvailableCallback& callback) {
54  if (service_is_available_) {
55    base::MessageLoop::current()->PostTask(FROM_HERE,
56                                           base::Bind(callback, true));
57  } else {
58    pending_wait_for_service_to_be_available_callbacks_.push_back(callback);
59  }
60}
61
62void FakeCryptohomeClient::IsMounted(
63    const BoolDBusMethodCallback& callback) {
64  base::MessageLoop::current()->PostTask(
65      FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true));
66}
67
68bool FakeCryptohomeClient::Unmount(bool* success) {
69  *success = unmount_result_;
70  return true;
71}
72
73void FakeCryptohomeClient::AsyncCheckKey(
74    const std::string& username,
75    const std::string& key,
76    const AsyncMethodCallback& callback) {
77  ReturnAsyncMethodResult(callback, false);
78}
79
80void FakeCryptohomeClient::AsyncMigrateKey(
81    const std::string& username,
82    const std::string& from_key,
83    const std::string& to_key,
84    const AsyncMethodCallback& callback) {
85  ReturnAsyncMethodResult(callback, false);
86}
87
88void FakeCryptohomeClient::AsyncRemove(
89    const std::string& username,
90    const AsyncMethodCallback& callback) {
91  ReturnAsyncMethodResult(callback, false);
92}
93
94void FakeCryptohomeClient::GetSystemSalt(
95    const GetSystemSaltCallback& callback) {
96  base::MessageLoop::current()->PostTask(
97      FROM_HERE,
98      base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, system_salt_));
99}
100
101void FakeCryptohomeClient::GetSanitizedUsername(
102    const std::string& username,
103    const StringDBusMethodCallback& callback) {
104  // Even for stub implementation we have to return different values so that
105  // multi-profiles would work.
106  std::string sanitized_username = GetStubSanitizedUsername(username);
107  base::MessageLoop::current()->PostTask(
108      FROM_HERE,
109      base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, sanitized_username));
110}
111
112std::string FakeCryptohomeClient::BlockingGetSanitizedUsername(
113    const std::string& username) {
114  return GetStubSanitizedUsername(username);
115}
116
117void FakeCryptohomeClient::AsyncMount(const std::string& username,
118                                          const std::string& key,
119                                          int flags,
120                                          const AsyncMethodCallback& callback) {
121  ReturnAsyncMethodResult(callback, false);
122}
123
124void FakeCryptohomeClient::AsyncAddKey(
125    const std::string& username,
126    const std::string& key,
127    const std::string& new_key,
128    const AsyncMethodCallback& callback) {
129  ReturnAsyncMethodResult(callback, false);
130}
131
132void FakeCryptohomeClient::AsyncMountGuest(
133    const AsyncMethodCallback& callback) {
134  ReturnAsyncMethodResult(callback, false);
135}
136
137void FakeCryptohomeClient::AsyncMountPublic(
138    const std::string& public_mount_id,
139    int flags,
140    const AsyncMethodCallback& callback) {
141  ReturnAsyncMethodResult(callback, false);
142}
143
144void FakeCryptohomeClient::TpmIsReady(
145    const BoolDBusMethodCallback& callback) {
146  base::MessageLoop::current()->PostTask(
147      FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true));
148}
149
150void FakeCryptohomeClient::TpmIsEnabled(
151    const BoolDBusMethodCallback& callback) {
152  base::MessageLoop::current()->PostTask(
153      FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true));
154}
155
156bool FakeCryptohomeClient::CallTpmIsEnabledAndBlock(bool* enabled) {
157  *enabled = true;
158  return true;
159}
160
161void FakeCryptohomeClient::TpmGetPassword(
162    const StringDBusMethodCallback& callback) {
163  const char kStubTpmPassword[] = "Stub-TPM-password";
164  base::MessageLoop::current()->PostTask(
165      FROM_HERE,
166      base::Bind(callback, DBUS_METHOD_CALL_SUCCESS,
167                 std::string(kStubTpmPassword)));
168}
169
170void FakeCryptohomeClient::TpmIsOwned(
171    const BoolDBusMethodCallback& callback) {
172  base::MessageLoop::current()->PostTask(
173      FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true));
174}
175
176bool FakeCryptohomeClient::CallTpmIsOwnedAndBlock(bool* owned) {
177  *owned = true;
178  return true;
179}
180
181void FakeCryptohomeClient::TpmIsBeingOwned(
182    const BoolDBusMethodCallback& callback) {
183  base::MessageLoop::current()->PostTask(
184      FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true));
185}
186
187bool FakeCryptohomeClient::CallTpmIsBeingOwnedAndBlock(bool* owning) {
188  *owning = true;
189  return true;
190}
191
192void FakeCryptohomeClient::TpmCanAttemptOwnership(
193    const VoidDBusMethodCallback& callback) {
194  base::MessageLoop::current()->PostTask(
195      FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS));
196}
197
198void FakeCryptohomeClient::TpmClearStoredPassword(
199    const VoidDBusMethodCallback& callback) {
200  base::MessageLoop::current()->PostTask(
201      FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS));
202}
203
204bool FakeCryptohomeClient::CallTpmClearStoredPasswordAndBlock() {
205  return true;
206}
207
208void FakeCryptohomeClient::Pkcs11IsTpmTokenReady(
209    const BoolDBusMethodCallback& callback) {
210  base::MessageLoop::current()->PostTask(
211      FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true));
212}
213
214void FakeCryptohomeClient::Pkcs11GetTpmTokenInfo(
215    const Pkcs11GetTpmTokenInfoCallback& callback) {
216  const char kStubTPMTokenName[] = "StubTPMTokenName";
217  const char kStubUserPin[] = "012345";
218  const int kStubSlot = 0;
219  base::MessageLoop::current()->PostTask(
220      FROM_HERE,
221      base::Bind(callback,
222                 DBUS_METHOD_CALL_SUCCESS,
223                 std::string(kStubTPMTokenName),
224                 std::string(kStubUserPin),
225                 kStubSlot));
226}
227
228void FakeCryptohomeClient::Pkcs11GetTpmTokenInfoForUser(
229    const std::string& username,
230    const Pkcs11GetTpmTokenInfoCallback& callback) {
231  Pkcs11GetTpmTokenInfo(callback);
232}
233
234bool FakeCryptohomeClient::InstallAttributesGet(const std::string& name,
235                                                    std::vector<uint8>* value,
236                                                    bool* successful) {
237  if (install_attrs_.find(name) != install_attrs_.end()) {
238    *value = install_attrs_[name];
239    *successful = true;
240  } else {
241    value->clear();
242    *successful = false;
243  }
244  return true;
245}
246
247bool FakeCryptohomeClient::InstallAttributesSet(
248    const std::string& name,
249    const std::vector<uint8>& value,
250    bool* successful) {
251  install_attrs_[name] = value;
252  *successful = true;
253  return true;
254}
255
256bool FakeCryptohomeClient::InstallAttributesFinalize(bool* successful) {
257  locked_ = true;
258  *successful = true;
259
260  // Persist the install attributes so that they can be reloaded if the
261  // browser is restarted. This is used for ease of development when device
262  // enrollment is required.
263  // The cryptohome::SerializedInstallAttributes protobuf lives in
264  // chrome/browser/chromeos, so it can't be used directly here; use the
265  // low-level protobuf API instead to just write the name-value pairs.
266  // The cache file is read by EnterpriseInstallAttributes::ReadCacheFile.
267  base::FilePath cache_path;
268  if (!PathService::Get(chromeos::FILE_INSTALL_ATTRIBUTES, &cache_path))
269    return false;
270
271  std::string result;
272  {
273    // |result| can be used only after the StringOutputStream goes out of
274    // scope.
275    google::protobuf::io::StringOutputStream result_stream(&result);
276    google::protobuf::io::CodedOutputStream result_output(&result_stream);
277
278    // These tags encode a variable-length value on the wire, which can be
279    // used to encode strings, bytes and messages. We only needs constants
280    // for tag numbers 1 and 2 (see install_attributes.proto).
281    const int kVarLengthTag1 = (1 << 3) | 0x2;
282    const int kVarLengthTag2 = (2 << 3) | 0x2;
283
284    typedef std::map<std::string, std::vector<uint8> >::const_iterator Iter;
285    for (Iter it = install_attrs_.begin(); it != install_attrs_.end(); ++it) {
286      std::string attr;
287      {
288        google::protobuf::io::StringOutputStream attr_stream(&attr);
289        google::protobuf::io::CodedOutputStream attr_output(&attr_stream);
290
291        attr_output.WriteVarint32(kVarLengthTag1);
292        attr_output.WriteVarint32(it->first.size());
293        attr_output.WriteString(it->first);
294        attr_output.WriteVarint32(kVarLengthTag2);
295        attr_output.WriteVarint32(it->second.size());
296        attr_output.WriteRaw(it->second.data(), it->second.size());
297      }
298
299      // Two CodedOutputStreams are needed because inner messages must be
300      // prefixed by their total length, which can't be easily computed before
301      // writing their tags and values.
302      result_output.WriteVarint32(kVarLengthTag2);
303      result_output.WriteVarint32(attr.size());
304      result_output.WriteRaw(attr.data(), attr.size());
305    }
306  }
307
308  // The real implementation does a blocking wait on the dbus call; the fake
309  // implementation must have this file written before returning.
310  base::ThreadRestrictions::ScopedAllowIO allow_io;
311  base::WriteFile(cache_path, result.data(), result.size());
312
313  return true;
314}
315
316void FakeCryptohomeClient::InstallAttributesIsReady(
317    const BoolDBusMethodCallback& callback) {
318  base::MessageLoop::current()->PostTask(
319      FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true));
320}
321
322bool FakeCryptohomeClient::InstallAttributesIsInvalid(bool* is_invalid) {
323  *is_invalid = false;
324  return true;
325}
326
327bool FakeCryptohomeClient::InstallAttributesIsFirstInstall(
328    bool* is_first_install) {
329  *is_first_install = !locked_;
330  return true;
331}
332
333void FakeCryptohomeClient::TpmAttestationIsPrepared(
334    const BoolDBusMethodCallback& callback) {
335  base::MessageLoop::current()->PostTask(
336      FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true));
337}
338
339void FakeCryptohomeClient::TpmAttestationIsEnrolled(
340    const BoolDBusMethodCallback& callback) {
341  base::MessageLoop::current()->PostTask(
342      FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true));
343}
344
345void FakeCryptohomeClient::AsyncTpmAttestationCreateEnrollRequest(
346    chromeos::attestation::PrivacyCAType pca_type,
347    const AsyncMethodCallback& callback) {
348  ReturnAsyncMethodResult(callback, true);
349}
350
351void FakeCryptohomeClient::AsyncTpmAttestationEnroll(
352    chromeos::attestation::PrivacyCAType pca_type,
353    const std::string& pca_response,
354    const AsyncMethodCallback& callback) {
355  ReturnAsyncMethodResult(callback, false);
356}
357
358void FakeCryptohomeClient::AsyncTpmAttestationCreateCertRequest(
359    chromeos::attestation::PrivacyCAType pca_type,
360    attestation::AttestationCertificateProfile certificate_profile,
361    const std::string& user_id,
362    const std::string& request_origin,
363    const AsyncMethodCallback& callback) {
364  ReturnAsyncMethodResult(callback, true);
365}
366
367void FakeCryptohomeClient::AsyncTpmAttestationFinishCertRequest(
368    const std::string& pca_response,
369    attestation::AttestationKeyType key_type,
370    const std::string& user_id,
371    const std::string& key_name,
372    const AsyncMethodCallback& callback) {
373  ReturnAsyncMethodResult(callback, true);
374}
375
376void FakeCryptohomeClient::TpmAttestationDoesKeyExist(
377    attestation::AttestationKeyType key_type,
378    const std::string& user_id,
379    const std::string& key_name,
380    const BoolDBusMethodCallback& callback) {
381  base::MessageLoop::current()->PostTask(
382      FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, false));
383}
384
385void FakeCryptohomeClient::TpmAttestationGetCertificate(
386    attestation::AttestationKeyType key_type,
387    const std::string& user_id,
388    const std::string& key_name,
389    const DataMethodCallback& callback) {
390  base::MessageLoop::current()->PostTask(
391      FROM_HERE,
392      base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, false, std::string()));
393}
394
395void FakeCryptohomeClient::TpmAttestationGetPublicKey(
396    attestation::AttestationKeyType key_type,
397    const std::string& user_id,
398    const std::string& key_name,
399    const DataMethodCallback& callback) {
400  base::MessageLoop::current()->PostTask(
401      FROM_HERE,
402      base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, false, std::string()));
403}
404
405void FakeCryptohomeClient::TpmAttestationRegisterKey(
406    attestation::AttestationKeyType key_type,
407    const std::string& user_id,
408    const std::string& key_name,
409    const AsyncMethodCallback& callback) {
410  ReturnAsyncMethodResult(callback, true);
411}
412
413void FakeCryptohomeClient::TpmAttestationSignEnterpriseChallenge(
414    attestation::AttestationKeyType key_type,
415    const std::string& user_id,
416    const std::string& key_name,
417    const std::string& domain,
418    const std::string& device_id,
419    attestation::AttestationChallengeOptions options,
420    const std::string& challenge,
421    const AsyncMethodCallback& callback) {
422  ReturnAsyncMethodResult(callback, true);
423}
424
425void FakeCryptohomeClient::TpmAttestationSignSimpleChallenge(
426    attestation::AttestationKeyType key_type,
427    const std::string& user_id,
428    const std::string& key_name,
429    const std::string& challenge,
430    const AsyncMethodCallback& callback) {
431  ReturnAsyncMethodResult(callback, true);
432}
433
434void FakeCryptohomeClient::TpmAttestationGetKeyPayload(
435    attestation::AttestationKeyType key_type,
436    const std::string& user_id,
437    const std::string& key_name,
438    const DataMethodCallback& callback) {
439  base::MessageLoop::current()->PostTask(
440      FROM_HERE,
441      base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, false, std::string()));
442}
443
444void FakeCryptohomeClient::TpmAttestationSetKeyPayload(
445    attestation::AttestationKeyType key_type,
446    const std::string& user_id,
447    const std::string& key_name,
448    const std::string& payload,
449    const BoolDBusMethodCallback& callback) {
450  base::MessageLoop::current()->PostTask(
451      FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, false));
452}
453
454void FakeCryptohomeClient::TpmAttestationDeleteKeys(
455    attestation::AttestationKeyType key_type,
456    const std::string& user_id,
457    const std::string& key_prefix,
458    const BoolDBusMethodCallback& callback) {
459  base::MessageLoop::current()->PostTask(
460      FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, false));
461}
462
463void FakeCryptohomeClient::GetKeyDataEx(
464    const cryptohome::AccountIdentifier& id,
465    const cryptohome::AuthorizationRequest& auth,
466    const cryptohome::GetKeyDataRequest& request,
467    const ProtobufMethodCallback& callback) {
468  cryptohome::BaseReply reply;
469  reply.MutableExtension(cryptohome::GetKeyDataReply::reply);
470  ReturnProtobufMethodCallback(reply, callback);
471}
472
473void FakeCryptohomeClient::CheckKeyEx(
474    const cryptohome::AccountIdentifier& id,
475    const cryptohome::AuthorizationRequest& auth,
476    const cryptohome::CheckKeyRequest& request,
477    const ProtobufMethodCallback& callback) {
478  cryptohome::BaseReply reply;
479  ReturnProtobufMethodCallback(reply, callback);
480}
481
482void FakeCryptohomeClient::MountEx(
483    const cryptohome::AccountIdentifier& id,
484    const cryptohome::AuthorizationRequest& auth,
485    const cryptohome::MountRequest& request,
486    const ProtobufMethodCallback& callback) {
487  cryptohome::BaseReply reply;
488  cryptohome::MountReply* mount =
489      reply.MutableExtension(cryptohome::MountReply::reply);
490  mount->set_sanitized_username(GetStubSanitizedUsername(id.email()));
491  ReturnProtobufMethodCallback(reply, callback);
492}
493
494void FakeCryptohomeClient::AddKeyEx(
495    const cryptohome::AccountIdentifier& id,
496    const cryptohome::AuthorizationRequest& auth,
497    const cryptohome::AddKeyRequest& request,
498    const ProtobufMethodCallback& callback) {
499  cryptohome::BaseReply reply;
500  ReturnProtobufMethodCallback(reply, callback);
501}
502
503void FakeCryptohomeClient::RemoveKeyEx(
504    const cryptohome::AccountIdentifier& id,
505    const cryptohome::AuthorizationRequest& auth,
506    const cryptohome::RemoveKeyRequest& request,
507    const ProtobufMethodCallback& callback) {
508  cryptohome::BaseReply reply;
509  ReturnProtobufMethodCallback(reply, callback);
510}
511
512void FakeCryptohomeClient::UpdateKeyEx(
513    const cryptohome::AccountIdentifier& id,
514    const cryptohome::AuthorizationRequest& auth,
515    const cryptohome::UpdateKeyRequest& request,
516    const ProtobufMethodCallback& callback) {
517  cryptohome::BaseReply reply;
518  ReturnProtobufMethodCallback(reply, callback);
519}
520
521void FakeCryptohomeClient::GetBootAttribute(
522    const cryptohome::GetBootAttributeRequest& request,
523    const ProtobufMethodCallback& callback) {
524  cryptohome::BaseReply reply;
525  cryptohome::GetBootAttributeReply* attr_reply =
526      reply.MutableExtension(cryptohome::GetBootAttributeReply::reply);
527  attr_reply->set_value("");
528  ReturnProtobufMethodCallback(reply, callback);
529}
530
531void FakeCryptohomeClient::SetBootAttribute(
532    const cryptohome::SetBootAttributeRequest& request,
533    const ProtobufMethodCallback& callback) {
534  cryptohome::BaseReply reply;
535  ReturnProtobufMethodCallback(reply, callback);
536}
537
538void FakeCryptohomeClient::FlushAndSignBootAttributes(
539    const cryptohome::FlushAndSignBootAttributesRequest& request,
540    const ProtobufMethodCallback& callback) {
541  cryptohome::BaseReply reply;
542  ReturnProtobufMethodCallback(reply, callback);
543}
544
545void FakeCryptohomeClient::SetServiceIsAvailable(bool is_available) {
546  service_is_available_ = is_available;
547  if (is_available) {
548    std::vector<WaitForServiceToBeAvailableCallback> callbacks;
549    callbacks.swap(pending_wait_for_service_to_be_available_callbacks_);
550    for (size_t i = 0; i < callbacks.size(); ++i)
551      callbacks[i].Run(is_available);
552  }
553}
554
555// static
556std::vector<uint8> FakeCryptohomeClient::GetStubSystemSalt() {
557  const char kStubSystemSalt[] = "stub_system_salt";
558  return std::vector<uint8>(kStubSystemSalt,
559                            kStubSystemSalt + arraysize(kStubSystemSalt) - 1);
560}
561
562void FakeCryptohomeClient::ReturnProtobufMethodCallback(
563    const cryptohome::BaseReply& reply,
564    const ProtobufMethodCallback& callback) {
565  base::MessageLoop::current()->PostTask(
566      FROM_HERE,
567      base::Bind(callback,
568                 DBUS_METHOD_CALL_SUCCESS,
569                 true,
570                 reply));
571}
572
573void FakeCryptohomeClient::ReturnAsyncMethodResult(
574    const AsyncMethodCallback& callback,
575    bool returns_data) {
576  base::MessageLoop::current()->PostTask(
577      FROM_HERE,
578      base::Bind(&FakeCryptohomeClient::ReturnAsyncMethodResultInternal,
579                 weak_ptr_factory_.GetWeakPtr(),
580                 callback,
581                 returns_data));
582}
583
584void FakeCryptohomeClient::ReturnAsyncMethodResultInternal(
585    const AsyncMethodCallback& callback,
586    bool returns_data) {
587  callback.Run(async_call_id_);
588  if (!returns_data && !async_call_status_handler_.is_null()) {
589    base::MessageLoop::current()->PostTask(
590        FROM_HERE,
591        base::Bind(async_call_status_handler_,
592                   async_call_id_,
593                   true,
594                   cryptohome::MOUNT_ERROR_NONE));
595  } else if (returns_data && !async_call_status_data_handler_.is_null()) {
596    base::MessageLoop::current()->PostTask(
597        FROM_HERE,
598        base::Bind(async_call_status_data_handler_,
599                   async_call_id_,
600                   true,
601                   std::string()));
602  }
603  ++async_call_id_;
604}
605
606}  // namespace chromeos
607