1 // Copyright 2014 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/cryptohome/homedir_methods.h" 6 7 #include "base/bind.h" 8 #include "base/logging.h" 9 #include "chromeos/dbus/cryptohome/key.pb.h" 10 #include "chromeos/dbus/cryptohome/rpc.pb.h" 11 #include "chromeos/dbus/cryptohome_client.h" 12 #include "chromeos/dbus/dbus_thread_manager.h" 13 14 #if defined(USE_SYSTEM_PROTOBUF) 15 #include <google/protobuf/repeated_field.h> 16 #else 17 #include "third_party/protobuf/src/google/protobuf/repeated_field.h" 18 #endif 19 20 using chromeos::DBusThreadManager; 21 using google::protobuf::RepeatedPtrField; 22 23 namespace cryptohome { 24 25 namespace { 26 27 HomedirMethods* g_homedir_methods = NULL; 28 29 void FillKeyProtobuf(const KeyDefinition& key_def, Key* key) { 30 key->set_secret(key_def.secret); 31 KeyData* data = key->mutable_data(); 32 DCHECK_EQ(KeyDefinition::TYPE_PASSWORD, key_def.type); 33 data->set_type(KeyData::KEY_TYPE_PASSWORD); 34 data->set_label(key_def.label); 35 36 if (key_def.revision > 0) 37 data->set_revision(key_def.revision); 38 39 if (key_def.privileges != 0) { 40 KeyPrivileges* privileges = data->mutable_privileges(); 41 privileges->set_mount(key_def.privileges & PRIV_MOUNT); 42 privileges->set_add(key_def.privileges & PRIV_ADD); 43 privileges->set_remove(key_def.privileges & PRIV_REMOVE); 44 privileges->set_update(key_def.privileges & PRIV_MIGRATE); 45 privileges->set_authorized_update(key_def.privileges & 46 PRIV_AUTHORIZED_UPDATE); 47 } 48 49 for (std::vector<KeyDefinition::AuthorizationData>::const_iterator auth_it = 50 key_def.authorization_data.begin(); 51 auth_it != key_def.authorization_data.end(); ++auth_it) { 52 KeyAuthorizationData* auth_data = data->add_authorization_data(); 53 switch (auth_it->type) { 54 case KeyDefinition::AuthorizationData::TYPE_HMACSHA256: 55 auth_data->set_type( 56 KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_HMACSHA256); 57 break; 58 case KeyDefinition::AuthorizationData::TYPE_AES256CBC_HMACSHA256: 59 auth_data->set_type( 60 KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_AES256CBC_HMACSHA256); 61 break; 62 default: 63 NOTREACHED(); 64 break; 65 } 66 67 for (std::vector<KeyDefinition::AuthorizationData::Secret>::const_iterator 68 secret_it = auth_it->secrets.begin(); 69 secret_it != auth_it->secrets.end(); ++secret_it) { 70 KeyAuthorizationSecret* secret = auth_data->add_secrets(); 71 secret->mutable_usage()->set_encrypt(secret_it->encrypt); 72 secret->mutable_usage()->set_sign(secret_it->sign); 73 if (!secret_it->symmetric_key.empty()) 74 secret->set_symmetric_key(secret_it->symmetric_key); 75 if (!secret_it->public_key.empty()) 76 secret->set_public_key(secret_it->public_key); 77 secret->set_wrapped(secret_it->wrapped); 78 } 79 } 80 81 for (std::vector<KeyDefinition::ProviderData>::const_iterator it = 82 key_def.provider_data.begin(); it != key_def.provider_data.end(); 83 ++it) { 84 KeyProviderData::Entry* entry = 85 data->mutable_provider_data()->add_entry(); 86 entry->set_name(it->name); 87 if (it->number) 88 entry->set_number(*it->number); 89 if (it->bytes) 90 entry->set_bytes(*it->bytes); 91 } 92 } 93 94 // Fill identification protobuffer. 95 void FillIdentificationProtobuf(const Identification& id, 96 cryptohome::AccountIdentifier* id_proto) { 97 id_proto->set_email(id.user_id); 98 } 99 100 // Fill authorization protobuffer. 101 void FillAuthorizationProtobuf(const Authorization& auth, 102 cryptohome::AuthorizationRequest* auth_proto) { 103 Key* key = auth_proto->mutable_key(); 104 if (!auth.label.empty()) { 105 key->mutable_data()->set_label(auth.label); 106 } 107 key->set_secret(auth.key); 108 } 109 110 void ParseAuthorizationDataProtobuf( 111 const KeyAuthorizationData& authorization_data_proto, 112 KeyDefinition::AuthorizationData* authorization_data) { 113 switch (authorization_data_proto.type()) { 114 case KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_HMACSHA256: 115 authorization_data->type = 116 KeyDefinition::AuthorizationData::TYPE_HMACSHA256; 117 break; 118 case KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_AES256CBC_HMACSHA256: 119 authorization_data->type = 120 KeyDefinition::AuthorizationData::TYPE_AES256CBC_HMACSHA256; 121 break; 122 default: 123 NOTREACHED(); 124 return; 125 } 126 127 for (RepeatedPtrField<KeyAuthorizationSecret>::const_iterator it = 128 authorization_data_proto.secrets().begin(); 129 it != authorization_data_proto.secrets().end(); ++it) { 130 authorization_data->secrets.push_back( 131 KeyDefinition::AuthorizationData::Secret(it->usage().encrypt(), 132 it->usage().sign(), 133 it->symmetric_key(), 134 it->public_key(), 135 it->wrapped())); 136 } 137 } 138 139 MountError MapError(CryptohomeErrorCode code) { 140 switch (code) { 141 case CRYPTOHOME_ERROR_NOT_SET: 142 return MOUNT_ERROR_NONE; 143 case CRYPTOHOME_ERROR_ACCOUNT_NOT_FOUND: 144 return MOUNT_ERROR_USER_DOES_NOT_EXIST; 145 case CRYPTOHOME_ERROR_NOT_IMPLEMENTED: 146 case CRYPTOHOME_ERROR_MOUNT_FATAL: 147 case CRYPTOHOME_ERROR_KEY_QUOTA_EXCEEDED: 148 case CRYPTOHOME_ERROR_BACKING_STORE_FAILURE: 149 return MOUNT_ERROR_FATAL; 150 case CRYPTOHOME_ERROR_AUTHORIZATION_KEY_NOT_FOUND: 151 case CRYPTOHOME_ERROR_KEY_NOT_FOUND: 152 case CRYPTOHOME_ERROR_AUTHORIZATION_KEY_FAILED: 153 return MOUNT_ERROR_KEY_FAILURE; 154 case CRYPTOHOME_ERROR_TPM_COMM_ERROR: 155 return MOUNT_ERROR_TPM_COMM_ERROR; 156 case CRYPTOHOME_ERROR_TPM_DEFEND_LOCK: 157 return MOUNT_ERROR_TPM_DEFEND_LOCK; 158 case CRYPTOHOME_ERROR_MOUNT_MOUNT_POINT_BUSY: 159 return MOUNT_ERROR_MOUNT_POINT_BUSY; 160 case CRYPTOHOME_ERROR_TPM_NEEDS_REBOOT: 161 return MOUNT_ERROR_TPM_NEEDS_REBOOT; 162 case CRYPTOHOME_ERROR_AUTHORIZATION_KEY_DENIED: 163 case CRYPTOHOME_ERROR_KEY_LABEL_EXISTS: 164 case CRYPTOHOME_ERROR_UPDATE_SIGNATURE_INVALID: 165 return MOUNT_ERROR_KEY_FAILURE; 166 default: 167 NOTREACHED(); 168 return MOUNT_ERROR_FATAL; 169 } 170 } 171 172 // The implementation of HomedirMethods 173 class HomedirMethodsImpl : public HomedirMethods { 174 public: 175 HomedirMethodsImpl() : weak_ptr_factory_(this) {} 176 177 virtual ~HomedirMethodsImpl() {} 178 179 virtual void GetKeyDataEx(const Identification& id, 180 const std::string& label, 181 const GetKeyDataCallback& callback) OVERRIDE { 182 cryptohome::AccountIdentifier id_proto; 183 cryptohome::AuthorizationRequest kEmptyAuthProto; 184 cryptohome::GetKeyDataRequest request; 185 186 FillIdentificationProtobuf(id, &id_proto); 187 request.mutable_key()->mutable_data()->set_label(label); 188 189 DBusThreadManager::Get()->GetCryptohomeClient()->GetKeyDataEx( 190 id_proto, 191 kEmptyAuthProto, 192 request, 193 base::Bind(&HomedirMethodsImpl::OnGetKeyDataExCallback, 194 weak_ptr_factory_.GetWeakPtr(), 195 callback)); 196 } 197 198 virtual void CheckKeyEx(const Identification& id, 199 const Authorization& auth, 200 const Callback& callback) OVERRIDE { 201 cryptohome::AccountIdentifier id_proto; 202 cryptohome::AuthorizationRequest auth_proto; 203 cryptohome::CheckKeyRequest request; 204 205 FillIdentificationProtobuf(id, &id_proto); 206 FillAuthorizationProtobuf(auth, &auth_proto); 207 208 DBusThreadManager::Get()->GetCryptohomeClient()->CheckKeyEx( 209 id_proto, 210 auth_proto, 211 request, 212 base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback, 213 weak_ptr_factory_.GetWeakPtr(), 214 callback)); 215 } 216 217 virtual void MountEx(const Identification& id, 218 const Authorization& auth, 219 const MountParameters& request, 220 const MountCallback& callback) OVERRIDE { 221 cryptohome::AccountIdentifier id_proto; 222 cryptohome::AuthorizationRequest auth_proto; 223 cryptohome::MountRequest request_proto; 224 225 FillIdentificationProtobuf(id, &id_proto); 226 FillAuthorizationProtobuf(auth, &auth_proto); 227 228 if (request.ephemeral) 229 request_proto.set_require_ephemeral(true); 230 231 if (!request.create_keys.empty()) { 232 CreateRequest* create = request_proto.mutable_create(); 233 for (size_t i = 0; i < request.create_keys.size(); ++i) 234 FillKeyProtobuf(request.create_keys[i], create->add_keys()); 235 } 236 237 DBusThreadManager::Get()->GetCryptohomeClient()->MountEx( 238 id_proto, 239 auth_proto, 240 request_proto, 241 base::Bind(&HomedirMethodsImpl::OnMountExCallback, 242 weak_ptr_factory_.GetWeakPtr(), 243 callback)); 244 } 245 246 virtual void AddKeyEx(const Identification& id, 247 const Authorization& auth, 248 const KeyDefinition& new_key, 249 bool clobber_if_exists, 250 const Callback& callback) OVERRIDE { 251 cryptohome::AccountIdentifier id_proto; 252 cryptohome::AuthorizationRequest auth_proto; 253 cryptohome::AddKeyRequest request; 254 255 FillIdentificationProtobuf(id, &id_proto); 256 FillAuthorizationProtobuf(auth, &auth_proto); 257 FillKeyProtobuf(new_key, request.mutable_key()); 258 request.set_clobber_if_exists(clobber_if_exists); 259 260 DBusThreadManager::Get()->GetCryptohomeClient()->AddKeyEx( 261 id_proto, 262 auth_proto, 263 request, 264 base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback, 265 weak_ptr_factory_.GetWeakPtr(), 266 callback)); 267 } 268 269 virtual void RemoveKeyEx(const Identification& id, 270 const Authorization& auth, 271 const std::string& label, 272 const Callback& callback) OVERRIDE { 273 cryptohome::AccountIdentifier id_proto; 274 cryptohome::AuthorizationRequest auth_proto; 275 cryptohome::RemoveKeyRequest request; 276 277 FillIdentificationProtobuf(id, &id_proto); 278 FillAuthorizationProtobuf(auth, &auth_proto); 279 request.mutable_key()->mutable_data()->set_label(label); 280 281 DBusThreadManager::Get()->GetCryptohomeClient()->RemoveKeyEx( 282 id_proto, 283 auth_proto, 284 request, 285 base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback, 286 weak_ptr_factory_.GetWeakPtr(), 287 callback)); 288 } 289 290 virtual void UpdateKeyEx(const Identification& id, 291 const Authorization& auth, 292 const KeyDefinition& new_key, 293 const std::string& signature, 294 const Callback& callback) OVERRIDE { 295 cryptohome::AccountIdentifier id_proto; 296 cryptohome::AuthorizationRequest auth_proto; 297 cryptohome::UpdateKeyRequest pb_update_key; 298 299 FillIdentificationProtobuf(id, &id_proto); 300 FillAuthorizationProtobuf(auth, &auth_proto); 301 FillKeyProtobuf(new_key, pb_update_key.mutable_changes()); 302 pb_update_key.set_authorization_signature(signature); 303 304 DBusThreadManager::Get()->GetCryptohomeClient()->UpdateKeyEx( 305 id_proto, 306 auth_proto, 307 pb_update_key, 308 base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback, 309 weak_ptr_factory_.GetWeakPtr(), 310 callback)); 311 } 312 313 private: 314 void OnGetKeyDataExCallback(const GetKeyDataCallback& callback, 315 chromeos::DBusMethodCallStatus call_status, 316 bool result, 317 const BaseReply& reply) { 318 if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) { 319 callback.Run(false, MOUNT_ERROR_FATAL, std::vector<KeyDefinition>()); 320 return; 321 } 322 if (reply.has_error()) { 323 if (reply.error() != CRYPTOHOME_ERROR_NOT_SET) { 324 callback.Run(false, 325 MapError(reply.error()), 326 std::vector<KeyDefinition>()); 327 return; 328 } 329 } 330 331 if (!reply.HasExtension(GetKeyDataReply::reply)) { 332 callback.Run(false, MOUNT_ERROR_FATAL, std::vector<KeyDefinition>()); 333 return; 334 } 335 336 // Extract the contents of the |KeyData| protos returned. 337 const RepeatedPtrField<KeyData>& key_data = 338 reply.GetExtension(GetKeyDataReply::reply).key_data(); 339 std::vector<KeyDefinition> key_definitions; 340 for (RepeatedPtrField<KeyData>::const_iterator it = key_data.begin(); 341 it != key_data.end(); ++it) { 342 343 // Extract |type|, |label| and |revision|. 344 DCHECK_EQ(KeyData::KEY_TYPE_PASSWORD, it->type()); 345 key_definitions.push_back(KeyDefinition(std::string() /* secret */, 346 it->label(), 347 0 /* privileges */)); 348 KeyDefinition& key_definition = key_definitions.back(); 349 key_definition.revision = it->revision(); 350 351 // Extract |privileges|. 352 const KeyPrivileges& privileges = it->privileges(); 353 if (privileges.mount()) 354 key_definition.privileges |= PRIV_MOUNT; 355 if (privileges.add()) 356 key_definition.privileges |= PRIV_ADD; 357 if (privileges.remove()) 358 key_definition.privileges |= PRIV_REMOVE; 359 if (privileges.update()) 360 key_definition.privileges |= PRIV_MIGRATE; 361 if (privileges.authorized_update()) 362 key_definition.privileges |= PRIV_AUTHORIZED_UPDATE; 363 364 // Extract |authorization_data|. 365 for (RepeatedPtrField<KeyAuthorizationData>::const_iterator auth_it = 366 it->authorization_data().begin(); 367 auth_it != it->authorization_data().end(); ++auth_it) { 368 key_definition.authorization_data.push_back( 369 KeyDefinition::AuthorizationData()); 370 ParseAuthorizationDataProtobuf( 371 *auth_it, 372 &key_definition.authorization_data.back()); 373 } 374 375 // Extract |provider_data|. 376 for (RepeatedPtrField<KeyProviderData::Entry>::const_iterator 377 provider_data_it = it->provider_data().entry().begin(); 378 provider_data_it != it->provider_data().entry().end(); 379 ++provider_data_it) { 380 // Extract |name|. 381 key_definition.provider_data.push_back( 382 KeyDefinition::ProviderData(provider_data_it->name())); 383 KeyDefinition::ProviderData& provider_data = 384 key_definition.provider_data.back(); 385 386 int data_items = 0; 387 388 // Extract |number|. 389 if (provider_data_it->has_number()) { 390 provider_data.number.reset(new int64(provider_data_it->number())); 391 ++data_items; 392 } 393 394 // Extract |bytes|. 395 if (provider_data_it->has_bytes()) { 396 provider_data.bytes.reset( 397 new std::string(provider_data_it->bytes())); 398 ++data_items; 399 } 400 401 DCHECK_EQ(1, data_items); 402 } 403 } 404 405 callback.Run(true, MOUNT_ERROR_NONE, key_definitions); 406 } 407 408 void OnMountExCallback(const MountCallback& callback, 409 chromeos::DBusMethodCallStatus call_status, 410 bool result, 411 const BaseReply& reply) { 412 if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) { 413 callback.Run(false, MOUNT_ERROR_FATAL, std::string()); 414 return; 415 } 416 if (reply.has_error()) { 417 if (reply.error() != CRYPTOHOME_ERROR_NOT_SET) { 418 callback.Run(false, MapError(reply.error()), std::string()); 419 return; 420 } 421 } 422 if (!reply.HasExtension(MountReply::reply)) { 423 callback.Run(false, MOUNT_ERROR_FATAL, std::string()); 424 return; 425 } 426 427 std::string mount_hash; 428 mount_hash = reply.GetExtension(MountReply::reply).sanitized_username(); 429 callback.Run(true, MOUNT_ERROR_NONE, mount_hash); 430 } 431 432 void OnBaseReplyCallback(const Callback& callback, 433 chromeos::DBusMethodCallStatus call_status, 434 bool result, 435 const BaseReply& reply) { 436 if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) { 437 callback.Run(false, MOUNT_ERROR_FATAL); 438 return; 439 } 440 if (reply.has_error()) { 441 if (reply.error() != CRYPTOHOME_ERROR_NOT_SET) { 442 callback.Run(false, MapError(reply.error())); 443 return; 444 } 445 } 446 callback.Run(true, MOUNT_ERROR_NONE); 447 } 448 449 base::WeakPtrFactory<HomedirMethodsImpl> weak_ptr_factory_; 450 451 DISALLOW_COPY_AND_ASSIGN(HomedirMethodsImpl); 452 }; 453 454 } // namespace 455 456 // static 457 void HomedirMethods::Initialize() { 458 if (g_homedir_methods) { 459 LOG(WARNING) << "HomedirMethods was already initialized"; 460 return; 461 } 462 g_homedir_methods = new HomedirMethodsImpl(); 463 VLOG(1) << "HomedirMethods initialized"; 464 } 465 466 // static 467 void HomedirMethods::InitializeForTesting(HomedirMethods* homedir_methods) { 468 if (g_homedir_methods) { 469 LOG(WARNING) << "HomedirMethods was already initialized"; 470 return; 471 } 472 g_homedir_methods = homedir_methods; 473 VLOG(1) << "HomedirMethods initialized"; 474 } 475 476 // static 477 void HomedirMethods::Shutdown() { 478 if (!g_homedir_methods) { 479 LOG(WARNING) << "AsyncMethodCaller::Shutdown() called with NULL manager"; 480 return; 481 } 482 delete g_homedir_methods; 483 g_homedir_methods = NULL; 484 VLOG(1) << "HomedirMethods Shutdown completed"; 485 } 486 487 // static 488 HomedirMethods* HomedirMethods::GetInstance() { return g_homedir_methods; } 489 490 } // namespace cryptohome 491