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 "chromeos/dbus/cryptohome/key.pb.h" 9 #include "chromeos/dbus/cryptohome/rpc.pb.h" 10 #include "chromeos/dbus/cryptohome_client.h" 11 #include "chromeos/dbus/dbus_thread_manager.h" 12 13 using chromeos::DBusThreadManager; 14 15 namespace cryptohome { 16 17 namespace { 18 19 HomedirMethods* g_homedir_methods = NULL; 20 21 void FillKeyProtobuf(const KeyDefinition& key_def, Key* key) { 22 key->set_secret(key_def.key); 23 KeyData* data = key->mutable_data(); 24 data->set_label(key_def.label); 25 26 if (key_def.revision > 0) 27 data->set_revision(key_def.revision); 28 29 if (key_def.privileges != 0) { 30 KeyPrivileges* privileges = data->mutable_privileges(); 31 privileges->set_mount(key_def.privileges & PRIV_MOUNT); 32 privileges->set_add(key_def.privileges & PRIV_ADD); 33 privileges->set_remove(key_def.privileges & PRIV_REMOVE); 34 privileges->set_update(key_def.privileges & PRIV_MIGRATE); 35 privileges->set_authorized_update(key_def.privileges & 36 PRIV_AUTHORIZED_UPDATE); 37 } 38 39 if (key_def.encryption_key.empty() && key_def.signature_key.empty()) 40 return; 41 42 KeyAuthorizationData* auth_data = data->add_authorization_data(); 43 auth_data->set_type(KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_HMACSHA256); 44 if (!key_def.encryption_key.empty()) { 45 KeyAuthorizationSecret* secret = auth_data->add_secrets(); 46 secret->mutable_usage()->set_encrypt(true); 47 secret->set_symmetric_key(key_def.encryption_key); 48 } 49 if (!key_def.signature_key.empty()) { 50 KeyAuthorizationSecret* secret = auth_data->add_secrets(); 51 secret->mutable_usage()->set_sign(true); 52 secret->set_symmetric_key(key_def.signature_key); 53 } 54 } 55 56 // Fill identification protobuffer. 57 void FillIdentificationProtobuf(const Identification& id, 58 cryptohome::AccountIdentifier* id_proto) { 59 id_proto->set_email(id.user_id); 60 } 61 62 // Fill authorization protobuffer. 63 void FillAuthorizationProtobuf(const Authorization& auth, 64 cryptohome::AuthorizationRequest* auth_proto) { 65 Key* key = auth_proto->mutable_key(); 66 if (!auth.label.empty()) { 67 key->mutable_data()->set_label(auth.label); 68 } 69 key->set_secret(auth.key); 70 } 71 72 MountError MapError(CryptohomeErrorCode code) { 73 switch (code) { 74 case CRYPTOHOME_ERROR_NOT_SET: 75 return MOUNT_ERROR_NONE; 76 case CRYPTOHOME_ERROR_ACCOUNT_NOT_FOUND: 77 return MOUNT_ERROR_USER_DOES_NOT_EXIST; 78 case CRYPTOHOME_ERROR_NOT_IMPLEMENTED: 79 case CRYPTOHOME_ERROR_MOUNT_FATAL: 80 case CRYPTOHOME_ERROR_KEY_QUOTA_EXCEEDED: 81 case CRYPTOHOME_ERROR_BACKING_STORE_FAILURE: 82 return MOUNT_ERROR_FATAL; 83 case CRYPTOHOME_ERROR_AUTHORIZATION_KEY_NOT_FOUND: 84 case CRYPTOHOME_ERROR_KEY_NOT_FOUND: 85 case CRYPTOHOME_ERROR_AUTHORIZATION_KEY_FAILED: 86 return MOUNT_ERROR_KEY_FAILURE; 87 case CRYPTOHOME_ERROR_TPM_COMM_ERROR: 88 return MOUNT_ERROR_TPM_COMM_ERROR; 89 case CRYPTOHOME_ERROR_TPM_DEFEND_LOCK: 90 return MOUNT_ERROR_TPM_DEFEND_LOCK; 91 case CRYPTOHOME_ERROR_MOUNT_MOUNT_POINT_BUSY: 92 return MOUNT_ERROR_MOUNT_POINT_BUSY; 93 case CRYPTOHOME_ERROR_TPM_NEEDS_REBOOT: 94 return MOUNT_ERROR_TPM_NEEDS_REBOOT; 95 case CRYPTOHOME_ERROR_AUTHORIZATION_KEY_DENIED: 96 case CRYPTOHOME_ERROR_KEY_LABEL_EXISTS: 97 case CRYPTOHOME_ERROR_UPDATE_SIGNATURE_INVALID: 98 return MOUNT_ERROR_KEY_FAILURE; 99 default: 100 NOTREACHED(); 101 return MOUNT_ERROR_FATAL; 102 } 103 } 104 105 // The implementation of HomedirMethods 106 class HomedirMethodsImpl : public HomedirMethods { 107 public: 108 HomedirMethodsImpl() : weak_ptr_factory_(this) {} 109 110 virtual ~HomedirMethodsImpl() {} 111 112 virtual void CheckKeyEx(const Identification& id, 113 const Authorization& auth, 114 const Callback& callback) OVERRIDE { 115 cryptohome::AccountIdentifier id_proto; 116 cryptohome::AuthorizationRequest auth_proto; 117 cryptohome::CheckKeyRequest request; 118 119 FillIdentificationProtobuf(id, &id_proto); 120 FillAuthorizationProtobuf(auth, &auth_proto); 121 122 DBusThreadManager::Get()->GetCryptohomeClient()->CheckKeyEx( 123 id_proto, 124 auth_proto, 125 request, 126 base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback, 127 weak_ptr_factory_.GetWeakPtr(), 128 callback)); 129 } 130 131 virtual void MountEx(const Identification& id, 132 const Authorization& auth, 133 const MountParameters& request, 134 const MountCallback& callback) OVERRIDE { 135 cryptohome::AccountIdentifier id_proto; 136 cryptohome::AuthorizationRequest auth_proto; 137 cryptohome::MountRequest request_proto; 138 139 FillIdentificationProtobuf(id, &id_proto); 140 FillAuthorizationProtobuf(auth, &auth_proto); 141 142 if (request.ephemeral) 143 request_proto.set_require_ephemeral(true); 144 145 if (!request.create_keys.empty()) { 146 CreateRequest* create = request_proto.mutable_create(); 147 for (size_t i = 0; i < request.create_keys.size(); ++i) 148 FillKeyProtobuf(request.create_keys[i], create->add_keys()); 149 } 150 151 DBusThreadManager::Get()->GetCryptohomeClient()->MountEx( 152 id_proto, 153 auth_proto, 154 request_proto, 155 base::Bind(&HomedirMethodsImpl::OnMountExCallback, 156 weak_ptr_factory_.GetWeakPtr(), 157 callback)); 158 } 159 160 virtual void AddKeyEx(const Identification& id, 161 const Authorization& auth, 162 const KeyDefinition& new_key, 163 bool clobber_if_exists, 164 const Callback& callback) OVERRIDE { 165 cryptohome::AccountIdentifier id_proto; 166 cryptohome::AuthorizationRequest auth_proto; 167 cryptohome::AddKeyRequest request; 168 169 FillIdentificationProtobuf(id, &id_proto); 170 FillAuthorizationProtobuf(auth, &auth_proto); 171 FillKeyProtobuf(new_key, request.mutable_key()); 172 request.set_clobber_if_exists(clobber_if_exists); 173 174 DBusThreadManager::Get()->GetCryptohomeClient()->AddKeyEx( 175 id_proto, 176 auth_proto, 177 request, 178 base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback, 179 weak_ptr_factory_.GetWeakPtr(), 180 callback)); 181 } 182 183 virtual void RemoveKeyEx(const Identification& id, 184 const Authorization& auth, 185 const std::string& label, 186 const Callback& callback) OVERRIDE { 187 cryptohome::AccountIdentifier id_proto; 188 cryptohome::AuthorizationRequest auth_proto; 189 cryptohome::RemoveKeyRequest request; 190 191 FillIdentificationProtobuf(id, &id_proto); 192 FillAuthorizationProtobuf(auth, &auth_proto); 193 request.mutable_key()->mutable_data()->set_label(label); 194 195 DBusThreadManager::Get()->GetCryptohomeClient()->RemoveKeyEx( 196 id_proto, 197 auth_proto, 198 request, 199 base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback, 200 weak_ptr_factory_.GetWeakPtr(), 201 callback)); 202 } 203 204 virtual void UpdateKeyEx(const Identification& id, 205 const Authorization& auth, 206 const KeyDefinition& new_key, 207 const std::string& signature, 208 const Callback& callback) OVERRIDE { 209 cryptohome::AccountIdentifier id_proto; 210 cryptohome::AuthorizationRequest auth_proto; 211 cryptohome::UpdateKeyRequest pb_update_key; 212 213 FillIdentificationProtobuf(id, &id_proto); 214 FillAuthorizationProtobuf(auth, &auth_proto); 215 FillKeyProtobuf(new_key, pb_update_key.mutable_changes()); 216 pb_update_key.set_authorization_signature(signature); 217 218 DBusThreadManager::Get()->GetCryptohomeClient()->UpdateKeyEx( 219 id_proto, 220 auth_proto, 221 pb_update_key, 222 base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback, 223 weak_ptr_factory_.GetWeakPtr(), 224 callback)); 225 } 226 227 private: 228 void OnMountExCallback(const MountCallback& callback, 229 chromeos::DBusMethodCallStatus call_status, 230 bool result, 231 const BaseReply& reply) { 232 if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) { 233 callback.Run(false, MOUNT_ERROR_FATAL, std::string()); 234 return; 235 } 236 if (reply.has_error()) { 237 if (reply.error() != CRYPTOHOME_ERROR_NOT_SET) { 238 callback.Run(false, MapError(reply.error()), std::string()); 239 return; 240 } 241 } 242 if (!reply.HasExtension(MountReply::reply)) { 243 callback.Run(false, MOUNT_ERROR_FATAL, std::string()); 244 return; 245 } 246 247 std::string mount_hash; 248 mount_hash = reply.GetExtension(MountReply::reply).sanitized_username(); 249 callback.Run(true, MOUNT_ERROR_NONE, mount_hash); 250 } 251 252 void OnBaseReplyCallback(const Callback& callback, 253 chromeos::DBusMethodCallStatus call_status, 254 bool result, 255 const BaseReply& reply) { 256 if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) { 257 callback.Run(false, MOUNT_ERROR_FATAL); 258 return; 259 } 260 if (reply.has_error()) { 261 if (reply.error() != CRYPTOHOME_ERROR_NOT_SET) { 262 callback.Run(false, MapError(reply.error())); 263 return; 264 } 265 } 266 callback.Run(true, MOUNT_ERROR_NONE); 267 } 268 269 base::WeakPtrFactory<HomedirMethodsImpl> weak_ptr_factory_; 270 271 DISALLOW_COPY_AND_ASSIGN(HomedirMethodsImpl); 272 }; 273 274 } // namespace 275 276 // static 277 void HomedirMethods::Initialize() { 278 if (g_homedir_methods) { 279 LOG(WARNING) << "HomedirMethods was already initialized"; 280 return; 281 } 282 g_homedir_methods = new HomedirMethodsImpl(); 283 VLOG(1) << "HomedirMethods initialized"; 284 } 285 286 // static 287 void HomedirMethods::InitializeForTesting(HomedirMethods* homedir_methods) { 288 if (g_homedir_methods) { 289 LOG(WARNING) << "HomedirMethods was already initialized"; 290 return; 291 } 292 g_homedir_methods = homedir_methods; 293 VLOG(1) << "HomedirMethods initialized"; 294 } 295 296 // static 297 void HomedirMethods::Shutdown() { 298 if (!g_homedir_methods) { 299 LOG(WARNING) << "AsyncMethodCaller::Shutdown() called with NULL manager"; 300 return; 301 } 302 delete g_homedir_methods; 303 g_homedir_methods = NULL; 304 VLOG(1) << "HomedirMethods Shutdown completed"; 305 } 306 307 // static 308 HomedirMethods* HomedirMethods::GetInstance() { return g_homedir_methods; } 309 310 } // namespace cryptohome 311