Roll src/third_party/WebKit 05e9c31:d6595eb (svn 198725:198727)
[chromium-blink-merge.git] / chromeos / cryptohome / homedir_methods.cc
blob0407e3c24ea9774a8c3aa081049d40d2ae785566
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.
5 #include "chromeos/cryptohome/homedir_methods.h"
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/dbus_thread_manager.h"
12 #include "components/device_event_log/device_event_log.h"
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
20 using chromeos::DBusThreadManager;
21 using google::protobuf::RepeatedPtrField;
23 namespace cryptohome {
25 namespace {
27 HomedirMethods* g_homedir_methods = NULL;
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);
36 if (key_def.revision > 0)
37 data->set_revision(key_def.revision);
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);
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;
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);
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);
94 // Fill identification protobuffer.
95 void FillIdentificationProtobuf(const Identification& id,
96 cryptohome::AccountIdentifier* id_proto) {
97 id_proto->set_email(id.user_id);
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);
107 key->set_secret(auth.key);
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;
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()));
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;
172 // The implementation of HomedirMethods
173 class HomedirMethodsImpl : public HomedirMethods {
174 public:
175 HomedirMethodsImpl() : weak_ptr_factory_(this) {}
177 ~HomedirMethodsImpl() override {}
179 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;
186 FillIdentificationProtobuf(id, &id_proto);
187 request.mutable_key()->mutable_data()->set_label(label);
189 DBusThreadManager::Get()->GetCryptohomeClient()->GetKeyDataEx(
190 id_proto,
191 kEmptyAuthProto,
192 request,
193 base::Bind(&HomedirMethodsImpl::OnGetKeyDataExCallback,
194 weak_ptr_factory_.GetWeakPtr(),
195 callback));
198 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;
205 FillIdentificationProtobuf(id, &id_proto);
206 FillAuthorizationProtobuf(auth, &auth_proto);
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));
217 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;
225 FillIdentificationProtobuf(id, &id_proto);
226 FillAuthorizationProtobuf(auth, &auth_proto);
228 if (request.ephemeral)
229 request_proto.set_require_ephemeral(true);
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());
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));
246 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;
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);
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));
269 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;
277 FillIdentificationProtobuf(id, &id_proto);
278 FillAuthorizationProtobuf(auth, &auth_proto);
279 request.mutable_key()->mutable_data()->set_label(label);
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));
290 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;
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);
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));
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;
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;
331 if (!reply.HasExtension(GetKeyDataReply::reply)) {
332 callback.Run(false, MOUNT_ERROR_FATAL, std::vector<KeyDefinition>());
333 return;
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) {
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();
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;
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());
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();
386 int data_items = 0;
388 // Extract |number|.
389 if (provider_data_it->has_number()) {
390 provider_data.number.reset(new int64(provider_data_it->number()));
391 ++data_items;
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;
401 DCHECK_EQ(1, data_items);
405 callback.Run(true, MOUNT_ERROR_NONE, key_definitions);
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;
416 if (reply.has_error()) {
417 if (reply.error() != CRYPTOHOME_ERROR_NOT_SET) {
418 LOGIN_LOG(ERROR) << "HomedirMethods MountEx error: " << reply.error();
419 callback.Run(false, MapError(reply.error()), std::string());
420 return;
423 if (!reply.HasExtension(MountReply::reply)) {
424 callback.Run(false, MOUNT_ERROR_FATAL, std::string());
425 return;
428 std::string mount_hash;
429 mount_hash = reply.GetExtension(MountReply::reply).sanitized_username();
430 callback.Run(true, MOUNT_ERROR_NONE, mount_hash);
433 void OnBaseReplyCallback(const Callback& callback,
434 chromeos::DBusMethodCallStatus call_status,
435 bool result,
436 const BaseReply& reply) {
437 if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) {
438 callback.Run(false, MOUNT_ERROR_FATAL);
439 return;
441 if (reply.has_error()) {
442 if (reply.error() != CRYPTOHOME_ERROR_NOT_SET) {
443 callback.Run(false, MapError(reply.error()));
444 return;
447 callback.Run(true, MOUNT_ERROR_NONE);
450 base::WeakPtrFactory<HomedirMethodsImpl> weak_ptr_factory_;
452 DISALLOW_COPY_AND_ASSIGN(HomedirMethodsImpl);
455 } // namespace
457 // static
458 void HomedirMethods::Initialize() {
459 if (g_homedir_methods) {
460 LOG(WARNING) << "HomedirMethods was already initialized";
461 return;
463 g_homedir_methods = new HomedirMethodsImpl();
464 VLOG(1) << "HomedirMethods initialized";
467 // static
468 void HomedirMethods::InitializeForTesting(HomedirMethods* homedir_methods) {
469 if (g_homedir_methods) {
470 LOG(WARNING) << "HomedirMethods was already initialized";
471 return;
473 g_homedir_methods = homedir_methods;
474 VLOG(1) << "HomedirMethods initialized";
477 // static
478 void HomedirMethods::Shutdown() {
479 if (!g_homedir_methods) {
480 LOG(WARNING) << "AsyncMethodCaller::Shutdown() called with NULL manager";
481 return;
483 delete g_homedir_methods;
484 g_homedir_methods = NULL;
485 VLOG(1) << "HomedirMethods Shutdown completed";
488 // static
489 HomedirMethods* HomedirMethods::GetInstance() { return g_homedir_methods; }
491 } // namespace cryptohome