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/dbus_thread_manager.h"
13 #if defined(USE_SYSTEM_PROTOBUF)
14 #include <google/protobuf/repeated_field.h>
16 #include "third_party/protobuf/src/google/protobuf/repeated_field.h"
19 using chromeos::DBusThreadManager
;
20 using google::protobuf::RepeatedPtrField
;
22 namespace cryptohome
{
26 HomedirMethods
* g_homedir_methods
= NULL
;
28 void FillKeyProtobuf(const KeyDefinition
& key_def
, Key
* key
) {
29 key
->set_secret(key_def
.secret
);
30 KeyData
* data
= key
->mutable_data();
31 DCHECK_EQ(KeyDefinition::TYPE_PASSWORD
, key_def
.type
);
32 data
->set_type(KeyData::KEY_TYPE_PASSWORD
);
33 data
->set_label(key_def
.label
);
35 if (key_def
.revision
> 0)
36 data
->set_revision(key_def
.revision
);
38 if (key_def
.privileges
!= 0) {
39 KeyPrivileges
* privileges
= data
->mutable_privileges();
40 privileges
->set_mount(key_def
.privileges
& PRIV_MOUNT
);
41 privileges
->set_add(key_def
.privileges
& PRIV_ADD
);
42 privileges
->set_remove(key_def
.privileges
& PRIV_REMOVE
);
43 privileges
->set_update(key_def
.privileges
& PRIV_MIGRATE
);
44 privileges
->set_authorized_update(key_def
.privileges
&
45 PRIV_AUTHORIZED_UPDATE
);
48 for (std::vector
<KeyDefinition::AuthorizationData
>::const_iterator auth_it
=
49 key_def
.authorization_data
.begin();
50 auth_it
!= key_def
.authorization_data
.end(); ++auth_it
) {
51 KeyAuthorizationData
* auth_data
= data
->add_authorization_data();
52 switch (auth_it
->type
) {
53 case KeyDefinition::AuthorizationData::TYPE_HMACSHA256
:
55 KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_HMACSHA256
);
57 case KeyDefinition::AuthorizationData::TYPE_AES256CBC_HMACSHA256
:
59 KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_AES256CBC_HMACSHA256
);
66 for (std::vector
<KeyDefinition::AuthorizationData::Secret
>::const_iterator
67 secret_it
= auth_it
->secrets
.begin();
68 secret_it
!= auth_it
->secrets
.end(); ++secret_it
) {
69 KeyAuthorizationSecret
* secret
= auth_data
->add_secrets();
70 secret
->mutable_usage()->set_encrypt(secret_it
->encrypt
);
71 secret
->mutable_usage()->set_sign(secret_it
->sign
);
72 if (!secret_it
->symmetric_key
.empty())
73 secret
->set_symmetric_key(secret_it
->symmetric_key
);
74 if (!secret_it
->public_key
.empty())
75 secret
->set_public_key(secret_it
->public_key
);
76 secret
->set_wrapped(secret_it
->wrapped
);
80 for (std::vector
<KeyDefinition::ProviderData
>::const_iterator it
=
81 key_def
.provider_data
.begin(); it
!= key_def
.provider_data
.end();
83 KeyProviderData::Entry
* entry
=
84 data
->mutable_provider_data()->add_entry();
85 entry
->set_name(it
->name
);
87 entry
->set_number(*it
->number
);
89 entry
->set_bytes(*it
->bytes
);
93 // Fill identification protobuffer.
94 void FillIdentificationProtobuf(const Identification
& id
,
95 cryptohome::AccountIdentifier
* id_proto
) {
96 id_proto
->set_email(id
.user_id
);
99 // Fill authorization protobuffer.
100 void FillAuthorizationProtobuf(const Authorization
& auth
,
101 cryptohome::AuthorizationRequest
* auth_proto
) {
102 Key
* key
= auth_proto
->mutable_key();
103 if (!auth
.label
.empty()) {
104 key
->mutable_data()->set_label(auth
.label
);
106 key
->set_secret(auth
.key
);
109 void ParseAuthorizationDataProtobuf(
110 const KeyAuthorizationData
& authorization_data_proto
,
111 KeyDefinition::AuthorizationData
* authorization_data
) {
112 switch (authorization_data_proto
.type()) {
113 case KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_HMACSHA256
:
114 authorization_data
->type
=
115 KeyDefinition::AuthorizationData::TYPE_HMACSHA256
;
117 case KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_AES256CBC_HMACSHA256
:
118 authorization_data
->type
=
119 KeyDefinition::AuthorizationData::TYPE_AES256CBC_HMACSHA256
;
126 for (RepeatedPtrField
<KeyAuthorizationSecret
>::const_iterator it
=
127 authorization_data_proto
.secrets().begin();
128 it
!= authorization_data_proto
.secrets().end(); ++it
) {
129 authorization_data
->secrets
.push_back(
130 KeyDefinition::AuthorizationData::Secret(it
->usage().encrypt(),
138 MountError
MapError(CryptohomeErrorCode code
) {
140 case CRYPTOHOME_ERROR_NOT_SET
:
141 return MOUNT_ERROR_NONE
;
142 case CRYPTOHOME_ERROR_ACCOUNT_NOT_FOUND
:
143 return MOUNT_ERROR_USER_DOES_NOT_EXIST
;
144 case CRYPTOHOME_ERROR_NOT_IMPLEMENTED
:
145 case CRYPTOHOME_ERROR_MOUNT_FATAL
:
146 case CRYPTOHOME_ERROR_KEY_QUOTA_EXCEEDED
:
147 case CRYPTOHOME_ERROR_BACKING_STORE_FAILURE
:
148 return MOUNT_ERROR_FATAL
;
149 case CRYPTOHOME_ERROR_AUTHORIZATION_KEY_NOT_FOUND
:
150 case CRYPTOHOME_ERROR_KEY_NOT_FOUND
:
151 case CRYPTOHOME_ERROR_AUTHORIZATION_KEY_FAILED
:
152 return MOUNT_ERROR_KEY_FAILURE
;
153 case CRYPTOHOME_ERROR_TPM_COMM_ERROR
:
154 return MOUNT_ERROR_TPM_COMM_ERROR
;
155 case CRYPTOHOME_ERROR_TPM_DEFEND_LOCK
:
156 return MOUNT_ERROR_TPM_DEFEND_LOCK
;
157 case CRYPTOHOME_ERROR_MOUNT_MOUNT_POINT_BUSY
:
158 return MOUNT_ERROR_MOUNT_POINT_BUSY
;
159 case CRYPTOHOME_ERROR_TPM_NEEDS_REBOOT
:
160 return MOUNT_ERROR_TPM_NEEDS_REBOOT
;
161 case CRYPTOHOME_ERROR_AUTHORIZATION_KEY_DENIED
:
162 case CRYPTOHOME_ERROR_KEY_LABEL_EXISTS
:
163 case CRYPTOHOME_ERROR_UPDATE_SIGNATURE_INVALID
:
164 return MOUNT_ERROR_KEY_FAILURE
;
167 return MOUNT_ERROR_FATAL
;
171 // The implementation of HomedirMethods
172 class HomedirMethodsImpl
: public HomedirMethods
{
174 HomedirMethodsImpl() : weak_ptr_factory_(this) {}
176 ~HomedirMethodsImpl() override
{}
178 void GetKeyDataEx(const Identification
& id
,
179 const std::string
& label
,
180 const GetKeyDataCallback
& callback
) override
{
181 cryptohome::AccountIdentifier id_proto
;
182 cryptohome::AuthorizationRequest kEmptyAuthProto
;
183 cryptohome::GetKeyDataRequest request
;
185 FillIdentificationProtobuf(id
, &id_proto
);
186 request
.mutable_key()->mutable_data()->set_label(label
);
188 DBusThreadManager::Get()->GetCryptohomeClient()->GetKeyDataEx(
192 base::Bind(&HomedirMethodsImpl::OnGetKeyDataExCallback
,
193 weak_ptr_factory_
.GetWeakPtr(),
197 void CheckKeyEx(const Identification
& id
,
198 const Authorization
& auth
,
199 const Callback
& callback
) override
{
200 cryptohome::AccountIdentifier id_proto
;
201 cryptohome::AuthorizationRequest auth_proto
;
202 cryptohome::CheckKeyRequest request
;
204 FillIdentificationProtobuf(id
, &id_proto
);
205 FillAuthorizationProtobuf(auth
, &auth_proto
);
207 DBusThreadManager::Get()->GetCryptohomeClient()->CheckKeyEx(
211 base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback
,
212 weak_ptr_factory_
.GetWeakPtr(),
216 void MountEx(const Identification
& id
,
217 const Authorization
& auth
,
218 const MountParameters
& request
,
219 const MountCallback
& callback
) override
{
220 cryptohome::AccountIdentifier id_proto
;
221 cryptohome::AuthorizationRequest auth_proto
;
222 cryptohome::MountRequest request_proto
;
224 FillIdentificationProtobuf(id
, &id_proto
);
225 FillAuthorizationProtobuf(auth
, &auth_proto
);
227 if (request
.ephemeral
)
228 request_proto
.set_require_ephemeral(true);
230 if (!request
.create_keys
.empty()) {
231 CreateRequest
* create
= request_proto
.mutable_create();
232 for (size_t i
= 0; i
< request
.create_keys
.size(); ++i
)
233 FillKeyProtobuf(request
.create_keys
[i
], create
->add_keys());
236 DBusThreadManager::Get()->GetCryptohomeClient()->MountEx(
240 base::Bind(&HomedirMethodsImpl::OnMountExCallback
,
241 weak_ptr_factory_
.GetWeakPtr(),
245 void AddKeyEx(const Identification
& id
,
246 const Authorization
& auth
,
247 const KeyDefinition
& new_key
,
248 bool clobber_if_exists
,
249 const Callback
& callback
) override
{
250 cryptohome::AccountIdentifier id_proto
;
251 cryptohome::AuthorizationRequest auth_proto
;
252 cryptohome::AddKeyRequest request
;
254 FillIdentificationProtobuf(id
, &id_proto
);
255 FillAuthorizationProtobuf(auth
, &auth_proto
);
256 FillKeyProtobuf(new_key
, request
.mutable_key());
257 request
.set_clobber_if_exists(clobber_if_exists
);
259 DBusThreadManager::Get()->GetCryptohomeClient()->AddKeyEx(
263 base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback
,
264 weak_ptr_factory_
.GetWeakPtr(),
268 void RemoveKeyEx(const Identification
& id
,
269 const Authorization
& auth
,
270 const std::string
& label
,
271 const Callback
& callback
) override
{
272 cryptohome::AccountIdentifier id_proto
;
273 cryptohome::AuthorizationRequest auth_proto
;
274 cryptohome::RemoveKeyRequest request
;
276 FillIdentificationProtobuf(id
, &id_proto
);
277 FillAuthorizationProtobuf(auth
, &auth_proto
);
278 request
.mutable_key()->mutable_data()->set_label(label
);
280 DBusThreadManager::Get()->GetCryptohomeClient()->RemoveKeyEx(
284 base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback
,
285 weak_ptr_factory_
.GetWeakPtr(),
289 void UpdateKeyEx(const Identification
& id
,
290 const Authorization
& auth
,
291 const KeyDefinition
& new_key
,
292 const std::string
& signature
,
293 const Callback
& callback
) override
{
294 cryptohome::AccountIdentifier id_proto
;
295 cryptohome::AuthorizationRequest auth_proto
;
296 cryptohome::UpdateKeyRequest pb_update_key
;
298 FillIdentificationProtobuf(id
, &id_proto
);
299 FillAuthorizationProtobuf(auth
, &auth_proto
);
300 FillKeyProtobuf(new_key
, pb_update_key
.mutable_changes());
301 pb_update_key
.set_authorization_signature(signature
);
303 DBusThreadManager::Get()->GetCryptohomeClient()->UpdateKeyEx(
307 base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback
,
308 weak_ptr_factory_
.GetWeakPtr(),
313 void OnGetKeyDataExCallback(const GetKeyDataCallback
& callback
,
314 chromeos::DBusMethodCallStatus call_status
,
316 const BaseReply
& reply
) {
317 if (call_status
!= chromeos::DBUS_METHOD_CALL_SUCCESS
) {
318 callback
.Run(false, MOUNT_ERROR_FATAL
, std::vector
<KeyDefinition
>());
321 if (reply
.has_error()) {
322 if (reply
.error() != CRYPTOHOME_ERROR_NOT_SET
) {
324 MapError(reply
.error()),
325 std::vector
<KeyDefinition
>());
330 if (!reply
.HasExtension(GetKeyDataReply::reply
)) {
331 callback
.Run(false, MOUNT_ERROR_FATAL
, std::vector
<KeyDefinition
>());
335 // Extract the contents of the |KeyData| protos returned.
336 const RepeatedPtrField
<KeyData
>& key_data
=
337 reply
.GetExtension(GetKeyDataReply::reply
).key_data();
338 std::vector
<KeyDefinition
> key_definitions
;
339 for (RepeatedPtrField
<KeyData
>::const_iterator it
= key_data
.begin();
340 it
!= key_data
.end(); ++it
) {
342 // Extract |type|, |label| and |revision|.
343 DCHECK_EQ(KeyData::KEY_TYPE_PASSWORD
, it
->type());
344 key_definitions
.push_back(KeyDefinition(std::string() /* secret */,
346 0 /* privileges */));
347 KeyDefinition
& key_definition
= key_definitions
.back();
348 key_definition
.revision
= it
->revision();
350 // Extract |privileges|.
351 const KeyPrivileges
& privileges
= it
->privileges();
352 if (privileges
.mount())
353 key_definition
.privileges
|= PRIV_MOUNT
;
354 if (privileges
.add())
355 key_definition
.privileges
|= PRIV_ADD
;
356 if (privileges
.remove())
357 key_definition
.privileges
|= PRIV_REMOVE
;
358 if (privileges
.update())
359 key_definition
.privileges
|= PRIV_MIGRATE
;
360 if (privileges
.authorized_update())
361 key_definition
.privileges
|= PRIV_AUTHORIZED_UPDATE
;
363 // Extract |authorization_data|.
364 for (RepeatedPtrField
<KeyAuthorizationData
>::const_iterator auth_it
=
365 it
->authorization_data().begin();
366 auth_it
!= it
->authorization_data().end(); ++auth_it
) {
367 key_definition
.authorization_data
.push_back(
368 KeyDefinition::AuthorizationData());
369 ParseAuthorizationDataProtobuf(
371 &key_definition
.authorization_data
.back());
374 // Extract |provider_data|.
375 for (RepeatedPtrField
<KeyProviderData::Entry
>::const_iterator
376 provider_data_it
= it
->provider_data().entry().begin();
377 provider_data_it
!= it
->provider_data().entry().end();
378 ++provider_data_it
) {
380 key_definition
.provider_data
.push_back(
381 KeyDefinition::ProviderData(provider_data_it
->name()));
382 KeyDefinition::ProviderData
& provider_data
=
383 key_definition
.provider_data
.back();
388 if (provider_data_it
->has_number()) {
389 provider_data
.number
.reset(new int64(provider_data_it
->number()));
394 if (provider_data_it
->has_bytes()) {
395 provider_data
.bytes
.reset(
396 new std::string(provider_data_it
->bytes()));
400 DCHECK_EQ(1, data_items
);
404 callback
.Run(true, MOUNT_ERROR_NONE
, key_definitions
);
407 void OnMountExCallback(const MountCallback
& callback
,
408 chromeos::DBusMethodCallStatus call_status
,
410 const BaseReply
& reply
) {
411 if (call_status
!= chromeos::DBUS_METHOD_CALL_SUCCESS
) {
412 callback
.Run(false, MOUNT_ERROR_FATAL
, std::string());
415 if (reply
.has_error()) {
416 if (reply
.error() != CRYPTOHOME_ERROR_NOT_SET
) {
417 callback
.Run(false, MapError(reply
.error()), std::string());
421 if (!reply
.HasExtension(MountReply::reply
)) {
422 callback
.Run(false, MOUNT_ERROR_FATAL
, std::string());
426 std::string mount_hash
;
427 mount_hash
= reply
.GetExtension(MountReply::reply
).sanitized_username();
428 callback
.Run(true, MOUNT_ERROR_NONE
, mount_hash
);
431 void OnBaseReplyCallback(const Callback
& callback
,
432 chromeos::DBusMethodCallStatus call_status
,
434 const BaseReply
& reply
) {
435 if (call_status
!= chromeos::DBUS_METHOD_CALL_SUCCESS
) {
436 callback
.Run(false, MOUNT_ERROR_FATAL
);
439 if (reply
.has_error()) {
440 if (reply
.error() != CRYPTOHOME_ERROR_NOT_SET
) {
441 callback
.Run(false, MapError(reply
.error()));
445 callback
.Run(true, MOUNT_ERROR_NONE
);
448 base::WeakPtrFactory
<HomedirMethodsImpl
> weak_ptr_factory_
;
450 DISALLOW_COPY_AND_ASSIGN(HomedirMethodsImpl
);
456 void HomedirMethods::Initialize() {
457 if (g_homedir_methods
) {
458 LOG(WARNING
) << "HomedirMethods was already initialized";
461 g_homedir_methods
= new HomedirMethodsImpl();
462 VLOG(1) << "HomedirMethods initialized";
466 void HomedirMethods::InitializeForTesting(HomedirMethods
* homedir_methods
) {
467 if (g_homedir_methods
) {
468 LOG(WARNING
) << "HomedirMethods was already initialized";
471 g_homedir_methods
= homedir_methods
;
472 VLOG(1) << "HomedirMethods initialized";
476 void HomedirMethods::Shutdown() {
477 if (!g_homedir_methods
) {
478 LOG(WARNING
) << "AsyncMethodCaller::Shutdown() called with NULL manager";
481 delete g_homedir_methods
;
482 g_homedir_methods
= NULL
;
483 VLOG(1) << "HomedirMethods Shutdown completed";
487 HomedirMethods
* HomedirMethods::GetInstance() { return g_homedir_methods
; }
489 } // namespace cryptohome