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 21 namespace chromeos { 22 23 FakeCryptohomeClient::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 35 FakeCryptohomeClient::~FakeCryptohomeClient() {} 36 37 void FakeCryptohomeClient::Init(dbus::Bus* bus) { 38 } 39 40 void 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 47 void FakeCryptohomeClient::ResetAsyncCallStatusHandlers() { 48 async_call_status_handler_.Reset(); 49 async_call_status_data_handler_.Reset(); 50 } 51 52 void 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 62 void FakeCryptohomeClient::IsMounted( 63 const BoolDBusMethodCallback& callback) { 64 base::MessageLoop::current()->PostTask( 65 FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true)); 66 } 67 68 bool FakeCryptohomeClient::Unmount(bool* success) { 69 *success = unmount_result_; 70 return true; 71 } 72 73 void FakeCryptohomeClient::AsyncCheckKey( 74 const std::string& username, 75 const std::string& key, 76 const AsyncMethodCallback& callback) { 77 ReturnAsyncMethodResult(callback, false); 78 } 79 80 void 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 88 void FakeCryptohomeClient::AsyncRemove( 89 const std::string& username, 90 const AsyncMethodCallback& callback) { 91 ReturnAsyncMethodResult(callback, false); 92 } 93 94 void 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 101 void 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 112 std::string FakeCryptohomeClient::BlockingGetSanitizedUsername( 113 const std::string& username) { 114 return GetStubSanitizedUsername(username); 115 } 116 117 void FakeCryptohomeClient::AsyncMount(const std::string& username, 118 const std::string& key, 119 int flags, 120 const AsyncMethodCallback& callback) { 121 ReturnAsyncMethodResult(callback, false); 122 } 123 124 void 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 132 void FakeCryptohomeClient::AsyncMountGuest( 133 const AsyncMethodCallback& callback) { 134 ReturnAsyncMethodResult(callback, false); 135 } 136 137 void FakeCryptohomeClient::AsyncMountPublic( 138 const std::string& public_mount_id, 139 int flags, 140 const AsyncMethodCallback& callback) { 141 ReturnAsyncMethodResult(callback, false); 142 } 143 144 void FakeCryptohomeClient::TpmIsReady( 145 const BoolDBusMethodCallback& callback) { 146 base::MessageLoop::current()->PostTask( 147 FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true)); 148 } 149 150 void FakeCryptohomeClient::TpmIsEnabled( 151 const BoolDBusMethodCallback& callback) { 152 base::MessageLoop::current()->PostTask( 153 FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true)); 154 } 155 156 bool FakeCryptohomeClient::CallTpmIsEnabledAndBlock(bool* enabled) { 157 *enabled = true; 158 return true; 159 } 160 161 void 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 170 void FakeCryptohomeClient::TpmIsOwned( 171 const BoolDBusMethodCallback& callback) { 172 base::MessageLoop::current()->PostTask( 173 FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true)); 174 } 175 176 bool FakeCryptohomeClient::CallTpmIsOwnedAndBlock(bool* owned) { 177 *owned = true; 178 return true; 179 } 180 181 void FakeCryptohomeClient::TpmIsBeingOwned( 182 const BoolDBusMethodCallback& callback) { 183 base::MessageLoop::current()->PostTask( 184 FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true)); 185 } 186 187 bool FakeCryptohomeClient::CallTpmIsBeingOwnedAndBlock(bool* owning) { 188 *owning = true; 189 return true; 190 } 191 192 void FakeCryptohomeClient::TpmCanAttemptOwnership( 193 const VoidDBusMethodCallback& callback) { 194 base::MessageLoop::current()->PostTask( 195 FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS)); 196 } 197 198 void FakeCryptohomeClient::TpmClearStoredPassword( 199 const VoidDBusMethodCallback& callback) { 200 base::MessageLoop::current()->PostTask( 201 FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS)); 202 } 203 204 bool FakeCryptohomeClient::CallTpmClearStoredPasswordAndBlock() { 205 return true; 206 } 207 208 void FakeCryptohomeClient::Pkcs11IsTpmTokenReady( 209 const BoolDBusMethodCallback& callback) { 210 base::MessageLoop::current()->PostTask( 211 FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true)); 212 } 213 214 void 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 228 void FakeCryptohomeClient::Pkcs11GetTpmTokenInfoForUser( 229 const std::string& username, 230 const Pkcs11GetTpmTokenInfoCallback& callback) { 231 Pkcs11GetTpmTokenInfo(callback); 232 } 233 234 bool 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 247 bool 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 256 bool 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 316 void FakeCryptohomeClient::InstallAttributesIsReady( 317 const BoolDBusMethodCallback& callback) { 318 base::MessageLoop::current()->PostTask( 319 FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true)); 320 } 321 322 bool FakeCryptohomeClient::InstallAttributesIsInvalid(bool* is_invalid) { 323 *is_invalid = false; 324 return true; 325 } 326 327 bool FakeCryptohomeClient::InstallAttributesIsFirstInstall( 328 bool* is_first_install) { 329 *is_first_install = !locked_; 330 return true; 331 } 332 333 void FakeCryptohomeClient::TpmAttestationIsPrepared( 334 const BoolDBusMethodCallback& callback) { 335 base::MessageLoop::current()->PostTask( 336 FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true)); 337 } 338 339 void FakeCryptohomeClient::TpmAttestationIsEnrolled( 340 const BoolDBusMethodCallback& callback) { 341 base::MessageLoop::current()->PostTask( 342 FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true)); 343 } 344 345 void FakeCryptohomeClient::AsyncTpmAttestationCreateEnrollRequest( 346 chromeos::attestation::PrivacyCAType pca_type, 347 const AsyncMethodCallback& callback) { 348 ReturnAsyncMethodResult(callback, true); 349 } 350 351 void FakeCryptohomeClient::AsyncTpmAttestationEnroll( 352 chromeos::attestation::PrivacyCAType pca_type, 353 const std::string& pca_response, 354 const AsyncMethodCallback& callback) { 355 ReturnAsyncMethodResult(callback, false); 356 } 357 358 void 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 367 void 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 376 void 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 385 void 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 395 void 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 405 void 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 413 void 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 425 void 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 434 void 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 444 void 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 454 void 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 463 void 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 473 void 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 482 void 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 494 void 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 503 void 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 512 void 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 521 void 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 531 void FakeCryptohomeClient::SetBootAttribute( 532 const cryptohome::SetBootAttributeRequest& request, 533 const ProtobufMethodCallback& callback) { 534 cryptohome::BaseReply reply; 535 ReturnProtobufMethodCallback(reply, callback); 536 } 537 538 void FakeCryptohomeClient::FlushAndSignBootAttributes( 539 const cryptohome::FlushAndSignBootAttributesRequest& request, 540 const ProtobufMethodCallback& callback) { 541 cryptohome::BaseReply reply; 542 ReturnProtobufMethodCallback(reply, callback); 543 } 544 545 void 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 556 std::vector<uint8> FakeCryptohomeClient::GetStubSystemSalt() { 557 const char kStubSystemSalt[] = "stub_system_salt"; 558 return std::vector<uint8>(kStubSystemSalt, 559 kStubSystemSalt + arraysize(kStubSystemSalt) - 1); 560 } 561 562 void 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 573 void 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 584 void 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