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