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"
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"
14 #if defined(USE_SYSTEM_PROTOBUF)
15 #include <google/protobuf/repeated_field.h>
17 #include "third_party/protobuf/src/google/protobuf/repeated_field.h"
20 using chromeos::DBusThreadManager
;
21 using google::protobuf::RepeatedPtrField
;
23 namespace cryptohome
{
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
:
56 KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_HMACSHA256
);
58 case KeyDefinition::AuthorizationData::TYPE_AES256CBC_HMACSHA256
:
60 KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_AES256CBC_HMACSHA256
);
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();
84 KeyProviderData::Entry
* entry
=
85 data
->mutable_provider_data()->add_entry();
86 entry
->set_name(it
->name
);
88 entry
->set_number(*it
->number
);
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
;
118 case KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_AES256CBC_HMACSHA256
:
119 authorization_data
->type
=
120 KeyDefinition::AuthorizationData::TYPE_AES256CBC_HMACSHA256
;
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(),
139 MountError
MapError(CryptohomeErrorCode 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
;
168 return MOUNT_ERROR_FATAL
;
172 // The implementation of HomedirMethods
173 class HomedirMethodsImpl
: public HomedirMethods
{
175 HomedirMethodsImpl() : weak_ptr_factory_(this) {}
177 virtual ~HomedirMethodsImpl() {}
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
;
186 FillIdentificationProtobuf(id
, &id_proto
);
187 request
.mutable_key()->mutable_data()->set_label(label
);
189 DBusThreadManager::Get()->GetCryptohomeClient()->GetKeyDataEx(
193 base::Bind(&HomedirMethodsImpl::OnGetKeyDataExCallback
,
194 weak_ptr_factory_
.GetWeakPtr(),
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
;
205 FillIdentificationProtobuf(id
, &id_proto
);
206 FillAuthorizationProtobuf(auth
, &auth_proto
);
208 DBusThreadManager::Get()->GetCryptohomeClient()->CheckKeyEx(
212 base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback
,
213 weak_ptr_factory_
.GetWeakPtr(),
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
;
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(
241 base::Bind(&HomedirMethodsImpl::OnMountExCallback
,
242 weak_ptr_factory_
.GetWeakPtr(),
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
;
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(
264 base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback
,
265 weak_ptr_factory_
.GetWeakPtr(),
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
;
277 FillIdentificationProtobuf(id
, &id_proto
);
278 FillAuthorizationProtobuf(auth
, &auth_proto
);
279 request
.mutable_key()->mutable_data()->set_label(label
);
281 DBusThreadManager::Get()->GetCryptohomeClient()->RemoveKeyEx(
285 base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback
,
286 weak_ptr_factory_
.GetWeakPtr(),
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
;
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(
308 base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback
,
309 weak_ptr_factory_
.GetWeakPtr(),
314 void OnGetKeyDataExCallback(const GetKeyDataCallback
& callback
,
315 chromeos::DBusMethodCallStatus call_status
,
317 const BaseReply
& reply
) {
318 if (call_status
!= chromeos::DBUS_METHOD_CALL_SUCCESS
) {
319 callback
.Run(false, MOUNT_ERROR_FATAL
, std::vector
<KeyDefinition
>());
322 if (reply
.has_error()) {
323 if (reply
.error() != CRYPTOHOME_ERROR_NOT_SET
) {
325 MapError(reply
.error()),
326 std::vector
<KeyDefinition
>());
331 if (!reply
.HasExtension(GetKeyDataReply::reply
)) {
332 callback
.Run(false, MOUNT_ERROR_FATAL
, std::vector
<KeyDefinition
>());
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 */,
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(
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
) {
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();
389 if (provider_data_it
->has_number()) {
390 provider_data
.number
.reset(new int64(provider_data_it
->number()));
395 if (provider_data_it
->has_bytes()) {
396 provider_data
.bytes
.reset(
397 new std::string(provider_data_it
->bytes()));
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
,
411 const BaseReply
& reply
) {
412 if (call_status
!= chromeos::DBUS_METHOD_CALL_SUCCESS
) {
413 callback
.Run(false, MOUNT_ERROR_FATAL
, std::string());
416 if (reply
.has_error()) {
417 if (reply
.error() != CRYPTOHOME_ERROR_NOT_SET
) {
418 callback
.Run(false, MapError(reply
.error()), std::string());
422 if (!reply
.HasExtension(MountReply::reply
)) {
423 callback
.Run(false, MOUNT_ERROR_FATAL
, std::string());
427 std::string mount_hash
;
428 mount_hash
= reply
.GetExtension(MountReply::reply
).sanitized_username();
429 callback
.Run(true, MOUNT_ERROR_NONE
, mount_hash
);
432 void OnBaseReplyCallback(const Callback
& callback
,
433 chromeos::DBusMethodCallStatus call_status
,
435 const BaseReply
& reply
) {
436 if (call_status
!= chromeos::DBUS_METHOD_CALL_SUCCESS
) {
437 callback
.Run(false, MOUNT_ERROR_FATAL
);
440 if (reply
.has_error()) {
441 if (reply
.error() != CRYPTOHOME_ERROR_NOT_SET
) {
442 callback
.Run(false, MapError(reply
.error()));
446 callback
.Run(true, MOUNT_ERROR_NONE
);
449 base::WeakPtrFactory
<HomedirMethodsImpl
> weak_ptr_factory_
;
451 DISALLOW_COPY_AND_ASSIGN(HomedirMethodsImpl
);
457 void HomedirMethods::Initialize() {
458 if (g_homedir_methods
) {
459 LOG(WARNING
) << "HomedirMethods was already initialized";
462 g_homedir_methods
= new HomedirMethodsImpl();
463 VLOG(1) << "HomedirMethods initialized";
467 void HomedirMethods::InitializeForTesting(HomedirMethods
* homedir_methods
) {
468 if (g_homedir_methods
) {
469 LOG(WARNING
) << "HomedirMethods was already initialized";
472 g_homedir_methods
= homedir_methods
;
473 VLOG(1) << "HomedirMethods initialized";
477 void HomedirMethods::Shutdown() {
478 if (!g_homedir_methods
) {
479 LOG(WARNING
) << "AsyncMethodCaller::Shutdown() called with NULL manager";
482 delete g_homedir_methods
;
483 g_homedir_methods
= NULL
;
484 VLOG(1) << "HomedirMethods Shutdown completed";
488 HomedirMethods
* HomedirMethods::GetInstance() { return g_homedir_methods
; }
490 } // namespace cryptohome