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