• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
FillKeyProtobuf(const KeyDefinition & key_def,Key * key)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.
FillIdentificationProtobuf(const Identification & id,cryptohome::AccountIdentifier * id_proto)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.
FillAuthorizationProtobuf(const Authorization & auth,cryptohome::AuthorizationRequest * auth_proto)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 
MapError(CryptohomeErrorCode code)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:
HomedirMethodsImpl()108   HomedirMethodsImpl() : weak_ptr_factory_(this) {}
109 
~HomedirMethodsImpl()110   virtual ~HomedirMethodsImpl() {}
111 
CheckKeyEx(const Identification & id,const Authorization & auth,const Callback & callback)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 
MountEx(const Identification & id,const Authorization & auth,const MountParameters & request,const MountCallback & callback)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 
AddKeyEx(const Identification & id,const Authorization & auth,const KeyDefinition & new_key,bool clobber_if_exists,const Callback & callback)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 
RemoveKeyEx(const Identification & id,const Authorization & auth,const std::string & label,const Callback & callback)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 
UpdateKeyEx(const Identification & id,const Authorization & auth,const KeyDefinition & new_key,const std::string & signature,const Callback & callback)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:
OnMountExCallback(const MountCallback & callback,chromeos::DBusMethodCallStatus call_status,bool result,const BaseReply & reply)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 
OnBaseReplyCallback(const Callback & callback,chromeos::DBusMethodCallStatus call_status,bool result,const BaseReply & reply)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
Initialize()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
InitializeForTesting(HomedirMethods * homedir_methods)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
Shutdown()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
GetInstance()308 HomedirMethods* HomedirMethods::GetInstance() { return g_homedir_methods; }
309 
310 }  // namespace cryptohome
311